5031 lines
195 KiB
C++
Executable File
5031 lines
195 KiB
C++
Executable File
/*
|
||
**
|
||
** @RDE_HEADER@
|
||
** plan_editor.cpp
|
||
** $Id$
|
||
** $HeadURL$
|
||
** $Author$
|
||
**
|
||
** -----------------------------------------------------------------------------------------------
|
||
**
|
||
** Hardware-Environment: Intel-PC
|
||
** Software-Environment: Windows 7, Qt 5.9, ArcGIS 100.2.1
|
||
**
|
||
** Language ........: C++ 11
|
||
**
|
||
** -----------------------------------------------------------------------------------------------
|
||
**
|
||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||
**
|
||
** -----------------------------------------------------------------------------------------------
|
||
**
|
||
** Notes .........:
|
||
**
|
||
** 09.12.2015, JT : First edition for use with Qt5
|
||
**
|
||
** ------------------------------------------------------------------------------------------------
|
||
*/
|
||
|
||
const char* const REVISION = "$Revision$";
|
||
|
||
|
||
#include "dialog.h"
|
||
#include "drop_event_manager.h"
|
||
#include "icon_names.h"
|
||
#include "lookup_symbol_dlg.h"
|
||
#include "geometry_placer.h"
|
||
#include "selection_worker.h"
|
||
#include "plan_editor_utils.h"
|
||
#include "metadata_dialog.h"
|
||
#include "model_tree_widget.h"
|
||
#include "model_tree_widget_item.h"
|
||
#include "symbol_favourites.h"
|
||
|
||
#include <Rubberbands/rubberband_factory.h>
|
||
|
||
#include <Symbology/symbol_dictionary.h>
|
||
#include <Symbology/sidc_builder_base.h>
|
||
#include <Symbology/sidc_codec.h>
|
||
#include <SymbologyGui/base_symbol_lookup_dialog.h>
|
||
#include <SymbologyGui/symbol_modification_dialog.h>
|
||
|
||
|
||
#include <GeometryModel/geometry_node_visitor.h>
|
||
|
||
#include <Map/bounding_box.h>
|
||
#include <Map/layer_parameter.h>
|
||
#include <Map/party_id_to_color_functor.h>
|
||
#include <Map/pixel_based_textbox_handler.h>
|
||
|
||
#include <Map/sight_fan.h> // just for testing sight fan
|
||
|
||
#include <MapObjects/polyline.h> // just for testing parallel translation
|
||
|
||
#include <MathUtils/math_const.h>
|
||
#include <MathUtils/simple_helper.h>
|
||
#include <MathUtils/matrix2d.h>
|
||
|
||
#include <LtsSession/lts_session.h>
|
||
#include <LtsSession/lts_session_data.h>
|
||
|
||
#include <LtsWidgets/lts_combo_box.h>
|
||
#include <LtsWidgets/lts_message_dialog.h>
|
||
#include <LtsWidgets/lts_tool_bar_area.h>
|
||
#include <LtsWidgets/lts_text_editor.h>
|
||
#include <LtsWidgets/lts_text_edit_dialog.h>
|
||
|
||
#include <QtCore/QAbstractItemModel>
|
||
#include <QtCore/QFile>
|
||
#include <QtCore/QFileInfo>
|
||
#include <QtCore/QMimeData>
|
||
#include <QtCore/QString>
|
||
#include <QtCore/QStringRef>
|
||
#include <QtCore/QSettings>
|
||
#include <QtCore/QTemporaryFile>
|
||
#include <QtCore/QTime>
|
||
#include <QtCore/QTimer>
|
||
#include <QtCore/QUuid>
|
||
|
||
#include <QtGui/QCursor>
|
||
#include <QtGui/QGuiApplication>
|
||
#include <QtGui/QImage>
|
||
#include <QtGui/QMouseEvent>
|
||
#include <QtGui/QPixmap>
|
||
#include <QtGui/QTextTable>
|
||
#include <QtGui/QTextTableCell>
|
||
|
||
#include <QtWidgets/QAction>
|
||
|
||
#include <QtWidgets/QFormLayout>
|
||
#include <QtWidgets/QGraphicsView>
|
||
#include <QtWidgets/QGraphicsProxyWidget>
|
||
#include <QtWidgets/QGroupBox>
|
||
#include <QtWidgets/QLabel>
|
||
#include <QtWidgets/QLineEdit>
|
||
|
||
#include <QtWidgets/QMenu>
|
||
#include <QtWidgets/QMessageBox>
|
||
#include <QtWidgets/QPushButton>
|
||
#include <QtWidgets/QRadioButton>
|
||
#include <QtWidgets/QTabWidget>
|
||
#include <QtWidgets/QTextBrowser>
|
||
#include <QtWidgets/QToolButton>
|
||
#include <QtWidgets/QVBoxLayout>
|
||
|
||
#include <QtPrintSupport/QPrintDialog>
|
||
|
||
#include <SituationMap/LayerAggregation/layer_aggregation_widget.h>
|
||
#include <SituationMap/LayerAggregation/participant_aggregation_dialog.h>
|
||
|
||
#include <limits>
|
||
|
||
#include "plan_editor_internal.h"
|
||
|
||
#include "setting_keys.h"
|
||
|
||
|
||
#include <Map/viewshed.h> // just for testing
|
||
|
||
|
||
namespace PlanEditor
|
||
{
|
||
|
||
const double PasteDistance = 20.0;
|
||
const int PLAN_EDITOR_TEXTBOX_PARENT_ID = -123;
|
||
|
||
class KeyPressDeleteFilter : public QObject
|
||
{
|
||
public:
|
||
explicit KeyPressDeleteFilter(PlanEditor *planEditor)
|
||
: QObject(planEditor) , m_planEditor(planEditor) {}
|
||
|
||
protected:
|
||
bool eventFilter(QObject *obj, QEvent *event) override
|
||
{
|
||
if (event->type() == QEvent::KeyPress)
|
||
{
|
||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||
if ((keyEvent->key() == Qt::Key_Delete) && m_planEditor)
|
||
m_planEditor->onDelete();
|
||
return true;
|
||
}
|
||
|
||
// standard event processing
|
||
return QObject::eventFilter(obj, event);
|
||
}
|
||
QPointer<PlanEditor> m_planEditor;
|
||
};
|
||
|
||
|
||
void PlanEditor::onGeoModelModified(unsigned int modifyCount)
|
||
{
|
||
if (!m_internal || !m_internal->m_modelTreeWidget)
|
||
return;
|
||
m_internal->m_modelTreeWidget->haveChanges((modifyCount > 0));
|
||
} // void PlanEditor::onGeoModelModified(unsigned int modifyCount)
|
||
|
||
|
||
void PlanEditor::onNoticeGeoModelTypeError(const QString &errorMsg)
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model type error: " << errorMsg;
|
||
} // PlanEditor::onNoticeGeoModelTypeError( const QString & )
|
||
|
||
|
||
void PlanEditor::onNoticeGeoModelAttributeError(const QString &errorMsg)
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model attribute error: " << errorMsg;
|
||
} // PlanEditor::onNoticeGeoModelAttributeError( const QString & )
|
||
|
||
|
||
void PlanEditor::onNoticeGeoModelModelError(const QString &errorMsg)
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model error: " << errorMsg;
|
||
} // PlanEditor::onNoticeGeoModelModelError( const QString & )
|
||
|
||
|
||
void PlanEditor::onNoticeGeoModelError(const QString &errorMsg)
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model error: " << errorMsg;
|
||
QString msg = tr("Critical internal failure detected: %1").arg(errorMsg);
|
||
msg += QStringLiteral("<br>");
|
||
msg += tr("It is recommended to save the plan and restart the editor to avoid data loss");
|
||
|
||
QMessageBox::critical(topLevelWidget(), tr("Critical Internal Failure"), msg);
|
||
} // PlanEditor::onNoticeGeoModelError( const QString & )
|
||
|
||
|
||
void PlanEditor::onNoticeGeoModelUpdate(const SituationMap::GeometryModel::Node &node
|
||
, SituationMap::GeometryModel::Attribute att
|
||
, bool coordsChanged)
|
||
{
|
||
Q_UNUSED(node);
|
||
Q_UNUSED(att);
|
||
Q_UNUSED(coordsChanged);
|
||
|
||
const QString &nodename = m_internal->m_geoModel->getNodeDisplayName(node);
|
||
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model has changed: "
|
||
<< " nodeDisplayName='" << nodename << "'"
|
||
<< " connectedId=" << node.connectedId()
|
||
<< " att=" << static_cast<int>(att)
|
||
<< " coordsChanged=" << coordsChanged;
|
||
|
||
switch (m_internal->m_updateViewMode)
|
||
{
|
||
case UpdateViewMode::Scheduled : m_internal->m_delayedUpdateTimer->start(10); break;
|
||
case UpdateViewMode::Immediately : onUpdateView(); break;
|
||
case UpdateViewMode::Manually : break;
|
||
}
|
||
|
||
// [GUEZE-2947] Undo,Redo fuer PixelBasedTextBoxen
|
||
// update TextBoxes (transfer data from model to TextBoxes)
|
||
if ((att == SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes) ||
|
||
(att == SituationMap::GeometryModel::Attribute::MaxAttributes) )
|
||
{
|
||
// // initializePlanTextBoxPixel(); // does not really work, to rough
|
||
|
||
// Assumption:
|
||
// - we create one PixelBasedTextBox (implicit an EditorDialog is opened)
|
||
// - enter some characters (PixelBasedTextBox is updated)
|
||
// - we press apply
|
||
// within LtsTextEditDialog::apply() there will be two signals emitted
|
||
// - first 'signalTextApplied'
|
||
// this will update the geometryModel and via changed and onNoticeGeoModelUpdate
|
||
// the LtsTextEditDialog will be deleted
|
||
// - second 'signalTextAppliedWithBackGroundColor'
|
||
// will crash since object does not exist anymore....
|
||
|
||
// Note: most of the times, ptbdCont.size() == pbtbIdVec.size() are equal...
|
||
|
||
// Model
|
||
const QString &strRef =
|
||
m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes).toString();
|
||
const QVector<SituationMap::PixelTextBoxData> &ptbdCont =
|
||
SituationMap::PixelTextBoxData::pixelTextBoxContainerFromJsonStr(strRef);
|
||
|
||
// displayed TextBoxes
|
||
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
|
||
const SituationMap::PBTB_ID pbtbIdAsParent(PLAN_EDITOR_TEXTBOX_PARENT_ID);
|
||
const QVector<SituationMap::PBTB_ID> pbtbIdVec = pixelBasedTextBoxHandler.getAllIdsOfParent(pbtbIdAsParent);
|
||
|
||
if (ptbdCont.size() == pbtbIdVec.size())
|
||
{
|
||
// this case is typically entered by pressing: undo, redo, LtsTextEditDialog::apply()
|
||
|
||
QVectorIterator<SituationMap::PBTB_ID> pbtbIdVecIt(pbtbIdVec);
|
||
for (const SituationMap::PixelTextBoxData &ptbd : qAsConst(ptbdCont))
|
||
{
|
||
pbtbIdVecIt.hasNext();
|
||
const SituationMap::PBTB_ID &pbtbId = pbtbIdVecIt.next();
|
||
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " -------- ptbd.toDebugString = " << ptbd.toDebugString()
|
||
<< " UPDATE pbtbId = " << pbtbId;
|
||
|
||
pixelBasedTextBoxHandler.updateTextBox(pbtbId, ptbd);
|
||
}
|
||
} else {
|
||
// this case is typically entered by pressing undo, redo; but no by LtsTextEditDialog::apply()
|
||
|
||
initializePlanTextBoxPixel();
|
||
} // if (ptbdCont.size() == pbtbIdVec.size())
|
||
|
||
}
|
||
|
||
|
||
// NLDEVCTRL-807:
|
||
if (m_internal && m_internal->m_btnUndo)
|
||
m_internal->m_btnUndo->setEnabled((m_internal->m_geoModel->undoSteps() > 0));
|
||
|
||
if (m_internal && m_internal->m_btnRedo)
|
||
m_internal->m_btnRedo->setEnabled((m_internal->m_geoModel->redoSteps() > 0));
|
||
|
||
} // PlanEditor::onNoticeGeoModelUpdate( const SituationMap::GeometryModel::Node & node, SituationMap::GeometryModel::Attribute att, bool coordsChanged );
|
||
|
||
|
||
void PlanEditor::onUpdateView()
|
||
{
|
||
m_internal->m_delayedUpdateTimer->stop();
|
||
|
||
if (m_internal->m_teDebug)
|
||
m_internal->m_teDebug->setPlainText(QString::fromUtf8(m_internal->m_geoModel->toByteArrayDebug()));
|
||
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map, *(m_internal->m_geoModel));
|
||
// m_internal->m_map->getQGraphicsView() seems to be nullptr , mostly during slotReplaySessionForPlanEditorStarted
|
||
if (m_internal->m_map &&
|
||
m_internal->m_map->getQGraphicsView() &&
|
||
m_internal->m_map->getQGraphicsView()->viewport())
|
||
m_internal->m_map->getQGraphicsView()->viewport()->update();
|
||
|
||
m_internal->m_modelTreeWidget->showNeedSaveFlag( (m_internal->m_geoModel->modificationCounter() > 0) );
|
||
} // PlanEditor::onUpdateView()
|
||
|
||
|
||
QString PlanEditor::planDefaultDirectory() const
|
||
{
|
||
return m_internal->m_defaultPlanDirectory;
|
||
} // PlanEditor::planDefaultDirectory() const
|
||
|
||
|
||
void PlanEditor::setPlanDefaultDirectory(const QString &dir)
|
||
{
|
||
QFileInfo fileInfo(dir);
|
||
|
||
if ((fileInfo.isDir()) || (dir.isEmpty()))
|
||
m_internal->m_defaultPlanDirectory = dir;
|
||
else
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " failed: \"" << dir << "\" is not a directory.";
|
||
} // PlanEditor::setPlanDefaultDirectory( const QString & dir )
|
||
|
||
|
||
QWidget *PlanEditor::topLevelWidget() const { return m_internal->m_session.topLevelWidget(); }
|
||
|
||
|
||
void PlanEditor::setParticipantsSidcsInUse(const QSet<QString> &sidcs)
|
||
{
|
||
// DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " sidcs: " << sidcs.values().join(QLatin1String(";"));
|
||
|
||
if (!m_internal->m_lookupSymbolManager)
|
||
return;
|
||
m_internal->m_lookupSymbolManager->setParticipantsSidcsInUse(sidcs);
|
||
}
|
||
|
||
|
||
static void importGuezXMLSymbolsFromFile(const AdvancedSymbology::SymbolDictionary &symbolDict);
|
||
|
||
|
||
PlanEditor::PlanEditor(SituationMap::Map *map, LtsSession::LtsSession *ltsSession)
|
||
: QObject()
|
||
, m_internal(new PlanEditor::InternalData(map, PlanEditorSession(ltsSession, this), this))
|
||
{
|
||
init();
|
||
}
|
||
|
||
|
||
PlanEditor::PlanEditor(SituationMap::Map *map, LtsWidgets::LtsBaseLayoutWidget *ltsbaseWidget)
|
||
: QObject()
|
||
, m_internal(new PlanEditor::InternalData(map, PlanEditorSession(ltsbaseWidget, this), this))
|
||
{
|
||
init();
|
||
}
|
||
|
||
|
||
void PlanEditor::init()
|
||
{
|
||
if (!m_internal->m_map)
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "SituationMap::Map instance is nullptr.";
|
||
return;
|
||
}
|
||
|
||
// Qt-doc: event filters are automatically removed when destroyed
|
||
KeyPressDeleteFilter *kpFilter = new KeyPressDeleteFilter(this);
|
||
m_internal->m_map->installEventFilter(kpFilter);
|
||
|
||
SituationMap::RB::RubberbandFactory *rbndFactory = &m_internal->m_map->rubberbandFactory();
|
||
|
||
connect(rbndFactory, &SituationMap::RB::RubberbandFactory::rubberbandCreated, this, &PlanEditor::onRubberbandAction);
|
||
connect(rbndFactory, &SituationMap::RB::RubberbandFactory::rubberbandDestroyed, this, &PlanEditor::onRubberbandAction);
|
||
|
||
AdvancedSymbology::SymbolDictionary &symbolDict = m_internal->m_map->symbolDictionary(); // make symbol dictionary if doesn't exist
|
||
|
||
AdvancedSymbology::LoadStatus dictStatus = symbolDict.loadStatus();
|
||
if ((AdvancedSymbology::LoadStatus::Loaded != dictStatus) && (AdvancedSymbology::LoadStatus::Loading != dictStatus))
|
||
symbolDict.load();
|
||
|
||
importGuezXMLSymbolsFromFile(symbolDict);
|
||
|
||
auto &layerFac = m_internal->m_map->layerFactory();
|
||
layerFac.setLayersVisible({SituationMap::LayerType::Undefined, SituationMap::LayerType::JumpPoint, SituationMap::LayerType::SnapshotOverlay,
|
||
SituationMap::LayerType::Overlay, SituationMap::LayerType::Operational
|
||
}, false);
|
||
|
||
if (m_internal->m_session.isSnapshot()) // ToDo: check if partitionType is sufficiant
|
||
{
|
||
m_internal->initLogicalLayernameAndRenderer(m_internal->m_map->layerFactory().snapshotOverlayLayername(), this);
|
||
layerFac.addOverlayLayer(m_internal->m_logicalLayername, m_internal->m_logicalLayername, true);
|
||
}
|
||
else
|
||
layerFac.addOperationalLayer(m_internal->m_logicalLayername, tr("PlanEditor"));
|
||
|
||
// ToDo: removeOperationalLayer
|
||
|
||
|
||
if (nullptr == topLevelWidget())
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "top level widget is nullptr.";
|
||
}
|
||
|
||
|
||
buildFileBox(m_internal->m_session);
|
||
buildSelectionModeBox(m_internal->m_session);
|
||
buildEditBox(m_internal->m_session);
|
||
buildCreateBox(m_internal->m_session);
|
||
buildHelpBox(m_internal->m_session);
|
||
|
||
m_internal -> m_modelTreeWidget = new ModelTreeWidget(this, topLevelWidget());
|
||
|
||
#ifdef LTS_DEBUG
|
||
m_internal -> m_dlgDebug = buildDebugBox(topLevelWidget());
|
||
|
||
m_internal->m_session.addWidget(m_internal -> m_dlgDebug.data(), title(), QLatin1String("Debug"), LtsWidgets::LayoutArea::eInfoTab, false);
|
||
#endif
|
||
m_internal->m_session.addWidget(m_internal -> m_modelTreeWidget.data(), title(), m_internal->m_modelTreeWidget->objectName(), LtsWidgets::LayoutArea::eInfoTab, false);
|
||
|
||
m_internal->m_session.makeCurrentWidget(m_internal->m_modelTreeWidget, LtsWidgets::LayoutArea::eInfoTab);
|
||
|
||
onHideDialogTab();
|
||
|
||
if (m_internal->m_map)
|
||
{
|
||
connect(m_internal->m_map, &SituationMap::Map::mapObjectsClicked , this, &PlanEditor::onMapObjectClicked);
|
||
connect(m_internal->m_map, &SituationMap::Map::mapObjectsPickedByArea, this, &PlanEditor::onMapObjectClicked);
|
||
|
||
connect(m_internal->m_map, &SituationMap::Map::mapReady, this, &PlanEditor::onEnablePlanEditor);
|
||
|
||
if (!m_internal->m_session.isLtsSession())
|
||
{
|
||
connect(m_internal->m_map, &SituationMap::Map::mapReady, this, [this]()
|
||
{
|
||
connect(m_internal->m_map.data()
|
||
, &SituationMap::Map::contextMenuClicked
|
||
, this
|
||
, &PlanEditor::onContextMenuRequested); // siehe auch sit_map.cpp Zeile 421 ff
|
||
});
|
||
}
|
||
|
||
if (!m_internal->m_map->isReady())
|
||
{
|
||
onDisablePlanEditor();
|
||
}
|
||
connect( qApp, &QCoreApplication::aboutToQuit, this, &PlanEditor::onQuit );
|
||
m_internal->m_map->installViewPortEventFilter(this);
|
||
}
|
||
else
|
||
onDisablePlanEditor();
|
||
|
||
|
||
m_internal->m_favouritesActionManager->initMainMenu();
|
||
|
||
// look for autosaved files
|
||
const QString &tmp = QStringLiteral("/tmp/plan_") + QString::number(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
|
||
if (QFile::exists(tmp))
|
||
{
|
||
if (LtsWidgets::Button::Yes == LtsWidgets::LtsMessageDialog::showMessage( topLevelWidget()
|
||
, tr("Autosaved file exists. Do you want to load it?")
|
||
, title() + QStringLiteral(" : ") + tr("Open autosaved file")
|
||
, LtsWidgets::Behaviour::Modal
|
||
, LtsWidgets::Button::Yes | LtsWidgets::Button::No))
|
||
loadFromFile(tmp);
|
||
}
|
||
|
||
m_internal->m_autosaveTimer->start(300000); // 5 mins = 300000
|
||
|
||
} // void PlanEditor::init( SituationMap::Map * map )
|
||
|
||
|
||
QString PlanEditor::title() const
|
||
{
|
||
return m_internal->m_title;
|
||
}
|
||
|
||
|
||
void PlanEditor::onEnableSymbolWidgets()
|
||
{
|
||
if (m_internal->m_symbolDictLoaded) return;
|
||
m_internal->m_symbolDictLoaded = true;
|
||
m_internal->m_favouritesActionManager->initFromDefaultSettings();
|
||
for (QWidget *w : qAsConst(m_internal->m_symbolWidgets))
|
||
w->setEnabled(true);
|
||
} // PlanEditor::onEnableSymbolWidgets
|
||
|
||
|
||
void PlanEditor::onEnablePlanEditor()
|
||
{
|
||
|
||
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eInfoTab, true);
|
||
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eDialogTab, true);
|
||
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eSpecialTab, true);
|
||
|
||
m_internal->m_session.setMenuEnabled(true);
|
||
m_internal->m_session.setToolBarEnabled(true);
|
||
|
||
} // void PlanEditor::onEnablePlanEditor()
|
||
|
||
|
||
void PlanEditor::onDisablePlanEditor()
|
||
{
|
||
if (nullptr == m_internal->m_currentBboxRubberband)
|
||
{
|
||
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eInfoTab, false);
|
||
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eDialogTab, false);
|
||
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eSpecialTab, false);
|
||
|
||
m_internal->m_session.setMenuEnabled(false);
|
||
m_internal->m_session.setToolBarEnabled(false);
|
||
}
|
||
} // void PlanEditor::onDisablePlanEditor()
|
||
|
||
|
||
bool PlanEditor::readyForUse() const
|
||
{
|
||
return ((m_internal->m_map) && (m_internal->m_map->isReady()));
|
||
}
|
||
|
||
|
||
PlanEditor::~PlanEditor()
|
||
{
|
||
if (m_internal->m_map)
|
||
m_internal->m_map->removeViewPortEventFilter(this);
|
||
if (m_internal->m_textBoxNotifyTimer)
|
||
m_internal->m_textBoxNotifyTimer->stop();
|
||
|
||
} // PlanEditor::~PlanEditor()
|
||
|
||
|
||
bool PlanEditor::event(QEvent *e)
|
||
{
|
||
if (e->type() == QEvent::LanguageChange)
|
||
{
|
||
buildFileBox(m_internal->m_session,true);
|
||
buildSelectionModeBox(m_internal->m_session,true);
|
||
buildEditBox(m_internal->m_session,true);
|
||
buildCreateBox(m_internal->m_session,true);
|
||
buildHelpBox(m_internal->m_session,true);
|
||
m_internal->m_favouritesActionManager->initMainMenu(true);
|
||
}
|
||
return QObject::event(e);
|
||
} // bool PlanEditor::event(QEvent *e)
|
||
|
||
|
||
void PlanEditor::buildSelectionModeBox(const PlanEditorSession &session, bool retranslate)
|
||
{
|
||
LtsWidgets::PluginData pluginAction;
|
||
LtsWidgets::LtsDragIcon *currentDragIcon = nullptr;
|
||
QButtonGroup *selectButtonGroup = new QButtonGroup(this);
|
||
|
||
selectButtonGroup -> setExclusive(true);
|
||
|
||
pluginAction.menuGroup = tr("Selection");
|
||
|
||
pluginAction.identifier = QStringLiteral("Mouse_Pick_Selection");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_PICK_ICON_NAME));
|
||
pluginAction.menuText = tr("Mouse Pick Selection");
|
||
pluginAction.tooltip = tr("Selection with single mouse clicks");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::Picking; };
|
||
|
||
currentDragIcon = session.addMenuAction(pluginAction);
|
||
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
|
||
|
||
if (currentDragIcon)
|
||
{
|
||
currentDragIcon->setCheckable(true);
|
||
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::Picking);
|
||
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::Picking));
|
||
}
|
||
|
||
pluginAction.identifier = QStringLiteral("Line_Selection");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_LINE_ICON_NAME));
|
||
pluginAction.menuText = tr("Line Selection");
|
||
pluginAction.tooltip = tr("Selection with a line");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::Line; };
|
||
|
||
currentDragIcon = session.addMenuAction(pluginAction);
|
||
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
|
||
|
||
if (currentDragIcon)
|
||
{
|
||
currentDragIcon->setCheckable(true);
|
||
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::Line);
|
||
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::Line));
|
||
}
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Lasso_Selection");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_LASSO_EDIT_ICON_NAME));
|
||
pluginAction.menuText = tr("Lasso Selection");
|
||
pluginAction.tooltip = tr("Selection with a lasso");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::Lasso; };
|
||
|
||
currentDragIcon = session.addMenuAction(pluginAction);
|
||
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
|
||
|
||
if (currentDragIcon)
|
||
{
|
||
currentDragIcon->setCheckable(true);
|
||
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::Lasso);
|
||
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::Lasso));
|
||
}
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Rectangle_Selection");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_RECT_EDIT_ICON_NAME));
|
||
pluginAction.menuText = tr("Rectangle Selection");
|
||
pluginAction.tooltip = tr("Selection with a rectangle");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::Rectangle; };
|
||
|
||
currentDragIcon = session.addMenuAction(pluginAction);
|
||
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
|
||
|
||
if (currentDragIcon)
|
||
{
|
||
currentDragIcon->setCheckable(true);
|
||
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::Rectangle);
|
||
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::Rectangle));
|
||
}
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Mouse_Pick_Selection_and_Edit_Geometry");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_PICK_EDIT_ICON_NAME));
|
||
pluginAction.menuText = tr("Mouse Pick Selection and Edit Geometry");
|
||
pluginAction.tooltip = tr("Selection with single mouse clicks and starts proper rubberband to edit geometry");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::PickingAndEdit; };
|
||
|
||
currentDragIcon = session.addMenuAction(pluginAction);
|
||
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
|
||
|
||
if (currentDragIcon)
|
||
{
|
||
currentDragIcon->setCheckable(true);
|
||
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::PickingAndEdit);
|
||
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::PickingAndEdit));
|
||
}
|
||
/*
|
||
Dialog * dialog = new LtsWidgets::LtsDialog( parent );
|
||
QHBoxLayout * layout = new QHBoxLayout( dialog );
|
||
QToolButton * tb = nullptr;
|
||
|
||
dialog->setTitle("Picking Mode");
|
||
|
||
tb = new QToolButton(dialog);
|
||
{
|
||
tb->setText( tr("Picking") );
|
||
tb->setIcon( Utils::getIcon(QLatin1String(SELECT_PICK_ICON_NAME)) );
|
||
tb->setToolTip( tr("Selection with single mouse clicks") );
|
||
connect( tb, &QToolButton::clicked, this, &PlanEditor::onSelectionActivatePicking );
|
||
}
|
||
layout->addWidget( tb, 0 );
|
||
|
||
tb = new QToolButton(dialog);
|
||
{
|
||
tb->setText( tr("Line Select") );
|
||
tb->setIcon( Utils::getIcon(QLatin1String(SELECT_LINE_ICON_NAME)) );
|
||
tb->setToolTip( tr("Selection with intersection line") );
|
||
connect( tb, &QToolButton::clicked, this, &PlanEditor::onSelectionActivatePicking );
|
||
}
|
||
layout->addWidget( tb, 0 );
|
||
|
||
layout->addStretch(3);
|
||
|
||
return dialog;
|
||
*/
|
||
} // PlanEditor::buildSelectionModeBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
|
||
|
||
|
||
|
||
void PlanEditor::buildFileBox(const PlanEditorSession &session, bool retranslate)
|
||
{
|
||
|
||
if (m_internal->m_session.isLtsSession())
|
||
{
|
||
return; // skip if running as plugin
|
||
}
|
||
|
||
LtsWidgets::PluginData pluginAction;
|
||
|
||
pluginAction.menuGroup = tr("File");
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("New_Plan_File");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_NEW_ICON_NAME));
|
||
pluginAction.menuText = tr("New Plan");
|
||
pluginAction.tooltip = tr("Create empty plan");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanCreate(); };
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
pluginAction.identifier = QStringLiteral("Open_Plan_File");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_OPEN_ICON_NAME));
|
||
pluginAction.menuText = tr("Open Plan");
|
||
pluginAction.tooltip = tr("Load plan from file");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanLoad(); };
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Import_Plan_File");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_IMPORT_ICON_NAME));
|
||
pluginAction.menuText = tr("Import Plan");
|
||
pluginAction.tooltip = tr("Import plan from file");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanImport(); };
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Save_Plan_File");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_SAVE_ICON_NAME));
|
||
pluginAction.menuText = tr("Save");
|
||
pluginAction.tooltip = tr("Save plan to file");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanSave(); };
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("SaveAs_Plan_File");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_SAVEAS_ICON_NAME));
|
||
pluginAction.menuText = tr("Save As");
|
||
pluginAction.tooltip = tr("Save plan to file as");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanSaveAs(); };
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Export_Plan_File");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_SAVEAS_ICON_NAME));
|
||
pluginAction.menuText = tr("Export Selected");
|
||
pluginAction.tooltip = tr("Save selected plan parts to file as");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanSaveSelected(); };
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
pluginAction.identifier = QStringLiteral("Print_Plan");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_PRINT_ICON_NAME));
|
||
pluginAction.menuText = tr("Print");
|
||
pluginAction.tooltip = tr("Print plan");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanPrint(); };
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
#ifdef HAS_CLOSE_BUTTON
|
||
pluginAction.identifier = QStringLiteral("Close");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
|
||
pluginAction.menuText = tr("Close");
|
||
pluginAction.tooltip = tr("Close Plan Editor");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onQuit(); };
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
#endif
|
||
|
||
//#define TEST_AGGREGATION 1
|
||
#ifdef TEST_AGGREGATION
|
||
pluginAction.identifier = QStringLiteral("ParticipantAggregation");
|
||
pluginAction.menuIcon = QIcon(QLatin1String("icon:overlays.svg"));
|
||
pluginAction.menuText = tr("Participant Aggregation");
|
||
pluginAction.tooltip = tr("Aggregation settings for participants");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
QWidget *parent = this->topLevelWidget();
|
||
|
||
SituationMap::ParticipantAggregationDialog *pad = new SituationMap::ParticipantAggregationDialog(m_internal->m_map, parent);
|
||
m_internal->m_session.addWidget(pad, title(), tr("Participant Aggregation"), LtsWidgets::LayoutArea::eDialogTab);
|
||
};
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
#endif
|
||
|
||
#ifdef TEST_RUBBERBAND_RECTANGLE_5X5
|
||
pluginAction.identifier = QStringLiteral("Make_Rectangle_Rubberband");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
|
||
pluginAction.menuText = tr("Make Rectangle Rubberband");
|
||
pluginAction.tooltip = tr("Make Rectangle Rubberband");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
SituationMap::RB::RubberbandRectangle *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandRectangle>(m_internal.get());
|
||
if (rubberband)
|
||
{
|
||
rubberband->setAutoDelete(true);
|
||
rubberband->buildRectangleRelativeToBottomLeftCorner( m_internal->m_map->centerPoint(), 5, 5, QPointF(0,1) );
|
||
}
|
||
|
||
};
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
#endif
|
||
|
||
// #define TEST_SIGHT_FAN 1
|
||
#ifdef TEST_SIGHT_FAN
|
||
|
||
pluginAction.identifier = QStringLiteral("Make_SIGHT_FAN");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
|
||
pluginAction.menuText = tr("Make Sight Fan");
|
||
pluginAction.tooltip = tr("Make Sight Fan");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
SituationMap::RB::RubberbandEllipse *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandEllipse>(m_internal.get());
|
||
if (rubberband)
|
||
{
|
||
rubberband->setAutoDelete(true);
|
||
rubberband->constrainQuadratic(true);
|
||
rubberband->constrainOrthogonal(true);
|
||
rubberband->enableSector(true);
|
||
|
||
static SituationMap::RefPointer<SituationMap::SightFan> sightFan;
|
||
|
||
std::function<bool(SituationMap::RB::RubberbandBase*)> updateSightFan = [this](SituationMap::RB::RubberbandBase* rbBase) -> bool
|
||
{
|
||
SituationMap::RB::RubberbandEllipse *rubberElli = dynamic_cast<SituationMap::RB::RubberbandEllipse*>(rbBase);
|
||
if (rubberElli)
|
||
{
|
||
QPointF center;
|
||
double diameter;
|
||
double dummy;
|
||
QPointF direction;
|
||
double startAngle = 0.0;
|
||
double dAngle = 2.0 / 180.0*MathConst::pi;
|
||
unsigned int noBeams = 180;
|
||
|
||
rubberElli->rectangleParameter(center, diameter, dummy, direction);
|
||
if (diameter > 0.0)
|
||
{
|
||
double radius = diameter * 0.5;
|
||
if (rubberElli->hasSector())
|
||
{
|
||
startAngle = SituationMap::MathUtils::getMathAngle(rubberElli->sectorStart());
|
||
double endAngle = SituationMap::MathUtils::getMathAngle(rubberElli->sectorEnd());
|
||
|
||
noBeams = floor((endAngle - startAngle) / dAngle);
|
||
}
|
||
|
||
if (nullptr == sightFan.get())
|
||
{
|
||
SituationMap::ObjectFactory &objFac = m_internal->m_map->objectFactory();
|
||
sightFan = objFac.create<SituationMap::SightFan>(QLatin1String("Tools"));
|
||
if (sightFan)
|
||
{
|
||
sightFan->initFan( SituationMap::Point3D(center.x(),center.y(),0.0), 1.5, radius, radius / 1000.0, startAngle, dAngle, noBeams, 0.6 );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
sightFan->setInnerRadius(radius/1000.0);
|
||
sightFan->setRadius(radius);
|
||
sightFan->setStartAngle(startAngle);
|
||
sightFan->setNoOfFans(noBeams);
|
||
sightFan->move(center);
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}; // std::function<bool(SituationMap::RB::RubberbandBase*)>
|
||
|
||
rubberband->installExternalUpdate(updateSightFan);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this](SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (nullptr != sightFan.get())
|
||
{
|
||
sightFan->removeMySelf();
|
||
sightFan = nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandEllipse *rubberElli = dynamic_cast<SituationMap::RB::RubberbandEllipse*>(rubberband);
|
||
if (rubberElli)
|
||
{
|
||
SituationMap::ObjectFactory &objFac = m_internal->m_map->objectFactory();
|
||
|
||
SituationMap::RefPointer<SituationMap::SightFan> sightFan = objFac.create<SituationMap::SightFan>(QLatin1String("Tools"));
|
||
|
||
if (sightFan)
|
||
{
|
||
QPointF center = rubberElli->centerPoint();
|
||
double diameter;
|
||
double dummy;
|
||
QPointF direction;
|
||
double startAngle = 0.0;
|
||
double dAngle = 2.0/180.0*MathConst::pi;
|
||
unsigned int noBeams = 180;
|
||
|
||
rubberElli->rectangleParameter(center, diameter, dummy, direction);
|
||
|
||
if (rubberElli->hasSector())
|
||
{
|
||
startAngle = SituationMap::MathUtils::getMathAngle(rubberElli->sectorStart());
|
||
double endAngle = SituationMap::MathUtils::getMathAngle(rubberElli->sectorEnd());
|
||
|
||
noBeams = ceil(((startAngle > endAngle) ? (endAngle - startAngle + MathConst::pi_two) : (endAngle - startAngle)) / dAngle);
|
||
}
|
||
|
||
double radius = diameter * 0.5;
|
||
|
||
sightFan->initFan(SituationMap::Point3D(center.x(),center.y(),0.0), 1.5, radius, radius / 1000.0, startAngle, dAngle, noBeams, 0.6 );
|
||
}
|
||
}
|
||
});
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this](SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (nullptr != sightFan.get())
|
||
{
|
||
sightFan->removeMySelf();
|
||
sightFan = nullptr;
|
||
}
|
||
|
||
onRubberbandAbort(rubberband);
|
||
});
|
||
}
|
||
};
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
#endif
|
||
|
||
//#define TEST_SIGHT_FAN_DIALOG 1
|
||
#ifdef TEST_SIGHT_FAN_DIALOG
|
||
pluginAction.identifier = QStringLiteral("Make_SIGHT_FAN_DIALOG");
|
||
pluginAction.menuIcon = QIcon();
|
||
pluginAction.menuText = tr("Make Sight Fan Dialog");
|
||
pluginAction.tooltip = tr("Make Sight Fan Dialog");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
ViewshedDialog *dlg = new ViewshedDialog(m_internal->m_session.topLevelWidget());
|
||
|
||
static double viewshedAlpha = 1.0;
|
||
static double viewshedInnerRadius = 100.0;
|
||
static double viewshedObserverHeight = 2.0;
|
||
static double viewshedTargetHeight = 2.0;
|
||
static double viewshedBeamAngle = 2.0;
|
||
|
||
dlg->initValues(viewshedAlpha, viewshedInnerRadius, viewshedObserverHeight, viewshedTargetHeight, viewshedBeamAngle);
|
||
|
||
connect(dlg, &ViewshedDialog::createViewshed, this, [this, dlg]()
|
||
{
|
||
|
||
viewshedAlpha = dlg->alpha();
|
||
viewshedInnerRadius = dlg->innerRadius();
|
||
viewshedObserverHeight = dlg->observerHeight();
|
||
viewshedTargetHeight = dlg->targetHeight();
|
||
viewshedBeamAngle = dlg->beamAngle();
|
||
|
||
this->m_internal->m_map->viewshed().create(viewshedAlpha, viewshedInnerRadius, viewshedObserverHeight, viewshedTargetHeight, viewshedBeamAngle);
|
||
|
||
});
|
||
|
||
connect(dlg, &ViewshedDialog::removeViewshed, this, [this]()
|
||
{
|
||
this->m_internal->m_map->viewshed().remove();
|
||
});
|
||
|
||
connect(dlg, &ViewshedDialog::parameterChanged, this, [this, dlg]()
|
||
{
|
||
|
||
viewshedAlpha = dlg->alpha();
|
||
viewshedInnerRadius = dlg->innerRadius();
|
||
viewshedObserverHeight = dlg->observerHeight();
|
||
viewshedTargetHeight = dlg->targetHeight();
|
||
viewshedBeamAngle = dlg->beamAngle();
|
||
|
||
this->m_internal->m_map->viewshed().modify(-1,viewshedAlpha, viewshedInnerRadius, viewshedObserverHeight, viewshedTargetHeight, viewshedBeamAngle);
|
||
|
||
});
|
||
|
||
m_internal->m_session.addWidget( dlg, tr("Situation Map"), QLatin1String("ViewshedDialog"), LtsWidgets::LayoutArea::eDialogTab, true );
|
||
};
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
#endif
|
||
|
||
//#define TEST_PARTICIPANT_LIST
|
||
#ifdef TEST_PARTICIPANT_LIST
|
||
pluginAction.identifier = QStringLiteral("setParticipantsSidcList");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
|
||
pluginAction.menuText = tr("Test setParticipantsSidcList");
|
||
pluginAction.tooltip = tr("setParticipantsSidcList");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
if (isSymbolModelValid())
|
||
{
|
||
QStringList sidcList;
|
||
|
||
sidcList << AdvancedSymbology::SidcCodec::encodeComplete(AdvancedSymbology::SymbologyType::MIL2525D, QStringLiteral("10010100001205000000"));
|
||
sidcList << AdvancedSymbology::SidcCodec::encodeComplete(AdvancedSymbology::SymbologyType::MIL2525D, QStringLiteral("10010100001106000000"));
|
||
sidcList << AdvancedSymbology::SidcCodec::encodeComplete(AdvancedSymbology::SymbologyType::MIL2525D, QStringLiteral("10011500001202030000"));
|
||
|
||
setParticipantsSidcList(sidcList);
|
||
}
|
||
};
|
||
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
pluginAction.identifier = QStringLiteral("resetParticipantsSidcList");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
|
||
pluginAction.menuText = tr("Test resetParticipantsSidcList");
|
||
pluginAction.tooltip = tr("resetParticipantsSidcList");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
if (isSymbolModelValid())
|
||
{
|
||
setParticipantsSidcList(QStringList());
|
||
}
|
||
};
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
#endif
|
||
|
||
//#define TEST_PARALLEL_TRANSLATION
|
||
#ifdef TEST_PARALLEL_TRANSLATION
|
||
pluginAction.identifier = QStringLiteral("ParallelTranslation");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
|
||
pluginAction.menuText = tr("Test Parallel Translation");
|
||
pluginAction.tooltip = tr("Test Parallel Translation");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
SituationMap::RB::RubberbandCorridor *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandCorridor>(m_internal.get());
|
||
if (rubberband)
|
||
{
|
||
static std::function<bool(SituationMap::RB::RubberbandBase*)> testParallel = [this](SituationMap::RB::RubberbandBase *r) -> bool
|
||
{
|
||
const QVector<QPointF> &line = static_cast<SituationMap::RB::RubberbandCorridor *>(r)->coordinateVector();
|
||
if (line.size() > 2)
|
||
{
|
||
double distance = static_cast<SituationMap::RB::RubberbandCorridor *>(r)->corridorWidth();
|
||
|
||
const QVector<QPointF> &pLine =
|
||
SituationMap::MathUtils::GeometryEngine::parallelTranslation( m_internal->m_map->coordTranslationFunctor(), line, distance );
|
||
|
||
static SituationMap::Polyline *pLineObjPtr = nullptr;
|
||
|
||
if (nullptr == pLineObjPtr)
|
||
{
|
||
SituationMap::ObjectFactory &objFac = m_internal->m_map->objectFactory();
|
||
|
||
pLineObjPtr = objFac.create<SituationMap::Polyline>( SituationMap::INVALID_MAP_ID
|
||
, QStringLiteral("PlanEditorLayer")
|
||
, QLatin1String("Test")).get();
|
||
}
|
||
|
||
if (pLineObjPtr)
|
||
{
|
||
if (pLine.size() > 1)
|
||
{
|
||
SituationMap::LineStyle lineStyle;
|
||
|
||
lineStyle.setLineWidth(5);
|
||
lineStyle.setLineColor(QColor(Qt::green));
|
||
|
||
pLineObjPtr->setLineStyle(lineStyle);
|
||
pLineObjPtr->setPositions(SituationMap::convert2D3D(pLine));
|
||
pLineObjPtr->updateView();
|
||
}
|
||
else
|
||
{
|
||
pLineObjPtr->removeMySelf();
|
||
pLineObjPtr = nullptr;
|
||
}
|
||
}
|
||
|
||
// and now back again
|
||
if (1)
|
||
{
|
||
const QVector<QPointF> &rLine =
|
||
SituationMap::MathUtils::GeometryEngine::parallelTranslation( m_internal->m_map->coordTranslationFunctor(), pLine, -distance );
|
||
|
||
static SituationMap::Polyline *rLineObjPtr = nullptr;
|
||
|
||
if (nullptr == rLineObjPtr)
|
||
{
|
||
SituationMap::ObjectFactory &objFac = m_internal->m_map->objectFactory();
|
||
|
||
rLineObjPtr = objFac.create<SituationMap::Polyline>(SituationMap::INVALID_MAP_ID
|
||
, QStringLiteral("PlanEditorLayer")
|
||
, QLatin1String("Test")).get();
|
||
}
|
||
|
||
if (rLineObjPtr)
|
||
{
|
||
if (rLine.size() > 1)
|
||
{
|
||
SituationMap::LineStyle lineStyle;
|
||
|
||
lineStyle.setLineWidth(10);
|
||
lineStyle.setLineColor(QColor(Qt::red));
|
||
|
||
rLineObjPtr->setLineStyle(lineStyle);
|
||
rLineObjPtr->setPositions(SituationMap::convert2D3D(rLine));
|
||
rLineObjPtr->updateView();
|
||
}
|
||
else
|
||
{
|
||
rLineObjPtr->removeMySelf();
|
||
rLineObjPtr = nullptr;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
};
|
||
|
||
rubberband->setAutoDelete(true);
|
||
|
||
rubberband->installExternalUpdate(testParallel);
|
||
}
|
||
};
|
||
if (retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
#endif
|
||
} // PlanEditor::buildFileBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
|
||
|
||
|
||
void PlanEditor::buildEditBox(const PlanEditorSession &session, bool retranslate)
|
||
{
|
||
LtsWidgets::PluginData pluginAction;
|
||
|
||
pluginAction.menuGroup = tr("Edit");
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Undo");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(UNDO_ICON_NAME));
|
||
pluginAction.menuText = tr("Undo");
|
||
pluginAction.tooltip = tr("Undo last actions. Undo is limited to the last %1 actions").arg(m_internal->m_geoModel->maxUndoSteps());
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onUndo(); };
|
||
|
||
LtsWidgets::LtsDragIcon *ltsButton = session.addMenuAction(pluginAction);
|
||
QMenu *undoMenu = new QMenu();
|
||
QAction *tmpAction = undoMenu->addAction(tr("Show Undo History"));
|
||
|
||
connect(tmpAction, &QAction::triggered, this, &PlanEditor::onUndoHistory);
|
||
|
||
if (ltsButton)
|
||
{
|
||
ltsButton -> setMenu(undoMenu);
|
||
ltsButton -> setEnabled(false);
|
||
|
||
if (!retranslate)
|
||
{
|
||
m_internal->m_ltsItems += ltsButton;
|
||
m_internal->m_btnUndo = ltsButton;
|
||
}
|
||
}
|
||
|
||
pluginAction.identifier = QStringLiteral("Redo");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(REDO_ICON_NAME));
|
||
pluginAction.menuText = tr("Redo");
|
||
pluginAction.tooltip = tr("Redo last Undo");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onRedo(); };
|
||
|
||
ltsButton = session.addMenuAction(pluginAction);
|
||
|
||
QMenu *redoMenu = new QMenu(ltsButton);
|
||
|
||
tmpAction = redoMenu->addAction(tr("Show Redo History"));
|
||
|
||
connect(tmpAction, &QAction::triggered, this, &PlanEditor::onRedoHistory);
|
||
|
||
if (ltsButton)
|
||
{
|
||
ltsButton -> setMenu(redoMenu);
|
||
ltsButton -> setEnabled(false);
|
||
|
||
if (!retranslate)
|
||
{
|
||
m_internal->m_ltsItems += ltsButton;
|
||
m_internal->m_btnRedo = ltsButton;
|
||
}
|
||
}
|
||
|
||
pluginAction.identifier = QStringLiteral("Copy_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(COPY_ICON_NAME));
|
||
pluginAction.menuText = tr("Copy");
|
||
pluginAction.tooltip = tr("Copy selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onCopy(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Cut_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(CUT_ICON_NAME));
|
||
pluginAction.menuText = tr("Cut");
|
||
pluginAction.tooltip = tr("Cut selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onCut(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Paste_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(PASTE_ICON_NAME));
|
||
pluginAction.menuText = tr("Paste");
|
||
pluginAction.tooltip = tr("Paste selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPaste(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
pluginAction.identifier = QStringLiteral("MetaData");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_METADATA_ICON_NAME));
|
||
pluginAction.menuText = tr("Meta Data");
|
||
pluginAction.tooltip = tr("Show Meta Data of Plan");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onMetaData(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Group_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(GROUP_SELECTED_ICON_NAME));
|
||
pluginAction.menuText = tr("Group");
|
||
pluginAction.tooltip = tr("Group selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onGroup(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Ungroup_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(UNGROUP_SELECTED_ICON_NAME));
|
||
pluginAction.menuText = tr("Ungroup");
|
||
pluginAction.tooltip = tr("Ungroup selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onUngroup(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Delete_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DELETE_SELECTED_ICON_NAME));
|
||
pluginAction.menuText = tr("Delete");
|
||
pluginAction.tooltip = tr("Delete selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onDelete(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("GraphicAttributes");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(ATTR_EDIT_SELECTED_ICON_NAME));
|
||
pluginAction.menuText = tr("Graphic Attributes");
|
||
pluginAction.tooltip = tr("Edit Attributes of selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onEditAttributes(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Edit_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(EDIT_SELECTED_ICON_NAME));
|
||
pluginAction.menuText = tr("Edit");
|
||
pluginAction.tooltip = tr("Edit geometry of selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onEditGraphicGeometry(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Move_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(MOVE_SELECTED_ICON_NAME));
|
||
pluginAction.menuText = tr("Move");
|
||
pluginAction.tooltip = tr("Move geometry of selected features");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onMoveGraphicGeometry(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Rotate_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(ROTATE_SELECTED_ICON_NAME));
|
||
pluginAction.menuText = tr("Rotate");
|
||
pluginAction.tooltip = tr("Rotate geometry of selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onRotateGraphicGeometry(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Scale_Feature");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SCALE_SELECTED_ICON_NAME));
|
||
pluginAction.menuText = tr("Scale");
|
||
pluginAction.tooltip = tr("Scale geometry of selected feature");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onScaleGraphicGeometry(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
} // void PlanEditor::buildEditBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
|
||
|
||
|
||
void PlanEditor::buildCreateBox(const PlanEditorSession &session, bool retranslate)
|
||
{
|
||
LtsWidgets::PluginData pluginAction;
|
||
|
||
pluginAction.menuGroup = tr("Create Graphics");
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_Line");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_LINE_ICON_NAME));
|
||
pluginAction.menuText = tr("Line");
|
||
pluginAction.tooltip = tr("Draw line");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateLine(this, m_internal.get()));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onLineCreateRubberband(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_Polyline");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_POLYLINE_ICON_NAME));
|
||
pluginAction.menuText = tr("Polyline");
|
||
pluginAction.tooltip = tr("Draw polyline");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPolylineCreateRubberband(); };
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreatePolyLine(this, m_internal.get()));
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_Polygon");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_POLYGON_ICON_NAME));
|
||
pluginAction.menuText = tr("Polygon");
|
||
pluginAction.tooltip = tr("Draw polygon");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreatePolygon(this, m_internal.get()));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPolygonCreateRubberband(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_Rectangle");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_RECTANGLE_ICON_NAME));
|
||
pluginAction.menuText = tr("Rectangle");
|
||
pluginAction.tooltip = tr("Draw rectangle");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateRectangle(this, m_internal.get()));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onRectangleCreateRubberband(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_SmoothLiné");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_SPLINE_ICON_NAME));
|
||
pluginAction.menuText = tr("Smooth Line");
|
||
pluginAction.tooltip = tr("Draw spline based smooth line");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreatePolyLine(this, m_internal.get(), true));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onSmoothLineCreateRubberband(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_Ellipse");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_ELLIPSE_ICON_NAME));
|
||
pluginAction.menuText = tr("Ellipse");
|
||
pluginAction.tooltip = tr("Draw ellipse");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateRectangle(this, m_internal.get(), true));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onEllipseCreateRubberband(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_Symbol");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_SYMBOL_ICON_NAME));
|
||
pluginAction.menuText = tr("Symbol");
|
||
pluginAction.tooltip = tr("Draw symbol from symbol dictionary");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateRectangle(this, m_internal.get(), true));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { onChooseSymbol(); };
|
||
|
||
LtsWidgets::LtsDragIcon *pbCreateSymbol = session.addMenuAction(pluginAction);
|
||
pbCreateSymbol->setEnabled(m_internal->m_symbolDictLoaded);
|
||
|
||
if (!retranslate)
|
||
{
|
||
m_internal->m_ltsItems += pbCreateSymbol;
|
||
m_internal->m_symbolWidgets += pbCreateSymbol; // set button to symbolWidgets list to enable the button if dictionary is loaded
|
||
}
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_Participants");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_PARTICIPANT_ICON_NAME));
|
||
pluginAction.menuText = tr("Participants");
|
||
pluginAction.tooltip = tr("Draw participants from symbol dictionary");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateRectangle(this, m_internal.get(), true));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
onClearSelection();
|
||
if (m_internal->m_symbolDictLoaded) m_internal->m_lookupSymbolManager -> onOpenParticipantDialog();
|
||
};
|
||
|
||
LtsWidgets::LtsDragIcon *pbCreateParticipants = session.addMenuAction(pluginAction);
|
||
pbCreateParticipants->setEnabled(m_internal->m_symbolDictLoaded);
|
||
|
||
if (!retranslate)
|
||
{
|
||
m_internal->m_ltsItems += pbCreateParticipants;
|
||
m_internal->m_symbolWidgets += pbCreateParticipants; // set button to symbolWidgets list to enable the button if dictionary is loaded
|
||
}
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_Text");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_TEXT_ICON_NAME));
|
||
pluginAction.menuText = tr("Text");
|
||
pluginAction.tooltip = tr("Draw single text line");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateTextLine(this, m_internal.get()));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
PlanEditor::onTextLineCreateRubberband();
|
||
};
|
||
if (!retranslate)
|
||
session.addMenuAction(pluginAction);
|
||
else
|
||
m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
|
||
pluginAction.identifier = QStringLiteral("Draw_TextBoxPixel");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_TEXT_ICON_NAME));
|
||
pluginAction.menuText = tr("Pixel-based Text");
|
||
pluginAction.tooltip = tr("Draw textbox");
|
||
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateTextLine(this, m_internal.get()));
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
PlanEditor::onTextBoxPixelCreateRubberband();
|
||
};
|
||
if (!retranslate)
|
||
session.addMenuAction(pluginAction);
|
||
else
|
||
m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
|
||
} // void PlanEditor::buildCreateBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
|
||
|
||
|
||
void PlanEditor::buildHelpBox(const PlanEditorSession &session, bool retranslate)
|
||
{
|
||
LtsWidgets::PluginData pluginAction;
|
||
|
||
pluginAction.menuGroup = tr("Help");
|
||
|
||
if (!m_internal->m_session.isLtsSession())
|
||
{
|
||
|
||
if (m_internal->m_viewHelp != nullptr)
|
||
{
|
||
pluginAction.identifier = QStringLiteral("Help");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(HELP_ICON_NAME));
|
||
pluginAction.menuText = tr("View Online Documentation");
|
||
pluginAction.tooltip = tr("Shows online documentation");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onViewHelp(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
}
|
||
|
||
pluginAction.identifier = QStringLiteral("About");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(ABOUT_ICON_NAME));
|
||
pluginAction.menuText = tr("About");
|
||
pluginAction.tooltip = tr("Shows about information");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onViewAbout(); };
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
}
|
||
|
||
//#define TestSymbolDialog
|
||
#ifdef TestSymbolDialog
|
||
pluginAction.identifier = QStringLiteral("SymbolDialog");
|
||
pluginAction.menuIcon = Utils::getIcon(QLatin1String(ABOUT_ICON_NAME));
|
||
pluginAction.menuText = tr("Symbol Dialog");
|
||
pluginAction.tooltip = tr("Selected a symbol");
|
||
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
|
||
{
|
||
qCritical() << "********************************* show symbol dialog ***************************************************************";
|
||
|
||
AdvancedSymbology::Gui::BaseSymbolLookupDialog *symbolDialog = new AdvancedSymbology::Gui::BaseSymbolLookupDialog(m_internal->m_map->symbolDictionary(), true, nullptr);
|
||
|
||
connect(symbolDialog, &AdvancedSymbology::Gui::BaseSymbolLookupDialog::lookupApplied, symbolDialog, [this](const QString & sidc)
|
||
{
|
||
qCritical() << "********************************* Selected Symbol : " << sidc << " ************************************************";
|
||
});
|
||
|
||
m_internal->m_session.addWidget(symbolDialog
|
||
, title()
|
||
, tr("Select Symbol")
|
||
, LtsWidgets::LayoutArea::eDialogTab
|
||
false);
|
||
};
|
||
|
||
if (!retranslate) session.addMenuAction(pluginAction);
|
||
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
|
||
#endif
|
||
|
||
} // void PlanEditor::buildHelpBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
|
||
|
||
|
||
LtsWidgets::LtsDialog *PlanEditor::buildDebugBox(QWidget *parent)
|
||
{
|
||
|
||
Dialog *gbLayer = new Dialog(parent, LtsWidgets::ButtonCombination::SeamlessDialog);
|
||
QVBoxLayout *tabLayout = new QVBoxLayout(gbLayer);
|
||
|
||
gbLayer -> setObjectName(QLatin1String("PlanEditor::PlanDebug"));
|
||
gbLayer -> setTitle(tr("Plan Debug"));
|
||
|
||
m_internal->m_teDebug = new QTextEdit(gbLayer);
|
||
m_internal->m_teDebug -> setReadOnly(true);
|
||
|
||
tabLayout->addWidget(m_internal->m_teDebug, 2);
|
||
|
||
return gbLayer;
|
||
|
||
} // PlanEditor::buildDebugBox( QWidget * parent )
|
||
|
||
|
||
bool PlanEditor::eventFilter(QObject *obj, QEvent *event)
|
||
{
|
||
if (QEvent::MouseButtonPress == event->type())
|
||
{
|
||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||
|
||
if (Qt::LeftButton == mouseEvent->button())
|
||
{
|
||
if (SituationMap::RB::Rubberband::activeRubberbands(m_internal->m_map.data()).isEmpty())
|
||
{
|
||
if (!(QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier) || QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier)))
|
||
{
|
||
switch (m_internal->m_selectionMode)
|
||
{
|
||
case SelectionMode::Picking: break;
|
||
case SelectionMode::PickingAndEdit: break;
|
||
|
||
case SelectionMode::Line:
|
||
case SelectionMode::Lasso:
|
||
case SelectionMode::Rectangle:
|
||
new SelectionWorker(this, m_internal->m_geoModel, m_internal->m_map.data(), m_internal->m_selectionMode, mouseEvent->pos());
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return QObject::eventFilter(obj, event);
|
||
} // bool PlanEditor::eventFilter( QObject * obj, QEvent * event )
|
||
|
||
|
||
void PlanEditor::onRubberbandAction()
|
||
{
|
||
if (nullptr == m_internal) return; // PlanEditor is expiring
|
||
const QList<SituationMap::RB::RubberbandBase *> &activeRbndList = SituationMap::RB::Rubberband::activeRubberbands(m_internal->m_map.data());
|
||
(activeRbndList.isEmpty()) ? onEnablePlanEditor() : onDisablePlanEditor();
|
||
} // void PlanEditor::onRubberbandAction()
|
||
|
||
|
||
void PlanEditor::onHideDialogTab()
|
||
{
|
||
m_internal->m_lookupSymbolManager -> onCloseDialog();
|
||
m_internal->m_attributeDialogManager -> onCloseDialog();
|
||
|
||
} // void PlanEditor::onHideDialogTab
|
||
|
||
|
||
void PlanEditor::onShowDialogTab(const SituationMap::GeometryModel::Node &node)
|
||
{
|
||
onEnablePlanEditor();
|
||
m_internal->m_attributeDialogManager->onOpenDialog(node);
|
||
|
||
// 28.10.2019, Norbert Thoden
|
||
// RP 553 Schnappschuss: in einem bereits angelegtem Textfeld können keine Änderungen vorgenommen werden..
|
||
// getStyleAttributes wird fuer alle PrimitiveTypen aufgerufen:
|
||
m_internal->m_attributeDialogManager->getStyleAttributes(node);
|
||
|
||
} // PlanEditor::onShowDialogTab
|
||
|
||
|
||
void PlanEditor::saveToFile(const QString &filePath)
|
||
{
|
||
QFile file(filePath);
|
||
|
||
if (file.open(QIODevice::WriteOnly))
|
||
{
|
||
file.write(m_internal->m_geoModel->toByteArray());
|
||
m_internal->m_geoModel->resetModificationCounter();
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Save plan to file \"%1\"failed").arg(filePath), title());
|
||
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Saving plan model to file - " << filePath << " - failed.";
|
||
}
|
||
} // PlanEditor::saveToFile( const QString & filePath )
|
||
|
||
|
||
void PlanEditor::initializePlan()
|
||
{
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
|
||
m_internal->m_geoModelRenderer->render();
|
||
|
||
initializePlanTextBoxPixel();
|
||
|
||
// m_internal->m_map->getQGraphicsView() seems to be nullptr , mostly during slotReplaySessionForPlanEditorStarted
|
||
if (m_internal->m_map &&
|
||
m_internal->m_map->getQGraphicsView() &&
|
||
m_internal->m_map->getQGraphicsView()->viewport())
|
||
m_internal->m_map->getQGraphicsView()->viewport()->update();
|
||
} // void PlanEditor::initializePlan()
|
||
|
||
void PlanEditor::initializePlanTextBoxPixel()
|
||
{
|
||
const QString &strRef =
|
||
m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes).toString();
|
||
const QVector<SituationMap::PixelTextBoxData> &ptbdCont =
|
||
SituationMap::PixelTextBoxData::pixelTextBoxContainerFromJsonStr(strRef);
|
||
|
||
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
|
||
const int parentId = PLAN_EDITOR_TEXTBOX_PARENT_ID;
|
||
pixelBasedTextBoxHandler.removeAllTextBoxesOfParent(parentId);
|
||
|
||
m_internal->resetTextBoxData();
|
||
m_internal->m_ourTextBoxIds.clear();
|
||
m_internal->m_ourTextBoxIds.reserve(ptbdCont.size());
|
||
for (const SituationMap::PixelTextBoxData &ptbd : qAsConst(ptbdCont))
|
||
{
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " -------- ptbd.toDebugString = " << ptbd.toDebugString();
|
||
|
||
if (!ptbd.isEmpty())
|
||
{
|
||
SituationMap::PBTB_ID pbtbId(parentId);
|
||
|
||
QTextEdit *newTextEdit = pixelBasedTextBoxHandler.createTextBox(pbtbId, ptbd, true);
|
||
|
||
if (newTextEdit)
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " new TextBox created: newTextEdit = " << newTextEdit
|
||
<< ", pbtbId=" << pbtbId
|
||
<< ", ptbd=" << ptbd;
|
||
else
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " createUpdateTextBox failed"
|
||
<< ", pbtbId=" << pbtbId
|
||
<< ", ptbd=" << ptbd;
|
||
|
||
// add to mgnt:
|
||
if (!m_internal->m_ourTextBoxIds.contains(pbtbId))
|
||
m_internal->m_ourTextBoxIds.append(pbtbId);
|
||
|
||
}
|
||
} // for
|
||
|
||
// add connect to open TextEditDialog:
|
||
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxDoubleClickEvent,
|
||
this, &PlanEditor::onTextEditDialogRequested, Qt::UniqueConnection);
|
||
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxGeometryChanged,
|
||
this, &PlanEditor::onTextEditGeometryChanged, Qt::UniqueConnection);
|
||
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxRemoveRequestedEvent,
|
||
this, &PlanEditor::onTextEditRemoveRequested, Qt::UniqueConnection);
|
||
}
|
||
|
||
void PlanEditor::checkFromEmptyPlan()
|
||
{
|
||
if (m_internal->m_modelTreeWidget->isEmpty())
|
||
{
|
||
#ifdef SHOW_MODAL_DIALOG_WHEN_OTHER_MODAL_DIALOG_IS_ACTIVE
|
||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
* REGG-4219:
|
||
* On Linux systemes some times a new LtsMessageDialog will appear behind an already existing other modal dialog. As
|
||
* result the user can't confirm with "Ok" and the progarm seems to hang up
|
||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Warning loading empty plan to PlanEditor."), title());
|
||
#endif
|
||
|
||
WARNING_LOG(m_internal->m_logger) << LOGFUNCTION << "Warning loading empty plan to PlanEditor.";
|
||
}
|
||
} // void PlanEditor::checkFromEmptyPlan()
|
||
|
||
|
||
void PlanEditor::setNameOfPlan(const QString & planName)
|
||
{
|
||
m_internal->m_modelTreeWidget->setNameOfPlan(planName);
|
||
} // void PlanEditor::setNameOfPlan(const QString & planName)
|
||
|
||
|
||
bool PlanEditor::setPlan(const QByteArray &xmlContent)
|
||
{
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START, xmlContent.size()" << xmlContent.size();
|
||
|
||
if (xmlContent.isEmpty())
|
||
{
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " xmlContent is Empty";
|
||
onPlanCreate();
|
||
return true;
|
||
}
|
||
|
||
if (!m_internal->m_geoModel->fromByteArray(xmlContent))
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " fromByteArray failed... -> clearModel";
|
||
m_internal->m_geoModel->clearModel();
|
||
return false;
|
||
}
|
||
initializePlan();
|
||
// not here, we are inside a Request
|
||
// checkFromEmptyPlan();
|
||
return true;
|
||
} // void PlanEditor::setPlan( const QByteArray & xmlContent )
|
||
|
||
|
||
bool PlanEditor::importPlan(const QByteArray &xmlContent)
|
||
{
|
||
bool importPlanEmpty = xmlContent.isEmpty();
|
||
bool status = true;
|
||
SituationMap::GeometryModel *importedModel = SituationMap::GeometryModelFactory::singleton()->create();
|
||
|
||
if (!importedModel)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Memory out of range"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Memory allocation failure. Can't create GeometryModel to import file";
|
||
return false;
|
||
}
|
||
|
||
if (!importPlanEmpty)
|
||
{
|
||
importedModel->cleanModel();
|
||
|
||
status = importedModel->fromByteArray(xmlContent);
|
||
if (status)
|
||
{
|
||
importPlanEmpty = importedModel->isEmpty();
|
||
|
||
if (!importPlanEmpty)
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
m_internal->m_geoModel->merge(importedModel, true, true);
|
||
m_internal->m_geoModel->endUndoBlock(tr("Import from file"));
|
||
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
|
||
m_internal->m_geoModelRenderer->render();
|
||
m_internal->m_map->getQGraphicsView()->viewport()->update();
|
||
}
|
||
}
|
||
}
|
||
delete importedModel;
|
||
|
||
if (importPlanEmpty)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Imported plan is empty."), title());
|
||
}
|
||
return status;
|
||
} // bool PlanEditor::importPlan(const QByteArray &xmlContent)
|
||
|
||
|
||
void PlanEditor::loadFromFile(const QString &filePath)
|
||
{
|
||
QFile file(filePath);
|
||
|
||
m_internal->m_geoModel->clearModel();
|
||
|
||
if (file.open(QIODevice::ReadOnly))
|
||
{
|
||
if (m_internal->m_geoModel->fromDevice(&file))
|
||
{
|
||
initializePlan();
|
||
checkFromEmptyPlan();
|
||
}
|
||
else
|
||
{
|
||
m_internal->m_geoModel->clearModel();
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Read plan from file '%1' failed").arg(filePath), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Parsing plan model data - " << filePath << " - failed.";
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Open file '%1' failed").arg(filePath), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Open file for reading plan model - " << filePath << " - failed.";
|
||
}
|
||
} // PlanEditor::loadFromFile( const QString & filePath )
|
||
|
||
|
||
void PlanEditor::saveSelectedToFile(const QString &filePath)
|
||
{
|
||
QFile file(filePath);
|
||
|
||
if (file.open(QIODevice::WriteOnly))
|
||
{
|
||
SituationMap::GeometryModel * exportModel = SituationMap::GeometryModelFactory::singleton()->clone( m_internal->m_geoModel );
|
||
|
||
Q_ASSERT(exportModel);
|
||
|
||
// ToDo
|
||
// 1. make copy from m_internal->m_geoModel
|
||
// 2. remove all node which are not selected
|
||
// 3. call cleanModel()
|
||
// 4. write to file
|
||
|
||
class MapObjectsVisitor : public SituationMap::GeometryNodeVisitor
|
||
{
|
||
QList<SituationMap::UniqueMapId> m_exportedNodes;
|
||
QList<SituationMap::GeometryModel::Node> m_removeNodeList;
|
||
QList<SituationMap::GeometryModel::Node> m_removeGroupList;
|
||
|
||
public:
|
||
|
||
MapObjectsVisitor(SituationMap::GeometryModel *geoModel, const QList<SituationMap::UniqueMapId> &exportedNodes)
|
||
: SituationMap::GeometryNodeVisitor(geoModel)
|
||
, m_exportedNodes(exportedNodes)
|
||
{
|
||
} // MapObjectsVisitor( SituationMap::GeometryModel & geoModel, const QList<SituationMap::UniqueMapId> & exportedNodes)
|
||
|
||
|
||
bool apply(SituationMap::GeometryModel *geoModel
|
||
, const SituationMap::GeometryModel::Node &node
|
||
, SituationMap::GeometryModel::PrimitiveType primitiveType) override
|
||
{
|
||
switch (primitiveType)
|
||
{
|
||
case SituationMap::GeometryModel::PrimitiveType::RootNode : break;
|
||
case SituationMap::GeometryModel::PrimitiveType::Node:
|
||
{
|
||
if (!node.hasChildNodes())
|
||
{
|
||
m_removeGroupList << node;
|
||
}
|
||
} break;
|
||
|
||
default:
|
||
{
|
||
if (geoModel->hasUserData(node))
|
||
{
|
||
bool ok = false;
|
||
SituationMap::UniqueMapId uid = geoModel->getUserData(node, &ok);
|
||
|
||
if (ok && m_exportedNodes.contains(uid))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
m_removeNodeList << node;
|
||
} break;
|
||
|
||
}
|
||
return true;
|
||
} // bool apply( SituationMap::GeometryModel*, const SituationMap::GeometryModel::Node &, SituationMap::GeometryModel::PrimitiveType
|
||
|
||
void cleanup()
|
||
{
|
||
for (const auto &node : qAsConst(m_removeNodeList))
|
||
m_geometryModel->removePrimitive(node);
|
||
|
||
for (const auto &group : qAsConst(m_removeGroupList))
|
||
m_geometryModel->deleteGroup(group);
|
||
|
||
} // void cleanup()
|
||
|
||
}; // MapObjectsVisitor
|
||
|
||
MapObjectsVisitor exportVisitor(exportModel, m_internal->m_selectionList);
|
||
|
||
exportVisitor.traverse(exportModel->getRootNode());
|
||
exportVisitor.cleanup();
|
||
|
||
exportModel->cleanModel();
|
||
|
||
file.write(exportModel->toByteArray());
|
||
file.close();
|
||
|
||
delete exportModel;
|
||
}
|
||
else ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Saving selected plan parts to file - " << filePath << " - failed.";
|
||
|
||
} // PlanEditor::saveSelectedToFile( const QString & filePath )
|
||
|
||
|
||
void PlanEditor::importFromFile(const QString &filePath)
|
||
{
|
||
QFile file(filePath);
|
||
|
||
if (file.open(QIODevice::ReadOnly))
|
||
{
|
||
const QByteArray & xmlContent = file.readAll();
|
||
if (!importPlan(xmlContent))
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Parsing plan model '%1' failed").arg(filePath), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Parsing plan model data - " << filePath << " - failed.";
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Open plan file '%1' failed").arg(filePath), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Open file for reading plan model - " << filePath << " - failed.";
|
||
}
|
||
} // PlanEditor::importFromFile( const QString & filePath )
|
||
|
||
|
||
bool PlanEditor::isSymbolModelValid() const
|
||
{
|
||
// if (m_internal->m_lookupSymbolManager->getBaseSymbolModelEsri())
|
||
// return (!m_internal->m_lookupSymbolManager->getBaseSymbolModelEsri()->isEmpty());
|
||
// return false;
|
||
return true;
|
||
}
|
||
|
||
|
||
void PlanEditor::setAllSymbolFavourites(const QString &xmlContent)
|
||
{
|
||
m_internal->m_favouritesActionManager->symbolFavourites()->contentFromString(xmlContent);
|
||
} // void PlanEditor::setAllSymbolFavourites( const QString & xmlContent )
|
||
|
||
|
||
QString PlanEditor::allSymbolFavouritesToString() const
|
||
{
|
||
return m_internal->m_favouritesActionManager->symbolFavourites()->toString();
|
||
} // QString PlanEditor::allSymbolFavouritesToString() const
|
||
|
||
|
||
SituationMap::UniqueMapId PlanEditor::getIdFromNode(const SituationMap::GeometryModel::Node &p) const
|
||
{
|
||
return m_internal->m_geoModelRenderer->getIdFromNode(p);
|
||
} // SituationMap::UniqueMapId PlanEditor::getIdFromNode(const SituationMap::GeometryModel::Node & p) const
|
||
|
||
|
||
void PlanEditor::setSelected(SituationMap::UniqueMapId uid, bool on, bool enableShowDialogTab)
|
||
{
|
||
SituationMap::AbstractMapObject *mapObj = m_internal->m_map->objectFactory().idToMapObject(uid);
|
||
if (!mapObj)
|
||
return;
|
||
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " setSelected... uid=" << uid
|
||
<< ", on=" << on
|
||
<< ", enableShowDialogTab=" << enableShowDialogTab;
|
||
|
||
mapObj->setSelected(on);
|
||
mapObj->updateView();
|
||
|
||
SituationMap::GeometryModel::Node modelPrimitive = m_internal->m_geoModelRenderer->getAssociatedNode(mapObj);
|
||
|
||
if (on)
|
||
{
|
||
if (enableShowDialogTab)
|
||
onShowDialogTab(modelPrimitive);
|
||
|
||
if (!m_internal->m_selectionList.contains(uid))
|
||
m_internal->m_selectionList.append(uid);
|
||
}
|
||
else
|
||
{
|
||
if (m_internal->m_selectionList.contains(uid))
|
||
m_internal->m_selectionList.removeOne(uid);
|
||
if (m_internal->m_selectionList.size() == 1)
|
||
{
|
||
// Can this even happen?
|
||
mapObj = m_internal->m_map->objectFactory().idToMapObject(m_internal->m_selectionList.first());
|
||
if (mapObj)
|
||
{
|
||
modelPrimitive = m_internal->m_geoModelRenderer->getAssociatedNode(mapObj);
|
||
onShowDialogTab(modelPrimitive);
|
||
}
|
||
}
|
||
if (m_internal->m_selectionList.isEmpty())
|
||
{
|
||
onHideDialogTab();
|
||
}
|
||
}
|
||
|
||
ModelTreeWidgetItem::selectItem(m_internal->m_modelTreeWidget->rootItem(), modelPrimitive, on);
|
||
|
||
} // PlanEditor::setSelected(SituationMap::UniqueMapId, bool on )
|
||
|
||
|
||
void PlanEditor::setSelected(const SituationMap::GeometryModel::Node &node, bool on, bool enableShowDialogTab)
|
||
{
|
||
setSelected(node, on, true, enableShowDialogTab);
|
||
}
|
||
|
||
|
||
void PlanEditor::setSelected(const SituationMap::GeometryModel::Node &node, bool on, bool checkParents, bool enableShowDialogTab)
|
||
{
|
||
if (!node.isValid()) return;
|
||
|
||
if (checkParents)
|
||
{
|
||
const SituationMap::GeometryModel::Node &parent = m_internal->m_geoModel->isInGroup(node);
|
||
if (parent.isValid())
|
||
setSelected(parent, on, true, enableShowDialogTab);
|
||
}
|
||
|
||
SituationMap::GeometryModel::PrimitiveType nodeType = m_internal->m_geoModel->getType(node);
|
||
|
||
if ((SituationMap::GeometryModel::PrimitiveType::Node == nodeType) || (SituationMap::GeometryModel::PrimitiveType::RootNode == nodeType))
|
||
{
|
||
const SituationMap::GeometryModel::NodeList &childNodes = m_internal->m_geoModel->getGroupPrimitives(node);
|
||
for (const SituationMap::GeometryModel::Node &childNode : childNodes)
|
||
setSelected(childNode, on, false, enableShowDialogTab);
|
||
}
|
||
else
|
||
{
|
||
bool ok = false;
|
||
SituationMap::UniqueMapId uid = m_internal->m_geoModel->getUserData(node, &ok);
|
||
|
||
if (ok)
|
||
setSelected(uid, on, enableShowDialogTab);
|
||
}
|
||
} // PlanEditor::setSelected(const SituationMap::GeometryModel::Node & node)
|
||
|
||
|
||
bool PlanEditor::isSelected(SituationMap::UniqueMapId uid)
|
||
{
|
||
return m_internal->m_selectionList.contains(uid);
|
||
} // bool PlanEditor::isSelected( SituationMap::UniqueMapId )
|
||
|
||
|
||
bool PlanEditor::isSelected(const SituationMap::GeometryModel::Node &node)
|
||
{
|
||
SituationMap::GeometryModel::PrimitiveType nodeType = m_internal->m_geoModel->getType(node);
|
||
if ((SituationMap::GeometryModel::PrimitiveType::Node == nodeType) || (SituationMap::GeometryModel::PrimitiveType::RootNode == nodeType))
|
||
{
|
||
const SituationMap::GeometryModel::NodeList &childNodes = m_internal->m_geoModel->getGroupPrimitives(node);
|
||
for (const SituationMap::GeometryModel::Node &childNode : childNodes)
|
||
{
|
||
if (isSelected(childNode)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
bool ok = false;
|
||
SituationMap::UniqueMapId uid = m_internal->m_geoModel->getUserData(node, &ok);
|
||
|
||
if (ok) return isSelected(uid);
|
||
}
|
||
return false;
|
||
} // bool PlanEditor::isSelected( const SituationMap::GeometryModel::Node & node )
|
||
|
||
|
||
void PlanEditor::addStyleAttributes(const SituationMap::GeometryModel::Node &node, bool prepareUndo, bool changedAttrOnly)
|
||
{
|
||
m_internal->m_attributeDialogManager->addStyleAttributes(node, prepareUndo, changedAttrOnly);
|
||
|
||
} // PlanEditor::addStyleAttributes( const SituationMap::GeometryModel::Node & node, bool prepareUndo )
|
||
|
||
|
||
void PlanEditor::getSymbolAttributes(const SituationMap::GeometryModel::Node &node)
|
||
{
|
||
SituationMap::GeometryModel::PrimitiveType primitiveType = m_internal->m_geoModel->getType(node);
|
||
const QList<SituationMap::GeometryModel::Attribute> &supportedStyleAttributes = m_internal->m_geoModel->supportedAttributes(primitiveType);
|
||
|
||
for (auto attr : supportedStyleAttributes)
|
||
{
|
||
QVariant attrValue = m_internal->m_geoModel->getAttribute(node, attr);
|
||
switch (attr)
|
||
{
|
||
case SituationMap::GeometryModel::Attribute::SIDC :
|
||
{
|
||
m_internal->m_symbolCurrentSidc = attrValue.toString();
|
||
// ToDo : Attribute Fenster aktualisieren
|
||
} break;
|
||
default : break;
|
||
}
|
||
}
|
||
} // PlanEditor::getSymbolAttributes( const SituationMap::GeometryModel::Node & node )
|
||
|
||
|
||
SituationMap::GeometryModel::Node PlanEditor::addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType type
|
||
, const QList<QPointF> &points
|
||
, const QList<QPair<SituationMap::GeometryModel::Attribute, QVariant>> &attributes
|
||
, int userData
|
||
, const QString &textData
|
||
, SituationMap::GeometryModel::HorizontalAlign textAlign)
|
||
{
|
||
const SituationMap::GeometryModel::Node &node = m_internal->m_geoModel->addPrimitive(type
|
||
, points
|
||
, attributes
|
||
, userData
|
||
, textData
|
||
, textAlign);
|
||
addStyleAttributes(node, false, false);
|
||
return node;
|
||
} // SituationMap::GeometryModel::Node PlanEditor::addGeoModelPrimitive(...)
|
||
|
||
|
||
void PlanEditor::removeFeature(SituationMap::UniqueMapId itemId, bool prepareUndo)
|
||
{
|
||
const SituationMap::GeometryModel::Node &node = m_internal->m_geoModel->findPrimitive(itemId);
|
||
if (!node.isValid()) return;
|
||
|
||
if (prepareUndo)
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
m_internal->m_geoModel->removePrimitive(node);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("delete single feature", TR_UNDO_TOKEN));
|
||
}
|
||
else m_internal->m_geoModel->removePrimitive(node);
|
||
|
||
} // PlanEditor::removeFeature( SituationMap::UniqueMapId id, bool prepareUndo )
|
||
|
||
|
||
void PlanEditor::updateSelectedFeature(const QString &undoToken)
|
||
{
|
||
if (m_internal->m_readStyleAttributesFromModel) return;
|
||
if (m_internal->m_selectionList.isEmpty()) return;
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
for (SituationMap::UniqueMapId uid : qAsConst(m_internal->m_selectionList))
|
||
{
|
||
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
|
||
if (modelPrimitive.isValid())
|
||
addStyleAttributes(modelPrimitive, false);
|
||
}
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(undoToken.isEmpty() ? tr("modify feature style", TR_UNDO_TOKEN) : undoToken);
|
||
|
||
emit modifyFeatureStyle(undoToken);
|
||
|
||
} // PlanEditor::updateSelectedFeature( const QString & undoToken )
|
||
|
||
|
||
void PlanEditor::abortCurrentBboxRubberband()
|
||
{
|
||
if (m_internal->m_currentBboxRubberband)
|
||
{
|
||
m_internal->m_currentBboxRubberband->deleteMySelf();
|
||
m_internal->m_currentBboxRubberband = nullptr;
|
||
}
|
||
} // void PlanEditor::abortCurrentBboxRubberband()
|
||
|
||
|
||
template<class RubberbandTransformClass> void PlanEditor::createTransformRubberband()
|
||
{
|
||
// start translate rubberband for move, scale and rotate if possible
|
||
// but first check the bounding box of selection
|
||
|
||
SituationMap::RB::RubberbandTransform *geoPlacerRB = GeometryPlacer<RubberbandTransformClass>::create(this, m_internal->m_map.data(), m_internal->m_geoModel, m_internal->m_selectionList, this);
|
||
|
||
if (geoPlacerRB)
|
||
{
|
||
// Ok, bounding box has a valid size and GeometryPlacer is valid and has a rubberband
|
||
|
||
onHideDialogTab(); // get more size on map widget for the map
|
||
|
||
m_internal->m_currentBboxRubberband = geoPlacerRB;
|
||
|
||
SituationMap::LayerParameter lp = m_internal->m_map->layerFactory().layerParameter(m_internal->m_logicalLayername);
|
||
|
||
int opacity = lp.opacity;
|
||
|
||
lp.opacity *= 0.3;
|
||
m_internal->m_map->layerFactory().setLayerParameter(m_internal->m_logicalLayername, lp);
|
||
lp.opacity = opacity;
|
||
|
||
connect(geoPlacerRB, &SituationMap::RB::Rubberband::finished, [this, lp](SituationMap::RB::RubberbandBase *)
|
||
{
|
||
onEditAttributes();
|
||
|
||
if (m_internal)
|
||
{
|
||
m_internal->m_currentBboxRubberband = nullptr;
|
||
m_internal->m_map->layerFactory().setLayerParameter(m_internal->m_logicalLayername, lp);
|
||
}
|
||
|
||
// 17.09.19, N. Thoden, (Qt 5.12.3)
|
||
// Maybe calling setFocus here is to early.
|
||
// Race condition between dialog/widget created by former onEditAttributes()
|
||
// and this setFocus():
|
||
m_internal->m_map->setFocus();
|
||
});
|
||
|
||
connect(this, &PlanEditor::modifyFeatureStyle, geoPlacerRB, [geoPlacerRB](const QString &)
|
||
{
|
||
GeometryPlacer<RubberbandTransformClass> *geoPlacer = static_cast<GeometryPlacer<RubberbandTransformClass>*>(geoPlacerRB->userData());
|
||
if (nullptr == geoPlacer) return;
|
||
geoPlacer->changeStyleAttributes();
|
||
});
|
||
}
|
||
} // template<class RubberbandTransformClass> void PlanEditor::createTransformRubberband()
|
||
|
||
|
||
void PlanEditor::onTransformRubberband()
|
||
{
|
||
createTransformRubberband<SituationMap::RB::RubberbandTransform>();
|
||
}
|
||
|
||
|
||
void PlanEditor::onTextEditDialogRequested(const SituationMap::PBTB_ID &pbtbId)
|
||
{
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << ", clickedObj = pbtbId " << pbtbId;
|
||
|
||
// reuse or create EditDialog
|
||
QWidget *parent = m_internal->m_session.topLevelWidget();
|
||
|
||
if (m_internal->m_textEditorDialog && m_internal->m_textEditorDialog->hasUnsavedChanges())
|
||
{
|
||
const LtsWidgets::Button answer =
|
||
LtsWidgets::LtsMessageDialog::askApplyDiscardCancel(m_internal->m_textEditorDialog);
|
||
switch (answer)
|
||
{
|
||
case LtsWidgets::Button::Apply:
|
||
m_internal->m_textEditorDialog->apply();
|
||
break;
|
||
case LtsWidgets::Button::Cancel:
|
||
// do not continue
|
||
return;
|
||
case LtsWidgets::Button::Discard:
|
||
if (m_internal->m_textBoxTextEdit)
|
||
m_internal->m_textBoxTextEdit->setHtml(m_internal->m_htmlTextForCancelation);
|
||
break;
|
||
default:
|
||
break;
|
||
} // switch
|
||
} // if
|
||
|
||
if (!m_internal->m_textEditorDialog)
|
||
{
|
||
m_internal->m_textEditorDialog = new LtsWidgets::LtsTextEditDialog(parent);
|
||
m_internal->m_textEditorDialog->enableBackgroundColor(true);
|
||
m_internal->m_textEditorDialog->setOnlineHelpFilename(QStringLiteral("Plan_Editor-Create_Graphics"));
|
||
|
||
m_internal->m_session.addOrReplaceWidget(m_internal->m_textEditorDialog,
|
||
QStringLiteral("PlanEditor"), // this->title()???
|
||
QStringLiteral("PixelBasedTextBoxAttributes"),
|
||
LtsWidgets::LayoutArea::eDialogTab,
|
||
true); //setClosable
|
||
}
|
||
|
||
m_internal->m_session.focusTab(m_internal->m_textEditorDialog,
|
||
LtsWidgets::LayoutArea::eDialogTab,
|
||
QStringLiteral("PlanEditor"),
|
||
QStringLiteral("PixelBasedTextBoxAttributes"));
|
||
|
||
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
|
||
|
||
//
|
||
// NOW store WHICH pbtbId and textEdit is linked to LtsTextEditDialog:
|
||
//
|
||
|
||
QTextEdit *currentTe = pixelBasedTextBoxHandler.getTextBox(pbtbId);
|
||
m_internal->m_textBoxIdInEditing = pbtbId;
|
||
m_internal->m_textBoxTextEdit = currentTe;
|
||
if (!pixelBasedTextBoxHandler.setSelected(m_internal->m_textBoxIdInEditing))
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " setSelected failed ";
|
||
|
||
// transfer current htmlText to EditDialog:
|
||
// m_internal->m_textBoxTextEdit may be null, use pixelBasedTextBoxHandler:
|
||
const SituationMap::PixelTextBoxData &data = pixelBasedTextBoxHandler.getPixelTextBoxData(pbtbId);
|
||
if (!data.isEmpty())
|
||
{
|
||
const QString ¤tText = data.m_htmlText; // m_htmlText ist updated during getPixelTextBoxData()
|
||
m_internal->m_textEditorDialog->setHtml(currentText);
|
||
m_internal->m_textEditorDialog->setInitialBackgroundColor(data.m_backgroundColor);
|
||
m_internal->m_textEditorDialog->__unchange__();
|
||
m_internal->m_htmlTextForCancelation = currentText;
|
||
}
|
||
|
||
// connections:
|
||
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::signalTextChanged,
|
||
this, &PlanEditor::onTextBoxPixelTextChanged, Qt::UniqueConnection);
|
||
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::signalBackgroundColorChanged,
|
||
this, &PlanEditor::onTextBoxPixelBackgroundColorChanged, Qt::UniqueConnection);
|
||
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::signalTextApplied,
|
||
this, &PlanEditor::onTextBoxPixelTextApplied, Qt::UniqueConnection);
|
||
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::signalDialogCanceled,
|
||
this, &PlanEditor::onTextBoxPixelCanceled, Qt::UniqueConnection);
|
||
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::destroyed,
|
||
this, &PlanEditor::onTextBoxPixelClosed, Qt::UniqueConnection);
|
||
|
||
// we use the QTextEdit::destroyed signal as signal when the pixelbased textbox is closed
|
||
connect(currentTe, &QTextEdit::destroyed,
|
||
this, [this /*, pbtbId*/] (QObject *)
|
||
{
|
||
// [GUEZE-2947] Undo,Redo fuer PixelBasedTextBoxen
|
||
delete m_internal->m_textEditorDialog;
|
||
|
||
// [GUEZE-2947] Undo,Redo fuer PixelBasedTextBoxen
|
||
// if (!m_internal->m_textEditorDialog.isNull())
|
||
// {
|
||
// if (pbtbId == m_internal->m_textBoxIdInEditing) // if it is the focused textbox we close the text editor
|
||
// {
|
||
// m_internal->m_textEditorDialog->__unchange__(); // unchange, so we close it, even if there are unsaved changes
|
||
// m_internal->m_textEditorDialog->closeRequest();
|
||
// }
|
||
// }
|
||
});
|
||
}
|
||
|
||
void PlanEditor::onTextEditGeometryChanged(const SituationMap::PBTB_ID &pbtbId)
|
||
{
|
||
// will be called by events: a) geometryChanged or b) positionChanged
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START " << pbtbId;
|
||
|
||
if (!m_internal->m_textBoxNotifyTimer)
|
||
{
|
||
m_internal->m_textBoxNotifyTimer = new QTimer(this);
|
||
m_internal->m_textBoxNotifyTimer->setSingleShot(true);
|
||
m_internal->m_textBoxNotifyTimer->setInterval(100);
|
||
connect(m_internal->m_textBoxNotifyTimer, &QTimer::timeout, this, [this] () {
|
||
writeTextBoxDataToModel();
|
||
});
|
||
}
|
||
m_internal->m_textBoxNotifyTimer->start();
|
||
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void PlanEditor::onTextEditRemoveRequested(const SituationMap::PBTB_ID &pbtbId)
|
||
{
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START " << pbtbId;
|
||
if (!pbtbId.isValid())
|
||
return;
|
||
|
||
// to ensure, that button save", save as" will save the correct data:
|
||
m_internal->m_ourTextBoxIds.removeAll(pbtbId);
|
||
|
||
QTimer::singleShot(100, this, [this, pbtbId] () {
|
||
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
|
||
if (!pixelBasedTextBoxHandler.removeTextBox(pbtbId))
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " removeTextBox failed: pbtbId=" << pbtbId;
|
||
writeTextBoxDataToModel();
|
||
});
|
||
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void PlanEditor::onMapObjectClicked(const SituationMap::Map::RefPointerMapObjectList &mapObjList)
|
||
{
|
||
if (mapObjList.isEmpty())
|
||
onHideDialogTab();
|
||
|
||
if (!m_internal->m_geoModel) return;
|
||
if (!m_internal->m_geoModelRenderer) return;
|
||
|
||
if (m_internal->m_currentBboxRubberband) return;
|
||
if (!SituationMap::RB::Rubberband::activeRubberbands(m_internal->m_map.data()).isEmpty()) return;
|
||
|
||
if (!(QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier) || QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier)))
|
||
{
|
||
if (mapObjList.isEmpty()) onClearSelection();
|
||
}
|
||
|
||
if ((SelectionMode::Picking == m_internal->m_selectionMode)
|
||
|| QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier)
|
||
|| QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
|
||
{
|
||
doPicking(mapObjList);
|
||
return;
|
||
}
|
||
|
||
if (SelectionMode::PickingAndEdit == m_internal->m_selectionMode)
|
||
{
|
||
doPicking(mapObjList);
|
||
onEditGraphicGeometry();
|
||
}
|
||
} // void PlanEditor::onMapObjectClicked( const SituationMap::Map::RefPointerMapObjectList & mapObjList, const QPoint & )
|
||
|
||
|
||
void PlanEditor::doPicking(const SituationMap::Map::RefPointerMapObjectList &mapObjList)
|
||
{
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX mapObjList.size() = " << mapObjList.size()
|
||
<< ", m_internal->m_selectionList.size() = " << m_internal->m_selectionList.size();
|
||
|
||
// Szenario:
|
||
// click an Ets symbol on the map: PlanEditor::doPicking open an EditDialog (occurance#1),
|
||
// PlanEditor::setSelected renews the same dialog (occurance#2), finally createTransformRubberband destroys the occurance#2
|
||
// Rbd::finished opens the same dialog (occurance#3), setSidc recognize an Ets symbol -> dialog will be closed....
|
||
// Reduce the construction/destruction to rblock seduce flickering, by adding bool enableShowDialogTab to setSelected.
|
||
// N. Thoden, 08/2019:
|
||
|
||
|
||
bool bAddSelection = (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier) || QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier));
|
||
|
||
// do we have to createTransformRubberband?
|
||
bool bCreateTransformRubberband =
|
||
!bAddSelection &&
|
||
(m_internal->m_selectionMode != SelectionMode::PickingAndEdit)
|
||
&& mapObjList.size() >= 1;
|
||
|
||
// Maybe:
|
||
// Do the *de*selection first:
|
||
// If we change on item to be selected now, a some kind of edit dialog will be opened.
|
||
// Unfortunately they emit a huge number of signals (e.g. SymbolModificationWidget::changed)
|
||
// If there ist still an item in the m_internal->m_selectionList, this will be infected by mistake)
|
||
// But: The selectionChanged of the ModelTreeWidgetItem is ordered be the model
|
||
// So if the selection (by clicking the ModelView) changes from a 3rd obj to the 1st,
|
||
// the selection=true will be set to the 1st AND THEN the selection=false will be set to the 3rd.
|
||
// N. Thoden, 08/2019:
|
||
|
||
for (auto mapObjPtr : mapObjList)
|
||
{
|
||
// NOTICE_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX mapObjPtr->debugInfo()... " << mapObjPtr->debugInfo() << " m_internal->m_selectionList.isEmpty() = " << m_internal->m_selectionList.isEmpty();
|
||
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModelRenderer->getAssociatedNode(mapObjPtr.get());
|
||
if (modelPrimitive.isValid())
|
||
{
|
||
// if (m_internal->m_selectionList.isEmpty())
|
||
// {
|
||
// NOTICE_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX onShowDialogTab..";
|
||
// onShowDialogTab(modelPrimitive);
|
||
// }
|
||
|
||
setSelected(modelPrimitive, true, !bCreateTransformRubberband); // enableShowDialogTab = !bCreateTransformRubberband;
|
||
}
|
||
}
|
||
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX bCreateTransformRubberband= " << bCreateTransformRubberband;
|
||
if (bCreateTransformRubberband)
|
||
createTransformRubberband<SituationMap::RB::RubberbandTransform>();
|
||
|
||
} // void PlanEditor::doPicking( const SituationMap::Map::RefPointerMapObjectList & mapObjList )
|
||
|
||
|
||
void PlanEditor::onContextMenuRequested( const SituationMap::Map::RefPointerMapObjectList&, const QPointF &viewportPosition)
|
||
{
|
||
if (m_internal->m_session.isLtsSession()) return; // context is handled by SituationMapGuiPlugin
|
||
|
||
if (nullptr == m_internal->m_map) return;
|
||
|
||
QMenu contextMenu;
|
||
QAction *selectionByArea = contextMenu.addAction(tr("Area Selection"));
|
||
QAction *scaleByArea = contextMenu.addAction(tr("Area Scale"));
|
||
|
||
QAction *selectedItem = contextMenu.exec(m_internal->m_map->mapToGlobal(viewportPosition.toPoint()));
|
||
|
||
if (selectedItem == selectionByArea)
|
||
{
|
||
if (nullptr != m_internal->m_map)
|
||
{
|
||
m_internal->m_map->pickMapObjectsArea();
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (selectedItem == scaleByArea)
|
||
{
|
||
if (nullptr != m_internal->m_map)
|
||
{
|
||
m_internal->m_map->scaleByArea();
|
||
}
|
||
return;
|
||
}
|
||
|
||
} // void PlanEditor::onContextMenuRequested( const SituationMap::Map::RefPointerMapObjectList &mapObjList, const QPointF &viewportPosition)
|
||
|
||
|
||
void PlanEditor::onViewAbout()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
QString aboutText = tr("Plan Editor application to create and modify excercise plans.");
|
||
|
||
aboutText = QStringLiteral("%1\nBuild: %2\nESRI ArcGISRuntime Release %3").arg(aboutText).arg( QLatin1String(REVISION) ).arg(QLatin1String(ACRGIS_VERSION_STR));
|
||
|
||
QMessageBox::about(m_internal->m_session.topLevelWidget(), title(), aboutText);
|
||
// ToDo: Implement me
|
||
|
||
} // PlanEditor::onViewAbout()
|
||
|
||
|
||
void PlanEditor::onViewHelp()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
if (nullptr == m_internal->m_viewHelp) return;
|
||
m_internal->m_viewHelp->show();
|
||
} // PlanEditor::onViewHelp()
|
||
|
||
void PlanEditor::onShowHelp()
|
||
{
|
||
if (m_internal->m_session.ltsSession())
|
||
{
|
||
m_internal->m_session.ltsSession()->slotShowOnlineHelp(QStringLiteral("Plan_Editor-Application"));
|
||
}
|
||
} // PlanEditor::onShowHelp()
|
||
|
||
void PlanEditor::installSaveFunction(const std::function<void()> &saveFunction)
|
||
{
|
||
m_internal->m_saveFunction = saveFunction;
|
||
} // void PlanEditor::installSaveFunction(std::function<void()> * saveFunction)
|
||
|
||
|
||
void PlanEditor::onQuit()
|
||
{
|
||
onAskSaveChanges();
|
||
emit quitPlanEditor();
|
||
} // PlanEditor::onQuit
|
||
|
||
|
||
void PlanEditor::onAskSaveChanges()
|
||
{
|
||
if (m_internal->m_geoModel->modificationCounter() < 1)
|
||
return;
|
||
|
||
if (LtsWidgets::Button::Yes == LtsWidgets::LtsMessageDialog::showMessage( topLevelWidget()
|
||
, tr("PlanEditor has unsaved changes. Do you want to save the plan?")
|
||
, title() + QStringLiteral(" : ") + tr("Save unsaved Changes")
|
||
, LtsWidgets::Behaviour::Modal
|
||
, LtsWidgets::Button::Yes | LtsWidgets::Button::No))
|
||
{
|
||
if (nullptr == m_internal->m_saveFunction)
|
||
{
|
||
onPlanSave();
|
||
|
||
if (m_internal->m_geoModel->modificationCounter() < 1)
|
||
{
|
||
const QString & msg = tr("Saving plan successfully.");
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), msg, title());
|
||
}
|
||
}
|
||
else
|
||
m_internal->m_saveFunction();
|
||
}
|
||
else
|
||
m_internal->m_geoModel->resetModificationCounter();
|
||
} // PlanEditor::onAskSaveChanges
|
||
|
||
|
||
void PlanEditor::onAskRejectChanges(bool &reject)
|
||
{
|
||
INFO_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
|
||
|
||
reject = true;
|
||
if (m_internal->m_geoModel->modificationCounter() < 1)
|
||
return;
|
||
|
||
reject = (LtsWidgets::Button::Yes == LtsWidgets::LtsMessageDialog::showMessage( topLevelWidget()
|
||
, tr("PlanEditor has unsaved changes. Do you want to discard this changes?")
|
||
, title() + QStringLiteral(" : ") + tr("Unsaved Changes")
|
||
, LtsWidgets::Behaviour::Modal
|
||
, LtsWidgets::Button::Yes | LtsWidgets::Button::No));
|
||
if (reject)
|
||
{
|
||
// discard:
|
||
m_internal->m_geoModel->resetModificationCounter();
|
||
m_internal->removeAutosaveFile();
|
||
}
|
||
return;
|
||
}
|
||
|
||
void PlanEditor::onSignalClose()
|
||
{
|
||
INFO_LOG(m_internal->m_logger) << LOGFUNCTION << " START, isSnapshot=" << m_internal->m_session.isSnapshot();
|
||
|
||
if (m_internal->m_session.isSnapshot())
|
||
{
|
||
// PlanEditorData is stored in OPERATIONAL_Layer, but SnapshotData is stored in OVERLAY_Layer
|
||
// see PlanEditor::init().
|
||
// Avoid, that the GraphicsLayer are destroyed via MapImpl::fini() _before_ the AbstractGraphicalObjects are destroyed.
|
||
// That would lead to segFault....
|
||
|
||
// cleanModel and destroy the coresponding MapObjects/GraphicalObjects:
|
||
if (m_internal->m_geoModel)
|
||
m_internal->m_geoModel->cleanModel();
|
||
}
|
||
|
||
INFO_LOG(m_internal->m_logger) << LOGFUNCTION << " END, isSnapshot=" << m_internal->m_session.isSnapshot();
|
||
}
|
||
|
||
void PlanEditor::onMetaData()
|
||
{
|
||
MetaDataDialog *dlg = new MetaDataDialog(this, m_internal->m_geoModel, m_internal->m_map.data(), m_internal->m_map);
|
||
m_internal->m_session.addWidget(dlg, title(), QLatin1String("MetaData"), LtsWidgets::LayoutArea::eDialogTab, false);
|
||
} // void PlanEditor::onMetaData()
|
||
|
||
|
||
|
||
void PlanEditor::onPlanPrint()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
QSharedPointer<QPrinter> printer(new QPrinter(QPrinter::PrinterMode::HighResolution));
|
||
QPrintDialog printDialog(printer.data(), topLevelWidget()); // choose a printer
|
||
|
||
printer->setOrientation(QPrinter::Orientation::Landscape);
|
||
|
||
if (printDialog.exec() == QDialog::Accepted)
|
||
{
|
||
QEventLoop eventLoop;
|
||
QMetaObject::Connection slotMetaObj = connect(m_internal->m_map.data()
|
||
, &SituationMap::Map::imageCompleted
|
||
, this
|
||
, [this, &printer, &eventLoop](const QUuid &, const QImage & image)
|
||
{
|
||
|
||
// now we have a nice image of our plan, next use use Qt Printer Support to send it to a printer
|
||
|
||
const QString &title = m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaDataTitle).toString();
|
||
const QString &author = m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaDataAuthor).toString();
|
||
const QString &leftFooter = author;
|
||
const QString &middleFooter = QString();
|
||
const QString &rightFooter = QDateTime::currentDateTime().toString(QStringLiteral("d.M.yyyy h:mm")); // current date and time
|
||
|
||
Q_UNUSED(title);
|
||
Q_UNUSED(author);
|
||
Q_UNUSED(leftFooter);
|
||
Q_UNUSED(middleFooter);
|
||
Q_UNUSED(rightFooter);
|
||
|
||
QTextCharFormat defaultFontFormat;
|
||
|
||
defaultFontFormat.setForeground(QBrush(QColor("black")));
|
||
defaultFontFormat.setFontPointSize(14);
|
||
|
||
QTextCharFormat largeFontFormat = defaultFontFormat;
|
||
|
||
largeFontFormat.setFontWeight(QFont::Bold);
|
||
largeFontFormat.setFontPointSize(28);
|
||
|
||
const QFont &defaultFont = defaultFontFormat.font();
|
||
int marginInt = defaultFont.pixelSize();
|
||
const QSizeF pageSize = printer->paperRect().size();
|
||
const QSizeF drawingSize = pageSize - QSizeF(2 * marginInt, 5 * marginInt) * 1.5;
|
||
QMarginsF margins;
|
||
|
||
margins.setLeft(marginInt);
|
||
margins.setTop(marginInt);
|
||
|
||
printer->setPageMargins(margins);
|
||
printer->setCreator(QStringLiteral("RDE-") + qAppName());
|
||
printer->setDocName(title);
|
||
|
||
QTextDocument document; // use a QTextDocument to add some text and place the map image
|
||
QPainter painter(printer.data()); // init painter to the choosen printer
|
||
|
||
const QUrl imageUrl(QLatin1String("PlanEditor://sitMapScreenshot.png"));
|
||
document.addResource(QTextDocument::ImageResource, imageUrl, QVariant(image));
|
||
|
||
qreal width = drawingSize.width() * 0.9;
|
||
qreal height = drawingSize.height() * 0.9;
|
||
|
||
QString html;
|
||
|
||
html += QStringLiteral("<html>\n");
|
||
html += QStringLiteral(" <br>\n");
|
||
html += QStringLiteral(" <h1 align=\"center\" style=\"font-size:48pt\" >\n");
|
||
html += title;
|
||
html += QStringLiteral(" </h1>\n");
|
||
|
||
html += QStringLiteral(" <hr width=\"%1\"> <br>\n").arg(width);
|
||
|
||
html += QStringLiteral(" <center>\n");
|
||
html += QStringLiteral(" <img src=\"%1\" width=\"%2\" height=\"%3\" />\n").arg(QStringLiteral("PlanEditor://sitMapScreenshot.png")).arg(width).arg(height);
|
||
html += QStringLiteral(" </center> <br>\n");
|
||
|
||
html += QStringLiteral(" <hr width=\"%1\">\n").arg(width);
|
||
|
||
html += QStringLiteral(" <table width=\"%1\">\n").arg(width);
|
||
html += QStringLiteral(" <tr>\n");
|
||
html += QStringLiteral(" <th align=\"left\" style=\"font-size:12pt\" >\n");
|
||
html += leftFooter;
|
||
html += QStringLiteral(" </th>\n");
|
||
html += QStringLiteral(" <th align=\"center\" style=\"font-size:12pt\" >\n");
|
||
html += middleFooter;
|
||
html += QStringLiteral(" </th>\n");
|
||
html += QStringLiteral(" <th align=\"right\" style=\"font-size:12pt\" >\n");
|
||
html += rightFooter;
|
||
html += QStringLiteral(" </th>\n");
|
||
html += QStringLiteral(" <tr>\n");
|
||
html += QStringLiteral(" </table>\n");
|
||
html += QStringLiteral("<html>\n");
|
||
|
||
document.setHtml(html);
|
||
|
||
// finally:
|
||
document.drawContents(&painter);
|
||
// #define DEBUG_MSGBOX
|
||
#ifdef DEBUG_MSGBOX
|
||
html = QStringLiteral("<html>\n");
|
||
html += QStringLiteral(" <br>\n");
|
||
html += QStringLiteral(" <h1 align=\"center\" style=\"font-size:48pt\" >\n");
|
||
html += title + tr("Jörg");
|
||
html += QStringLiteral(" </h1>\n");
|
||
|
||
html += QStringLiteral(" <hr> <br>\n");
|
||
html += QStringLiteral(" <p> Alle Kühe essen Heu Cälber mögen besseres Futter. \n");
|
||
html += QStringLiteral("Teigwaren heißen Teigwaren weil Teigwaren Teig waren.</p>\n");
|
||
|
||
static QMessageBox *box = new QMessageBox();
|
||
|
||
box->setAttribute(Qt::WA_DeleteOnClose, true);
|
||
box->setTextFormat(Qt::RichText);
|
||
box->addButton(new QPushButton(tr("close"), box), QMessageBox::AcceptRole);
|
||
box->setText(html);
|
||
box->show();
|
||
#endif
|
||
|
||
eventLoop.quit();
|
||
|
||
}); // lambda [this,&printer,&eventLoop,&slotMetaObj]( const QString & pdfFilePath )
|
||
|
||
if (m_internal->m_map->toImage().isNull())
|
||
{
|
||
disconnect(slotMetaObj);
|
||
QString msg = QObject::tr("Creating map image for printing failed");
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), msg, this->title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << msg;
|
||
return;
|
||
}
|
||
|
||
eventLoop.exec(); // wait for finish printing
|
||
disconnect(slotMetaObj);
|
||
}
|
||
} // PlanEditor::onPlanPrint
|
||
|
||
|
||
void PlanEditor::onPlanReset()
|
||
{
|
||
qDebug() << LOGFUNCTION << " START";
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
return;
|
||
m_internal->m_geoModel->clearModel();
|
||
setNameOfPlan(QString());
|
||
initializePlan();
|
||
} // PlanEditor::onPlanReset()
|
||
|
||
|
||
void PlanEditor::onPlanCreate()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
onAskSaveChanges();
|
||
onPlanReset();
|
||
onMetaData();
|
||
} // PlanEditor::onPlanCreate
|
||
|
||
|
||
static QString addPlanFileSuffix(const QString &filePath, const QString &selectedNameFilter)
|
||
{
|
||
QString defaultSuffix(QStringLiteral(".plan"));
|
||
|
||
// qCritical() << selectedNameFilter;
|
||
|
||
QStringRef suffix;
|
||
int suffixDefStart = selectedNameFilter.lastIndexOf(QLatin1Char('(')) + 1;
|
||
int suffixDefEnd = selectedNameFilter.lastIndexOf(QLatin1Char(')')) - 1;
|
||
|
||
if (suffixDefStart < suffixDefEnd)
|
||
{
|
||
const QStringRef &suffixFilter = selectedNameFilter.midRef(suffixDefStart, suffixDefEnd - suffixDefStart + 1);
|
||
const QVector<QStringRef> &suffixVector = suffixFilter.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
||
|
||
if (!suffixVector.isEmpty())
|
||
{
|
||
const QStringRef &filter = suffixVector.first();
|
||
int indexOfDot = filter.lastIndexOf(QLatin1Char('.'));
|
||
if (indexOfDot >= 0)
|
||
suffix = filter.right(filter.length() - indexOfDot);
|
||
}
|
||
}
|
||
|
||
// qCritical() << suffix;
|
||
|
||
if (suffix.isEmpty()) suffix = QStringRef(&defaultSuffix);
|
||
if ((suffix == QStringLiteral(".*")) || (filePath.endsWith(suffix))) return filePath;
|
||
|
||
return filePath + suffix;
|
||
|
||
} // static QString addPlanFileSuffix( const QString & filePath, const QString & selectedNameFilter )
|
||
|
||
|
||
void PlanEditor::onPlanLoad()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
|
||
onAskSaveChanges();
|
||
|
||
m_internal -> m_fileDialog -> setWindowTitle(tr("Plan Editor - Select File to Open"));
|
||
m_internal -> m_fileDialog -> setAcceptMode(QFileDialog::AcceptMode::AcceptOpen);
|
||
m_internal -> m_fileDialog -> setDirectory(planDefaultDirectory());
|
||
|
||
if (!m_internal->m_currentFileName.isEmpty())
|
||
m_internal -> m_fileDialog -> selectFile(m_internal->m_currentFileName);
|
||
|
||
if (m_internal->m_fileDialog->exec() == QDialog::DialogCode::Accepted)
|
||
{
|
||
const QStringList &fileList = m_internal->m_fileDialog->selectedFiles();
|
||
if (!fileList.isEmpty())
|
||
{
|
||
m_internal->m_currentFileName = fileList.first();
|
||
loadFromFile(m_internal->m_currentFileName);
|
||
|
||
QFileInfo fileInfo(m_internal->m_currentFileName);
|
||
setNameOfPlan(fileInfo.baseName());
|
||
}
|
||
}
|
||
} // PlanEditor::onPlanLoad
|
||
|
||
|
||
void PlanEditor::onPlanSave()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
return;
|
||
if (!m_internal->m_currentFileName.isEmpty())
|
||
{
|
||
QFileInfo fileInfo(m_internal->m_currentFileName);
|
||
if (fileInfo.exists())
|
||
{
|
||
saveToFile(fileInfo.absoluteFilePath());
|
||
return;
|
||
}
|
||
}
|
||
onPlanSaveAs();
|
||
} // PlanEditor::onPlanSave
|
||
|
||
|
||
void PlanEditor::onPlanSaveAs()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
return;
|
||
|
||
m_internal -> m_fileDialog -> setWindowTitle(tr("Plan Editor - Select File to Store current Plan"));
|
||
m_internal -> m_fileDialog -> setAcceptMode(QFileDialog::AcceptMode::AcceptSave);
|
||
m_internal -> m_fileDialog -> setDirectory(planDefaultDirectory());
|
||
|
||
if (!m_internal->m_currentFileName.isEmpty())
|
||
m_internal -> m_fileDialog -> selectFile(m_internal->m_currentFileName);
|
||
|
||
if (m_internal->m_fileDialog->exec() == QDialog::DialogCode::Accepted)
|
||
{
|
||
const QStringList &fileList = m_internal->m_fileDialog->selectedFiles();
|
||
if (!fileList.isEmpty())
|
||
{
|
||
m_internal->m_currentFileName = addPlanFileSuffix(fileList.first(), m_internal->m_fileDialog->selectedNameFilter());
|
||
saveToFile(m_internal->m_currentFileName);
|
||
|
||
QFileInfo fileInfo(m_internal->m_currentFileName);
|
||
setNameOfPlan(fileInfo.baseName());
|
||
|
||
m_internal->removeAutosaveFile();
|
||
}
|
||
}
|
||
} // PlanEditor::onPlanSaveAs
|
||
|
||
|
||
void PlanEditor::onPlanSaveSelected()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
|
||
m_internal -> m_fileDialog -> setWindowTitle(tr("Plan Editor - Select File to Store Selected Plan Items"));
|
||
m_internal -> m_fileDialog -> setAcceptMode(QFileDialog::AcceptMode::AcceptSave);
|
||
m_internal -> m_fileDialog -> setDirectory(planDefaultDirectory());
|
||
|
||
m_internal -> m_fileDialog -> selectFile(QString());
|
||
|
||
if (m_internal->m_fileDialog->exec() == QDialog::DialogCode::Accepted)
|
||
{
|
||
const QStringList &fileList = m_internal->m_fileDialog->selectedFiles();
|
||
if (!fileList.isEmpty())
|
||
{
|
||
m_internal->m_currentFileName = addPlanFileSuffix(fileList.first(), m_internal->m_fileDialog->selectedNameFilter());
|
||
saveSelectedToFile(m_internal->m_currentFileName);
|
||
}
|
||
}
|
||
} // PlanEditor::onPlanSaveSelected
|
||
|
||
|
||
void PlanEditor::onPlanAutoSave()
|
||
{
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
if (m_internal->m_geoModel->modificationCounter() < 1) return; // no modifications since last save
|
||
|
||
const QString &crt = QStringLiteral("/tmp/plan_") + QString::number(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
|
||
QFile file(crt);
|
||
if (file.open(QIODevice::WriteOnly))
|
||
file.write(m_internal->m_geoModel->toByteArray());
|
||
} // PlanEditor::onPlanAutoSave
|
||
|
||
void PlanEditor::onPlanImport()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
|
||
m_internal -> m_fileDialog -> setWindowTitle(tr("Plan Editor - Select File to Import"));
|
||
m_internal -> m_fileDialog -> setAcceptMode(QFileDialog::AcceptMode::AcceptOpen);
|
||
m_internal -> m_fileDialog -> setDirectory(planDefaultDirectory());
|
||
|
||
if (!m_internal->m_currentFileName.isEmpty())
|
||
m_internal -> m_fileDialog -> selectFile(m_internal->m_currentFileName);
|
||
|
||
if (m_internal->m_fileDialog->exec() == QDialog::DialogCode::Accepted)
|
||
{
|
||
const QStringList &fileList = m_internal->m_fileDialog->selectedFiles();
|
||
if (!fileList.isEmpty())
|
||
{
|
||
const QString & fileName = addPlanFileSuffix(fileList.first(), m_internal->m_fileDialog->selectedNameFilter());
|
||
importFromFile(fileName);
|
||
}
|
||
}
|
||
} // PlanEditor::onPlanImport
|
||
|
||
|
||
void PlanEditor::onCenterViewSelected()
|
||
{
|
||
const qreal eps = 0.00000000001;
|
||
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (m_internal->m_selectionList.isEmpty()) return;
|
||
|
||
qreal viewAreaMinX = std::numeric_limits<qreal>::max();
|
||
qreal viewAreaMinY = std::numeric_limits<qreal>::max();
|
||
qreal viewAreaMaxX = -std::numeric_limits<qreal>::max();
|
||
qreal viewAreaMaxY = -std::numeric_limits<qreal>::max();
|
||
|
||
for (SituationMap::UniqueMapId uid : qAsConst(m_internal->m_selectionList))
|
||
{
|
||
SituationMap::AbstractMapObject *mapObj = m_internal->m_map->objectFactory().idToMapObject(uid);
|
||
if (!mapObj) continue;
|
||
|
||
SituationMap::BoundingBox objBbox;
|
||
|
||
mapObj->boundingBox(objBbox);
|
||
|
||
switch (objBbox.extentType())
|
||
{
|
||
case SituationMap::BoundingBox::ExtentType::Sim :
|
||
{
|
||
const SituationMap::PositionCont &bboxVerticies = objBbox.positions();
|
||
for (const SituationMap::Point3D &v : bboxVerticies)
|
||
{
|
||
if (viewAreaMinX > v.x()) viewAreaMinX = v.x();
|
||
if (viewAreaMinY > v.y()) viewAreaMinY = v.y();
|
||
if (viewAreaMaxX < v.x()) viewAreaMaxX = v.x();
|
||
if (viewAreaMaxY < v.y()) viewAreaMaxY = v.y();
|
||
}
|
||
} break;
|
||
|
||
case SituationMap::BoundingBox::ExtentType::Pixel :
|
||
{
|
||
const SituationMap::Point3D &v = objBbox.center();
|
||
|
||
if (viewAreaMinX > v.x()) viewAreaMinX = v.x();
|
||
if (viewAreaMinY > v.y()) viewAreaMinY = v.y();
|
||
if (viewAreaMaxX < v.x()) viewAreaMaxX = v.x();
|
||
if (viewAreaMaxY < v.y()) viewAreaMaxY = v.y();
|
||
|
||
} break;
|
||
|
||
default : break;
|
||
}
|
||
} // for
|
||
|
||
if (viewAreaMinX < std::numeric_limits<qreal>::max())
|
||
{
|
||
// ViewAreaMin and viewAreaMax are defined, we can setup the view now
|
||
|
||
// add 10 % extra space
|
||
|
||
qreal dx = (viewAreaMaxX - viewAreaMinX) * 0.5;
|
||
qreal dy = (viewAreaMaxY - viewAreaMinY) * 0.5;
|
||
qreal cx = viewAreaMinX + dx;
|
||
qreal cy = viewAreaMinY + dy;
|
||
dx *= 1.05;
|
||
dy *= 1.05;
|
||
|
||
// setup values
|
||
|
||
if ((fabs(dx) < eps) || (fabs(dy) < eps))
|
||
{
|
||
QRectF extent = m_internal->m_map->extent();
|
||
|
||
dx = extent.width() * 0.5;
|
||
dy = extent.height() * 0.5;
|
||
}
|
||
|
||
viewAreaMinX = cx - dx;
|
||
viewAreaMinY = cy - dy;
|
||
viewAreaMaxX = cx + dx;
|
||
viewAreaMaxY = cy + dy;
|
||
|
||
m_internal->m_map->setExtent(viewAreaMinX, viewAreaMinY, viewAreaMaxX, viewAreaMaxY);
|
||
}
|
||
|
||
} // PlanEditor::onCenterViewSelected()
|
||
|
||
|
||
void PlanEditor::onClearSelection()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
const auto selList = m_internal->m_selectionList; // setSelected modifes m_selectionList
|
||
for (SituationMap::UniqueMapId uid : selList)
|
||
setSelected(uid, false);
|
||
m_internal->m_selectionList.clear();
|
||
ModelTreeWidgetItem::clearSelection(m_internal->m_modelTreeWidget->rootItem());
|
||
onHideDialogTab();
|
||
} // PlanEditor::onClearSelection()
|
||
|
||
|
||
void PlanEditor::onRubberbandAbort(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (rubberband != nullptr)
|
||
{
|
||
if (!m_internal->m_rbBackupNodeCoordinates.isEmpty())
|
||
{
|
||
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)rubberband->userData();
|
||
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
m_internal->m_geoModel->setPrimitivePoints(node, m_internal->m_rbBackupNodeCoordinates);
|
||
}
|
||
if (!rubberband->autoDelete()) rubberband->deleteMySelf();
|
||
}
|
||
m_internal->m_rbBackupNodeCoordinates.clear();
|
||
// ToDo: Status-Zeile
|
||
} // PlanEditor::onRubberbandAbort(SituationMap::RB::RubberbandBase * rubberband)
|
||
|
||
|
||
class DropCreateSymbol : public LtsWidgets::LtsDropHandler
|
||
{
|
||
PlanEditor *m_planEditor;
|
||
PlanEditor::InternalData *m_planEditorInternal;
|
||
QString m_sidc;
|
||
mutable bool m_createParticipant;
|
||
|
||
public:
|
||
|
||
DropCreateSymbol(PlanEditor *planEditor, PlanEditor::InternalData *planEditorInternal, const QString &sidc, bool createParticipant = false )
|
||
: LtsWidgets::LtsDropHandler()
|
||
, m_planEditor(planEditor)
|
||
, m_planEditorInternal(planEditorInternal)
|
||
, m_sidc(sidc)
|
||
, m_createParticipant(createParticipant) {;}
|
||
|
||
virtual ~DropCreateSymbol() = default;
|
||
|
||
void doDrop(int x, int y, const QMimeData * mimeData) const override
|
||
{
|
||
m_planEditor->onClearSelection();
|
||
|
||
if (nullptr == m_planEditorInternal) return;
|
||
if (nullptr == m_planEditorInternal->m_geoModel) return;
|
||
|
||
const AdvancedSymbology::SymbolDictionary &symbolDict = m_planEditorInternal->m_map->symbolDictionary();
|
||
const QString &baseCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(m_sidc);
|
||
const AdvancedSymbology::SymbolProperties &symbolProps = symbolDict.symbolProperties(baseCode);
|
||
|
||
|
||
if ((nullptr != mimeData) && mimeData->hasFormat(QStringLiteral("Participant")))
|
||
{
|
||
const QByteArray & participantInfo = mimeData->data(QStringLiteral("Participant"));
|
||
m_createParticipant = m_createParticipant || (participantInfo.toInt() > 0);
|
||
}
|
||
|
||
if (symbolProps.key() == AdvancedSymbology::SidcCodec::decodeRawSidc(baseCode))
|
||
{
|
||
m_planEditorInternal->m_symbolCurrentSidc = m_sidc;
|
||
|
||
SituationMap::RB::Rubberband *rubberband = m_planEditorInternal->m_map->rubberbandFactory().createSymbol(m_sidc, QPoint(x, y), m_planEditorInternal);
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
SituationMap::RB::RubberbandPointFeature *pointFeatureRB = dynamic_cast<SituationMap::RB::RubberbandPointFeature *>(rubberband);
|
||
|
||
if ((pointFeatureRB) && (pointFeatureRB->getMaximumPointCount() < 2))
|
||
{
|
||
// It is a point feature to start a rubberband makes no sense here because the coordinate is already
|
||
// known. We can use the coordinate of drop event to place the symbol.
|
||
|
||
QVector<QPointF> pointList;
|
||
pointList += m_planEditorInternal->m_map->viewPortWindowPointToMapCoordinate(QPointF(x, y));
|
||
|
||
pointFeatureRB->setCoordinateVector(pointList, SituationMap::RB::CoordinateSystem::Map);
|
||
|
||
m_planEditor->onSymbolCreate(rubberband,m_createParticipant);
|
||
|
||
pointFeatureRB -> deleteMySelf(); // bye bye rubberband
|
||
return;
|
||
}
|
||
|
||
m_planEditorInternal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> setPreviewSize(ICON_SIZE);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, [this](SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
m_planEditor->onSymbolCreate(rubberband, m_createParticipant);
|
||
});
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
QString msg = QObject::tr("Creating rubberband failed, may be wrong sidc (%1)").arg(m_planEditorInternal->m_symbolCurrentSidc);
|
||
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), msg, m_planEditor->title());
|
||
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << msg;
|
||
}
|
||
}
|
||
} // doDrop(int x, int y, const QMimeData * mimeData)
|
||
|
||
}; // DropCreateSymbol
|
||
|
||
|
||
qulonglong PlanEditor::createSymbolDropEvent(const QString &sidc)
|
||
{
|
||
bool createParticipant = false;
|
||
|
||
if (m_internal->m_lookupSymbolManager)
|
||
{
|
||
// createParticipant = m_internal->m_lookupSymbolManager->getBaseSymbolModel()->isParticipant(sidc);
|
||
createParticipant = m_internal->m_lookupSymbolManager->isParticipantDialog();
|
||
}
|
||
return m_internal->m_dropEventManager->add(new DropCreateSymbol(this, m_internal.get(), sidc, createParticipant));
|
||
} // int PlanEditor::createSymbolDropEvent(const QString & sidc)
|
||
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onSymbolCreateRubberband(const QString ¤tSidc, bool createParticipant )
|
||
{
|
||
// AdvancedSymbology::Gui::BaseSymbolModel *symbolModel = m_internal->m_lookupSymbolManager->getBaseSymbolModel();
|
||
// bool bCreateParticipant = createParticipant && (m_internal->m_lookupSymbolManager) && (m_internal->m_lookupSymbolManager->isParticipant(currentSidc));
|
||
|
||
bool bCreateParticipant = createParticipant && (m_internal->m_lookupSymbolManager) && (m_internal->m_lookupSymbolManager->isParticipantDialog());
|
||
|
||
onClearSelection();
|
||
|
||
const AdvancedSymbology::SymbolDictionary &symbolDict = m_internal->m_map->symbolDictionary();
|
||
const QString &baseKey = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(currentSidc);
|
||
const AdvancedSymbology::SymbolProperties &symbolProps = symbolDict.symbolProperties(baseKey);
|
||
|
||
if (symbolProps.key() == AdvancedSymbology::SidcCodec::decodeRawSidc(baseKey))
|
||
{
|
||
m_internal->m_symbolCurrentSidc = currentSidc;
|
||
|
||
SituationMap::RB::Rubberband *rubberband = m_internal->m_map->rubberbandFactory().createSymbol(currentSidc, m_internal.get());
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> setPreviewSize(ICON_SIZE);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, bCreateParticipant](SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
onSymbolCreate(rubberband, bCreateParticipant);
|
||
});
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband failed, may be wrong sidc (" << m_internal->m_symbolCurrentSidc << ")";
|
||
}
|
||
return rubberband;
|
||
}
|
||
|
||
return nullptr;
|
||
} // PlanEditor::onSymbolCreateRubberband()
|
||
|
||
|
||
void PlanEditor::onChooseSymbol()
|
||
{
|
||
onClearSelection();
|
||
if (m_internal->m_symbolDictLoaded) m_internal->m_lookupSymbolManager->onOpenSymbolDialog();
|
||
}; // PlanEditor::onChooseSymbol()
|
||
|
||
|
||
|
||
void PlanEditor::onSymbolCreate(SituationMap::RB::RubberbandBase *rubberband, bool createParticipant)
|
||
{
|
||
SituationMap::RB::Rubberband *rbnd = dynamic_cast<SituationMap::RB::Rubberband*>(rubberband);
|
||
|
||
if (nullptr == m_internal->m_geoModel) return;
|
||
if (nullptr == rbnd) return;
|
||
|
||
SituationMap::RB::RubberbandRectangle *rbRectangle = dynamic_cast<SituationMap::RB::RubberbandRectangle * >(rbnd);
|
||
SituationMap::RB::RubberbandEllipse *rbEllipse = dynamic_cast<SituationMap::RB::RubberbandEllipse * >(rbnd);
|
||
SituationMap::RB::RubberbandCorridor *rbCorridor = dynamic_cast<SituationMap::RB::RubberbandCorridor * >(rbnd);
|
||
bool isAttributedSymbol = (rbRectangle || rbEllipse || rbCorridor);
|
||
|
||
const QString &sidc = rbnd->getPreviewSidc();
|
||
|
||
QList<QPointF> points;
|
||
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
|
||
QString sidcAttributes;
|
||
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)rbnd->userData();
|
||
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
if (isAttributedSymbol)
|
||
{
|
||
if (rbRectangle && (nullptr == rbEllipse))
|
||
{
|
||
QPointF center;
|
||
qreal length;
|
||
qreal width;
|
||
QPointF dir;
|
||
|
||
rbRectangle->rectangleParameter(center, length, width, dir);
|
||
|
||
#ifdef SPEC_MIL2525D_RELATED
|
||
points += center;
|
||
#else
|
||
points = rbRectangle->coordinateVector().toList();
|
||
#endif
|
||
|
||
QMap<QString, QVariant> attrMap;
|
||
attrMap[QStringLiteral("length")] = length;
|
||
attrMap[QStringLiteral("width")] = width;
|
||
attrMap[QStringLiteral("attitude")] = SituationMap::MathUtils::getAngleDegreeNorth(QPointF(0, 0), dir);
|
||
|
||
sidcAttributes = m_internal->m_geoModel->buildSymbolAttributeString(attrMap);
|
||
}
|
||
|
||
if (rbEllipse)
|
||
{
|
||
QPointF center;
|
||
qreal diameter;
|
||
qreal d2;
|
||
QPointF dir;
|
||
|
||
rbEllipse->rectangleParameter(center, diameter, d2, dir);
|
||
points += center;
|
||
|
||
QMap<QString, QVariant> attrMap;
|
||
attrMap[QStringLiteral("radius")] = diameter * 0.5;
|
||
sidcAttributes = m_internal->m_geoModel->buildSymbolAttributeString(attrMap);
|
||
}
|
||
|
||
if (rbCorridor)
|
||
{
|
||
qreal corridorWidth = rbCorridor->corridorWidth() * 0.5;
|
||
const auto coords = rbCorridor->centerLine();
|
||
points.reserve(coords.size());
|
||
for (const QPointF &coord : coords)
|
||
points += coord;
|
||
QMap<QString, QVariant> attrMap;
|
||
attrMap[QStringLiteral("width")] = corridorWidth;
|
||
sidcAttributes = m_internal->m_geoModel->buildSymbolAttributeString(attrMap);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
const auto coords = rubberband->coordinateVector();
|
||
points.reserve(coords.size());
|
||
for (const QPointF &coord : coords)
|
||
points += coord;
|
||
}
|
||
|
||
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating symbol sidc='" << sidc << "'; Attributes='" << sidcAttributes << "'";
|
||
|
||
if (!node.isValid())
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
if (!sidcAttributes.isEmpty())
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::SIDC_Attributes, sidcAttributes);
|
||
|
||
SituationMap::GeometryModel::PrimitiveType symbolType = SituationMap::GeometryModel::PrimitiveType::Symbol;
|
||
|
||
if (AdvancedSymbology::SidcCodec::SidcType::CivilXml != AdvancedSymbology::SidcCodec::decodeSidcType(sidc))
|
||
{
|
||
symbolType = createParticipant
|
||
? SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol : SituationMap::GeometryModel::PrimitiveType::DictionarySymbol;
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::SIDC, sidc);
|
||
}
|
||
else
|
||
{
|
||
const QString &symbolId = AdvancedSymbology::SidcCodec::decodeRawSidc(sidc);
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::SymbolId, symbolId );
|
||
}
|
||
|
||
|
||
node = addGeoModelPrimitive(symbolType, points, attributes);
|
||
addStyleAttributes(node, false);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("create symbol", TR_UNDO_TOKEN));
|
||
onUpdateView();
|
||
setSelected(node);
|
||
}
|
||
else
|
||
{
|
||
if (!m_internal->m_rbBackupNodeCoordinates.isEmpty())
|
||
{
|
||
// restore last coordinate before rubberband was running
|
||
m_internal->m_geoModel->setPrimitivePoints(node, m_internal->m_rbBackupNodeCoordinates);
|
||
}
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
addStyleAttributes(node, false);
|
||
m_internal->m_geoModel->setPrimitiveAttribute(node, SituationMap::GeometryModel::Attribute::SIDC, sidc);
|
||
if (!sidcAttributes.isEmpty())
|
||
m_internal->m_geoModel->setPrimitiveAttribute(node, SituationMap::GeometryModel::Attribute::SIDC_Attributes, sidcAttributes);
|
||
m_internal->m_geoModel->setPrimitivePoints(node, points);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("modifiy symbol geometry", TR_UNDO_TOKEN));
|
||
}
|
||
m_internal->m_rbBackupNodeCoordinates.clear();
|
||
} // PlanEditor::onSymbolCreate( SituationMap::RB::RubberbandBase * rubberband )
|
||
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onLineCreateRubberband()
|
||
{
|
||
onClearSelection();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband failed! May there is another active rubberband";
|
||
return nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_internal.get());
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableClosed(false);
|
||
rubberband -> maximumPointCount(2);
|
||
rubberband -> enableFinishAfterConstruction(true);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onLineCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
return rubberband;
|
||
} // PlanEditor::onLineCreateRubberband()
|
||
|
||
|
||
void DropCreateLine::doDrop(int x, int y, const QMimeData *) const
|
||
{
|
||
m_planEditor->onClearSelection();
|
||
|
||
if (nullptr == m_planEditorInternal) return;
|
||
if (nullptr == m_planEditorInternal->m_geoModel) return;
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_planEditorInternal);
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_planEditorInternal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableClosed(false);
|
||
rubberband -> maximumPointCount(2);
|
||
|
||
double dx = m_planEditorInternal->m_map->width() * 0.25;
|
||
double dy = m_planEditorInternal->m_map->height() * 0.25;
|
||
|
||
QVector<QPointF> lineCoordinates;
|
||
|
||
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y - dy));
|
||
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y + dy));
|
||
|
||
rubberband->setCoordinateVector(lineCoordinates);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, &PlanEditor::onLineCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), QObject::tr("Creating rubberband failed! May there is another active rubberband"), m_planEditor->title());
|
||
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
} // DropCreateLine::doDrop( int x, int y ) const
|
||
|
||
|
||
void PlanEditor::onLineCreate(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
if (rubberband == nullptr) return;
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *lineRubberband = dynamic_cast<SituationMap::RB::RubberbandMultiPointFeature *>(rubberband);
|
||
|
||
if (lineRubberband)
|
||
{
|
||
QList<QPointF> points;
|
||
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
|
||
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)lineRubberband->userData();
|
||
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
const auto coords = lineRubberband->coordinateVector();
|
||
points.reserve(coords.size());
|
||
for (const QPointF &coord : coords)
|
||
points += coord;
|
||
|
||
if (!node.isValid())
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Line, points, attributes); // addStyleAttributes will be done in addGeoModelPrimitives
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("create line", TR_UNDO_TOKEN));
|
||
onUpdateView();
|
||
setSelected(node);
|
||
}
|
||
else
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
m_internal->m_geoModel->setPrimitivePoints(node, points);
|
||
addStyleAttributes(node, false);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("modifiy line geometry", TR_UNDO_TOKEN));
|
||
}
|
||
}
|
||
} // PlanEditor::onLineCreate( SituationMap::RB::RubberbandBase * rubberband )
|
||
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onPolylineCreateRubberband()
|
||
{
|
||
onClearSelection();
|
||
|
||
if (nullptr == m_internal->m_geoModel)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
|
||
return nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_internal.get());
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableClosed(false);
|
||
rubberband -> minimumPointCount(3);
|
||
rubberband -> enableFinishAfterConstruction(true);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onPolylineCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
return rubberband;
|
||
} // PlanEditor::onPolylineCreateRubberband()
|
||
|
||
|
||
void DropCreatePolyLine::doDrop(int x, int y, const QMimeData *) const
|
||
{
|
||
m_planEditor->onClearSelection();
|
||
|
||
if (nullptr == m_planEditorInternal) return;
|
||
if (nullptr == m_planEditorInternal->m_geoModel) return;
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband;
|
||
|
||
if (m_smooth) rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandSmoothLine>(m_planEditorInternal);
|
||
else rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_planEditorInternal);
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_planEditorInternal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableClosed(false);
|
||
|
||
double dx = m_planEditorInternal->m_map->width() * 0.25;
|
||
double dy = m_planEditorInternal->m_map->height() * 0.25;
|
||
|
||
QVector<QPointF> lineCoordinates;
|
||
|
||
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y - dy));
|
||
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y + dy));
|
||
|
||
rubberband->setCoordinateVector(lineCoordinates);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, &PlanEditor::onPolylineCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), QObject::tr("Creating rubberband failed! May there is another active rubberband"), m_planEditor->title());
|
||
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
} // DropCreatePolyLine::doDrop( int x, int y ) const
|
||
|
||
|
||
void PlanEditor::onPolylineCreate(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
if (rubberband == nullptr) return;
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *lineRubberband = dynamic_cast<SituationMap::RB::RubberbandMultiPointFeature *>(rubberband);
|
||
SituationMap::RB::RubberbandSmoothLine *smoothLine = dynamic_cast<SituationMap::RB::RubberbandSmoothLine *>(rubberband);
|
||
|
||
if (lineRubberband)
|
||
{
|
||
QList<QPointF> points;
|
||
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
|
||
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)lineRubberband->userData();
|
||
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
const auto coords = lineRubberband->coordinateVector();
|
||
points.reserve(coords.size());
|
||
for (const QPointF &coord : coords)
|
||
points += coord;
|
||
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Close, QVariant(false));
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Fill, QVariant(false));
|
||
|
||
if (!node.isValid())
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
if (smoothLine) node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Spline, points, attributes); // addStyleAttributes will be done in addGeoModelPrimitives
|
||
else node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Polyline, points, attributes);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock((smoothLine) ? tr("create new smooth line", TR_UNDO_TOKEN) : tr("create new polyline", TR_UNDO_TOKEN));
|
||
onUpdateView();
|
||
setSelected(node);
|
||
}
|
||
else
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
m_internal->m_geoModel->setPrimitivePoints(node, points);
|
||
addStyleAttributes(node, false);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("modifiy polyline geometry", TR_UNDO_TOKEN));
|
||
}
|
||
}
|
||
} // PlanEditor::onPolylineCreate( SituationMap::RB::RubberbandBase * rubberband )
|
||
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onSmoothLineCreateRubberband()
|
||
{
|
||
onClearSelection();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
|
||
return nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandSmoothLine>(m_internal.get());
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableClosed(false);
|
||
rubberband -> minimumPointCount(3);
|
||
rubberband -> enableFinishAfterConstruction(true);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onPolylineCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
|
||
return rubberband;
|
||
} // PlanEditor::onSmoothLineCreateRubberband()
|
||
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onPolygonCreateRubberband()
|
||
{
|
||
onClearSelection();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
|
||
return nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_internal.get());
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableClosed(true);
|
||
rubberband -> enableFinishAfterConstruction(true);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onPolygonCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
|
||
return rubberband;
|
||
} // PlanEditor::onPolygonCreateRubberband()
|
||
|
||
|
||
void DropCreatePolygon::doDrop(int x, int y, const QMimeData *) const
|
||
{
|
||
m_planEditor->onClearSelection();
|
||
|
||
if (nullptr == m_planEditorInternal) return;
|
||
if (nullptr == m_planEditorInternal->m_geoModel) return;
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband;
|
||
|
||
if (m_smooth) rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandSmoothLine>(m_planEditorInternal);
|
||
else rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_planEditorInternal);
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_planEditorInternal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableClosed(true);
|
||
|
||
double dx = m_planEditorInternal->m_map->width() * 0.25;
|
||
double dy = m_planEditorInternal->m_map->height() * 0.25;
|
||
|
||
QVector<QPointF> lineCoordinates;
|
||
|
||
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y - dy));
|
||
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y));
|
||
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y + dy));
|
||
|
||
rubberband->setCoordinateVector(lineCoordinates);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, &PlanEditor::onPolygonCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), QObject::tr("Creating rubberband failed! May there is another active rubberband"), m_planEditor->title());
|
||
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
|
||
} // DropCreatePolygon::doDrop( int x, int y ) const
|
||
|
||
|
||
void PlanEditor::onPolygonCreate(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
if (rubberband == nullptr) return;
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *lineRubberband = dynamic_cast<SituationMap::RB::RubberbandMultiPointFeature *>(rubberband);
|
||
SituationMap::RB::RubberbandSmoothLine *smoothLine = dynamic_cast<SituationMap::RB::RubberbandSmoothLine *>(rubberband);
|
||
|
||
if (lineRubberband)
|
||
{
|
||
QList<QPointF> points;
|
||
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
|
||
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)lineRubberband->userData();
|
||
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
const auto coords = lineRubberband->coordinateVector();
|
||
points.reserve(coords.size());
|
||
for (const QPointF &coord : coords)
|
||
points += coord;
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Close, QVariant(true));
|
||
|
||
// ToDo: fill attributes
|
||
|
||
if (!node.isValid())
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
if (smoothLine) node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Spline, points, attributes); // addStyleAttributes will be done in addGeoModelPrimitives
|
||
else node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Polyline, points, attributes);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("create polygon", TR_UNDO_TOKEN));
|
||
onUpdateView();
|
||
setSelected(node);
|
||
}
|
||
else
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
m_internal->m_geoModel->setPrimitivePoints(node, points);
|
||
addStyleAttributes(node, false);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("modify polygon geoemtry", TR_UNDO_TOKEN));
|
||
}
|
||
}
|
||
|
||
} // PlanEditor::onPolygonCreate( SituationMap::RB::RubberbandBase * rubberband )
|
||
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onRectangleCreateRubberband()
|
||
{
|
||
onClearSelection();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
|
||
return nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandRectangle *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandRectangle>(m_internal.get());
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onRectangleCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for rectangles failed.";
|
||
}
|
||
|
||
return rubberband;
|
||
} // PlanEditor::onRectangleCreateRubberband()
|
||
|
||
|
||
void DropCreateRectangle::doDrop(int x, int y, const QMimeData *) const
|
||
{
|
||
m_planEditor->onClearSelection();
|
||
|
||
if (nullptr == m_planEditorInternal) return;
|
||
if (nullptr == m_planEditorInternal->m_geoModel) return;
|
||
|
||
SituationMap::RB::RubberbandRectangle *rubberband;
|
||
|
||
if (m_ellipse) rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandEllipse>(m_planEditorInternal);
|
||
else rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandRectangle>(m_planEditorInternal);
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_planEditorInternal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
|
||
double dx = m_planEditorInternal->m_map->width() * 0.4;
|
||
double dy = m_planEditorInternal->m_map->height() * 0.25;
|
||
|
||
QVector<QPointF> coordinates;
|
||
|
||
coordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y - dy));
|
||
coordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y - dy));
|
||
coordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y + dy));
|
||
coordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y + dy));
|
||
|
||
rubberband->setCoordinateVector(coordinates);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, &PlanEditor::onRectangleCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), QObject::tr("Creating rubberband failed! May there is another active rubberband"), m_planEditor->title());
|
||
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << "Creating rubberband for rectangles failed.";
|
||
}
|
||
|
||
} // DropCreateRectangle::doDrop( int x, int y ) const
|
||
|
||
|
||
void PlanEditor::onRectangleCreate(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
if (rubberband == nullptr) return;
|
||
|
||
SituationMap::RB::RubberbandRectangle *rband = dynamic_cast<SituationMap::RB::RubberbandRectangle *>(rubberband);
|
||
SituationMap::RB::RubberbandEllipse *relli = dynamic_cast<SituationMap::RB::RubberbandEllipse *>(rubberband);
|
||
|
||
if (rband)
|
||
{
|
||
const QList<QPointF> &points = rband->coordinateVector().toList();
|
||
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
|
||
QPointF rectCenter;
|
||
QPointF rectOrientation;
|
||
qreal rectWidth;
|
||
qreal rectHeight;
|
||
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)rband->userData();
|
||
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
rband->rectangleParameter(rectCenter, rectWidth, rectHeight, rectOrientation, SituationMap::RB::CoordinateSystem::Geo);
|
||
|
||
qreal cosPhi = rectOrientation.x();
|
||
qreal phi = acos(cosPhi) * 180.0 / MathConst::pi;
|
||
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Center, QVariant(rectCenter));
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Width, QVariant(rectWidth));
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Height, QVariant(rectHeight));
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Rotate, QVariant(phi));
|
||
|
||
if (relli)
|
||
{
|
||
if (relli->hasSector())
|
||
{
|
||
auto getAngle = [](qreal sinPhi, qreal cosPhi) -> qreal
|
||
{
|
||
qreal phi = acos(cosPhi);
|
||
if (sinPhi < 0) phi = MathConst::pi_two - phi;
|
||
return (phi * 180.0 / MathConst::pi);
|
||
}; // getAngle
|
||
|
||
QPointF sectorStartVec = relli->sectorStart();
|
||
QPointF sectorEndVec = relli->sectorEnd();
|
||
|
||
qreal sectorStart = getAngle(sectorStartVec.y(), sectorStartVec.x());
|
||
qreal sectorEnd = getAngle(sectorEndVec.y(), sectorEndVec.x());
|
||
qreal sectorExtent = sectorEnd - sectorStart;
|
||
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Start, QVariant(sectorStart));
|
||
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Extent, QVariant(sectorExtent));
|
||
}
|
||
else attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Extent, QVariant(360));
|
||
}
|
||
|
||
if (!node.isValid())
|
||
{
|
||
const char *undoToken = (relli) ? "create ellipse" : "create rectangle";
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
if (relli) node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Ellipse, points, attributes); // addStyleAttributes will be done in addGeoModelPrimitives
|
||
else node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Rectangle, points, attributes);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr(undoToken, TR_UNDO_TOKEN));
|
||
onUpdateView();
|
||
setSelected(node);
|
||
}
|
||
else
|
||
{
|
||
const char *undoToken = (relli) ? "modify ellipse geometry" : "modify rectangle geoemtry";
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
m_internal->m_geoModel->setPrimitivePoints(node, points);
|
||
|
||
for (const auto &attrPair : qAsConst(attributes))
|
||
m_internal->m_geoModel->setPrimitiveAttribute(node, attrPair.first, attrPair.second);
|
||
addStyleAttributes(node, false);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr(undoToken, TR_UNDO_TOKEN));
|
||
}
|
||
}
|
||
|
||
} // PlanEditor::onRectangleCreate( SituationMap::RB::RubberbandBase * rubberband )
|
||
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onEllipseCreateRubberband()
|
||
{
|
||
onClearSelection();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
|
||
return nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandEllipse *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandEllipse>(m_internal.get());
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableSector();
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onRectangleCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for rectangles failed.";
|
||
}
|
||
|
||
return rubberband;
|
||
} // PlanEditor::onEllipseCreateRubberband()
|
||
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onTextLineCreateRubberband()
|
||
{
|
||
onClearSelection();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
|
||
return nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandPointFeature>(m_internal.get());
|
||
|
||
if (rubberband != nullptr)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableFinishAfterConstruction(true);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onTextLineCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
|
||
return rubberband;
|
||
}
|
||
|
||
SituationMap::RB::Rubberband *PlanEditor::onTextBoxPixelCreateRubberband()
|
||
{
|
||
onClearSelection();
|
||
|
||
if (m_internal->m_geoModel == nullptr)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
|
||
return nullptr;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandPointFeature>(m_internal.get());
|
||
|
||
if (rubberband)
|
||
{
|
||
m_internal->m_session.hideAnimated();
|
||
|
||
rubberband -> setAutoDelete(true);
|
||
rubberband -> enableFinishAfterConstruction(true);
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onTextBoxPixelCreate);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
|
||
}
|
||
else
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
|
||
}
|
||
|
||
return rubberband;
|
||
}
|
||
|
||
|
||
SituationMap::GeometryModel::Node PlanEditor::buildTextNode(const QPointF &loc)
|
||
{
|
||
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
|
||
QList<QPointF> points;
|
||
SituationMap::GeometryModel::Node node;
|
||
|
||
points += loc;
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Text
|
||
, points
|
||
, attributes
|
||
, SituationMap::IdHandler::BadId
|
||
, m_internal->m_attributeDialogManager->textLines());
|
||
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("create text", TR_UNDO_TOKEN));
|
||
return node;
|
||
} // PlanEditor::buildTextNode( const QPointF & loc )
|
||
|
||
void PlanEditor::buildTextBoxPixelNode(const QPointF &locPixel)
|
||
{
|
||
// // m_internal->m_geoModel->startUndoBlock();
|
||
|
||
// // cleanup 'current'...
|
||
// m_internal->resetCurrentTextBox();
|
||
|
||
//
|
||
// get in touch with TextBox at QGraphicsScene:
|
||
//
|
||
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
|
||
SituationMap::PBTB_ID pbtbId(PLAN_EDITOR_TEXTBOX_PARENT_ID);
|
||
SituationMap::PixelTextBoxData ptbd;
|
||
ptbd.m_position = locPixel.toPoint();
|
||
|
||
QTextEdit *newTextEdit = pixelBasedTextBoxHandler.createTextBox(pbtbId, ptbd, true);
|
||
|
||
//
|
||
// !! pbtbId maybe updated by createUpdateTextBox !!
|
||
//
|
||
|
||
INFO_LOG(m_internal->m_logger) << " new TextBox created: newTextEdit = " << newTextEdit
|
||
<< ", pbtbId=" << pbtbId
|
||
<< ", ptbd=" << ptbd;
|
||
|
||
// add to mgnt:
|
||
if (!m_internal->m_ourTextBoxIds.contains(pbtbId))
|
||
m_internal->m_ourTextBoxIds.append(pbtbId);
|
||
|
||
// connect slot to open TextEditDialog:
|
||
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxDoubleClickEvent,
|
||
this, &PlanEditor::onTextEditDialogRequested, Qt::UniqueConnection);
|
||
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxGeometryChanged,
|
||
this, &PlanEditor::onTextEditGeometryChanged, Qt::UniqueConnection);
|
||
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxRemoveRequestedEvent,
|
||
this, &PlanEditor::onTextEditRemoveRequested, Qt::UniqueConnection);
|
||
|
||
//
|
||
// reuse or create EditDialog
|
||
//
|
||
onTextEditDialogRequested(pbtbId);
|
||
|
||
// // m_internal->m_geoModel->endUndoBlock(tr("create textBoxPixel", TR_UNDO_TOKEN));
|
||
}
|
||
|
||
void PlanEditor::writeTextBoxDataToModel()
|
||
{
|
||
INFO_LOG(m_internal->m_logger) << LOGFUNCTION << " START"
|
||
<< ", m_internal->m_textBoxIds.size = " << m_internal->m_ourTextBoxIds.size();
|
||
|
||
QVector<SituationMap::PixelTextBoxData> ptbdVec;
|
||
ptbdVec.reserve(m_internal->m_ourTextBoxIds.size());
|
||
|
||
// Read text, bgColor, pos, size from SitMap (pixelBasedTextBoxHandler):
|
||
|
||
const SituationMap::PBTB_ID pbtbIdAsParent(PLAN_EDITOR_TEXTBOX_PARENT_ID);
|
||
const SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
|
||
const QVector<SituationMap::PBTB_ID> pbtbIdVec = pixelBasedTextBoxHandler.getAllIdsOfParent(pbtbIdAsParent);
|
||
|
||
for (const SituationMap::PBTB_ID &pbtbId : qAsConst(pbtbIdVec))
|
||
{
|
||
const SituationMap::PixelTextBoxData &data = pixelBasedTextBoxHandler.getPixelTextBoxData(pbtbId);
|
||
if (data.isEmpty())
|
||
continue;
|
||
ptbdVec.append(data);
|
||
} // for
|
||
|
||
// convert to Json (Container):
|
||
const QString &str = SituationMap::PixelTextBoxData::pixelTextBoxContainerToJsonStr(ptbdVec, QJsonDocument::JsonFormat::Compact);
|
||
|
||
// to model
|
||
m_internal->m_geoModel->setModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes, str);
|
||
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void DropCreateTextLine::doDrop(int x, int y, const QMimeData *) const
|
||
{
|
||
m_planEditor->onClearSelection();
|
||
|
||
if (nullptr == m_planEditorInternal) return;
|
||
if (nullptr == m_planEditorInternal->m_geoModel) return;
|
||
|
||
const QPointF loc = m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x, y));
|
||
const SituationMap::GeometryModel::Node node = m_planEditor->buildTextNode(loc);
|
||
m_planEditor->onUpdateView();
|
||
m_planEditor->setSelected(node);
|
||
|
||
} // DropCreateTextLine::doDrop(int x, int y, const QMimeData*) const
|
||
|
||
|
||
void PlanEditor::onTextLineCreate(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (m_internal->m_geoModel == nullptr) return;
|
||
if (rubberband == nullptr) return;
|
||
|
||
SituationMap::RB::RubberbandPointFeature *pointRubberband = dynamic_cast<SituationMap::RB::RubberbandPointFeature *>(rubberband);
|
||
|
||
if (pointRubberband)
|
||
{
|
||
const QPointF &loc = pointRubberband->singleCoordinate();
|
||
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)pointRubberband->userData();
|
||
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
if (!node.isValid())
|
||
{
|
||
node = buildTextNode(loc);
|
||
onUpdateView();
|
||
setSelected(node);
|
||
}
|
||
else
|
||
{
|
||
// restore last coordinate before rubberband was running
|
||
m_internal->m_geoModel->setPrimitivePoints(node, m_internal->m_rbBackupNodeCoordinates);
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
m_internal->m_geoModel->setPrimitivePoints(node, QList<QPointF>() << loc);
|
||
addStyleAttributes(node, false);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("modifiy text position", TR_UNDO_TOKEN));
|
||
}
|
||
}
|
||
|
||
m_internal->m_rbBackupNodeCoordinates.clear();
|
||
}
|
||
|
||
void PlanEditor::onTextBoxPixelCreate(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
if (!m_internal->m_geoModel || !rubberband)
|
||
return;
|
||
|
||
SituationMap::RB::RubberbandPointFeature *pointRubberband = dynamic_cast<SituationMap::RB::RubberbandPointFeature *>(rubberband);
|
||
|
||
if (!pointRubberband)
|
||
return;
|
||
|
||
const QVector<QPointF> &coordsRef = pointRubberband->coordinateVectorPixel();
|
||
const QPointF &locPixel = coordsRef.first();
|
||
|
||
// create TextEdit and it´s dialog:
|
||
buildTextBoxPixelNode(locPixel);
|
||
}
|
||
|
||
void PlanEditor::onTextBoxPixelTextChanged(const QString &htmlText)
|
||
{
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
|
||
if (!m_internal->m_map)
|
||
return;
|
||
|
||
// slight change -> no UndoBlock
|
||
|
||
const SituationMap::PBTB_ID currentPbtbId = m_internal->m_textBoxIdInEditing;
|
||
if (!currentPbtbId.isValid())
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_internal->m_textBoxIdInEditing invalid: " << currentPbtbId.toString();
|
||
return;
|
||
}
|
||
|
||
if (!m_internal->m_ourTextBoxIds.contains(currentPbtbId))
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_internal->m_textBoxIds does not have currentPbtbId = " << currentPbtbId;
|
||
return;
|
||
}
|
||
|
||
if (!m_internal->m_textBoxTextEdit)
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_textBoxTextEdit invalid: " << m_internal->m_textBoxTextEdit;
|
||
return;
|
||
}
|
||
|
||
// Update gui:
|
||
m_internal->m_textBoxTextEdit->setHtml(htmlText);
|
||
|
||
// to ensure, that button "save" and "save as" will save the correct data:
|
||
// [GUEZE-2947] Undo,Redo fuer PixelBasedTextBoxen
|
||
// on apply: // writeTextBoxDataToModel();
|
||
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void PlanEditor::onTextBoxPixelBackgroundColorChanged(const QColor &backgroundColor)
|
||
{
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START, backgroundColor= " << backgroundColor;
|
||
|
||
if (!backgroundColor.isValid())
|
||
return;
|
||
|
||
const SituationMap::PBTB_ID currentPbtbId = m_internal->m_textBoxIdInEditing;
|
||
if (!currentPbtbId.isValid())
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_internal->m_textBoxIdInEditing invalid: " << currentPbtbId.toString();
|
||
return;
|
||
}
|
||
|
||
if (!m_internal->m_ourTextBoxIds.contains(currentPbtbId))
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_internal->m_textBoxIds does not have currentPbtbId = " << currentPbtbId;
|
||
return;
|
||
}
|
||
|
||
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
|
||
SituationMap::PixelTextBoxData data = pixelBasedTextBoxHandler.getPixelTextBoxData(currentPbtbId);
|
||
if (data.isEmpty())
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_textBoxTextEdit invalid: " << m_internal->m_textBoxTextEdit;
|
||
return;
|
||
}
|
||
|
||
// Update gui:
|
||
data.m_backgroundColor = backgroundColor;
|
||
pixelBasedTextBoxHandler.updateTextBox(currentPbtbId, data);
|
||
|
||
// to ensure, that button save", save as" will save the correct data:
|
||
writeTextBoxDataToModel();
|
||
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END, backgroundColor= " << backgroundColor;
|
||
}
|
||
|
||
void PlanEditor::onTextBoxPixelTextApplied(const QString &htmlText)
|
||
{
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
|
||
|
||
// // m_internal->m_geoModel->startUndoBlock();
|
||
|
||
m_internal->m_htmlTextForCancelation = htmlText; // update
|
||
writeTextBoxDataToModel();
|
||
|
||
// // m_internal->m_geoModel->endUndoBlock(tr("update textBoxes", TR_UNDO_TOKEN));
|
||
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
|
||
void PlanEditor::onTextBoxPixelCanceled()
|
||
{
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
|
||
|
||
if (!m_internal->m_textBoxTextEdit)
|
||
{
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_textBoxTextEdit invalid: " << m_internal->m_textBoxTextEdit;
|
||
return;
|
||
}
|
||
|
||
// restore saved text:
|
||
m_internal->m_textBoxTextEdit->setHtml(m_internal->m_htmlTextForCancelation);
|
||
writeTextBoxDataToModel();
|
||
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void PlanEditor::onTextBoxPixelClosed()
|
||
{
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
|
||
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
|
||
pixelBasedTextBoxHandler.removeSelection();
|
||
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void PlanEditor::onTransformMove(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
SituationMap::RB::RubberbandTransformMove *rMove = dynamic_cast<SituationMap::RB::RubberbandTransformMove *>(rubberband);
|
||
|
||
if (rMove == nullptr) return;
|
||
|
||
QList<SituationMap::UniqueMapId> *featureToTransform = static_cast<QList<SituationMap::UniqueMapId>*>(rMove->userData());
|
||
|
||
// Nothing to do here because all work has been done in preview
|
||
|
||
rMove->setUserData(nullptr);
|
||
delete featureToTransform;
|
||
|
||
m_internal->m_geoModel->endUndoBlock(tr("move feature(s)", TR_UNDO_TOKEN));
|
||
|
||
} // PlanEditor::onTransformMove( SituationMap::RB::RubberbandBase * rubberband )
|
||
|
||
|
||
void PlanEditor::onTransformRotate(SituationMap::RB::RubberbandBase *rubberband)
|
||
{
|
||
SituationMap::RB::RubberbandTransformRotate *rRotate = dynamic_cast<SituationMap::RB::RubberbandTransformRotate *>(rubberband);
|
||
|
||
if (rRotate == nullptr) return;
|
||
|
||
// const QPointF & rCenter = rRotate -> centerPoint();
|
||
// qreal deltaAngle = rRotate -> getRelativeRotation();
|
||
|
||
for (auto uid : qAsConst(m_internal->m_selectionList))
|
||
{
|
||
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
|
||
if (modelPrimitive.isValid())
|
||
{
|
||
QList<QPointF> vertexList = m_internal->m_geoModel->getPrimitivePoints(modelPrimitive);
|
||
|
||
m_internal->m_geoModel->setPrimitivePoints(modelPrimitive, vertexList);
|
||
}
|
||
}
|
||
} // PlanEditor::onTransformRotate( SituationMap::RB::RubberbandBase * rubberband )
|
||
|
||
|
||
void PlanEditor::onTransformScale(SituationMap::RB::RubberbandBase * /*rubberband*/)
|
||
{
|
||
} // PlanEditor::onTransformScale( SituationMap::RB::RubberbandBase * rubberband )
|
||
|
||
|
||
void PlanEditor::onEditAttributes()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (!m_internal -> m_selectionList.isEmpty())
|
||
{
|
||
SituationMap::UniqueMapId uid = m_internal -> m_selectionList.first();
|
||
const SituationMap::GeometryModel::Node &node = m_internal -> m_geoModelRenderer -> getAssociatedNode(m_internal->m_map->objectFactory().idToMapObject(uid));
|
||
|
||
onShowDialogTab(node);
|
||
}
|
||
else
|
||
onShowDialogTab(SituationMap::GeometryModel::Node());
|
||
|
||
} // PlanEditor::onEditAttributes()
|
||
|
||
|
||
void PlanEditor::onEditGraphicGeometry()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (1 != m_internal->m_selectionList.size()) return;
|
||
|
||
SituationMap::UniqueMapId uid = m_internal -> m_selectionList.first();
|
||
SituationMap::AbstractMapObject *mapObj = m_internal -> m_map->objectFactory().idToMapObject(uid);
|
||
const SituationMap::GeometryModel::Node &node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
if (!node.isValid()) return;
|
||
|
||
SituationMap::GeometryModel::PrimitiveType primitiveType = m_internal->m_geoModel->getType(node);
|
||
SituationMap::RB::Rubberband *rubberband = nullptr;
|
||
|
||
auto previewGeometrySinglePointMove = [this](SituationMap::RB::RubberbandBase * rb) -> bool
|
||
{
|
||
if (!rb) return true;
|
||
|
||
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)rb->userData();
|
||
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
|
||
|
||
m_internal->m_geoModel->setPrimitivePoints(node, QList<QPointF>() << rb->singleCoordinate());
|
||
return true;
|
||
};
|
||
|
||
switch (primitiveType)
|
||
{
|
||
case SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol:
|
||
case SituationMap::GeometryModel::PrimitiveType::DictionarySymbol :
|
||
{
|
||
const QString &sidc = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::SIDC).toString();
|
||
rubberband = onSymbolCreateRubberband(sidc, (SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol== primitiveType) );
|
||
|
||
const QList<QPointF> &pointList = m_internal->m_geoModel->getPrimitivePoints(node);
|
||
|
||
if (pointList.size() == 1)
|
||
{
|
||
m_internal->m_rbBackupNodeCoordinates = pointList;
|
||
rubberband->installExternalUpdate(previewGeometrySinglePointMove);
|
||
}
|
||
} break;
|
||
|
||
case SituationMap::GeometryModel::PrimitiveType::Ellipse : rubberband = onEllipseCreateRubberband(); break;
|
||
case SituationMap::GeometryModel::PrimitiveType::Line : rubberband = onLineCreateRubberband(); break;
|
||
case SituationMap::GeometryModel::PrimitiveType::Polyline :
|
||
{
|
||
bool closed = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Close).toBool();
|
||
if (closed) rubberband = onPolygonCreateRubberband();
|
||
else rubberband = onPolylineCreateRubberband();
|
||
} break;
|
||
|
||
case SituationMap::GeometryModel::PrimitiveType::Rectangle : rubberband = onRectangleCreateRubberband(); break;
|
||
case SituationMap::GeometryModel::PrimitiveType::Spline : rubberband = onSmoothLineCreateRubberband(); break;
|
||
case SituationMap::GeometryModel::PrimitiveType::Symbol : break;
|
||
|
||
case SituationMap::GeometryModel::PrimitiveType::Text :
|
||
{
|
||
const QList<QPointF> &pointList = m_internal->m_geoModel->getPrimitivePoints(node);
|
||
|
||
if (pointList.size() == 1)
|
||
{
|
||
m_internal->m_rbBackupNodeCoordinates = pointList;
|
||
|
||
rubberband = onTextLineCreateRubberband();
|
||
|
||
rubberband->installExternalUpdate(previewGeometrySinglePointMove);
|
||
}
|
||
} break;
|
||
|
||
default : break;
|
||
}
|
||
|
||
if (rubberband == nullptr) return;
|
||
|
||
QList<QPointF> &&coordinateList = m_internal->m_geoModel->getPrimitivePoints(node);
|
||
|
||
if (coordinateList.empty())
|
||
{
|
||
rubberband -> deleteMySelf();
|
||
return;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandRectangle *rRectRubber = dynamic_cast<SituationMap::RB::RubberbandRectangle *>(rubberband);
|
||
|
||
/* --------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
* Now coordinates are always in geographic coordinate system and not longer in map coordinate system. The geometry model stores now the 4 verticies of
|
||
* the rectangle, which are used now directly in rubberband. Keep in mind that the map coordinate sytem has to be the same as for the first input.
|
||
* --------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
if (rRectRubber != nullptr)
|
||
{
|
||
QPointF rectCenter = coordinateList.first();
|
||
qreal rectWidth2 = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Width ).toDouble() * 0.5;
|
||
qreal rectHeight2 = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Height).toDouble() * 0.5;
|
||
qreal rectPhi = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Rotate).toDouble() * MathConst::pi / 180.0;
|
||
qreal cosPhi = cos(rectPhi);
|
||
qreal sinPhi = sin(rectPhi);
|
||
|
||
SituationMap::CoordTranslationFunctor * ctf = m_internal->m_map->coordTranslationFunctor();
|
||
|
||
if (ctf)
|
||
{
|
||
rectCenter = ctf->geographicToMap( rectCenter );
|
||
}
|
||
|
||
auto rotate = [cosPhi,sinPhi]( qreal x, qreal y ) -> QPointF
|
||
{
|
||
return QPointF( x*cosPhi - y*sinPhi, y*cosPhi + x*sinPhi );
|
||
}; // lamda rotate
|
||
|
||
coordinateList.clear();
|
||
|
||
coordinateList += rotate( -rectWidth2, -rectHeight2 ) + rectCenter;
|
||
coordinateList += rotate( +rectWidth2, -rectHeight2 ) + rectCenter;
|
||
coordinateList += rotate( +rectWidth2, +rectHeight2 ) + rectCenter;
|
||
coordinateList += rotate( -rectWidth2, +rectHeight2 ) + rectCenter;
|
||
}
|
||
* ------------------------------------------------------------------------------------------------------------------------------------------------------------ */
|
||
|
||
rubberband -> setCoordinateVector(coordinateList.toVector());
|
||
rubberband -> setUserData(mapObj);
|
||
|
||
if ((rRectRubber != nullptr) && (!rRectRubber->rectangleIsValid()))
|
||
{
|
||
rubberband->deleteMySelf();
|
||
|
||
QString msg = tr("Map coordinate system differs from simulation coordinate system. Display of rectangles, ellipses ... will be wrong!");
|
||
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), msg, title());
|
||
|
||
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << msg ;
|
||
}
|
||
|
||
SituationMap::RB::RubberbandEllipse *relli = dynamic_cast<SituationMap::RB::RubberbandEllipse *>(rubberband);
|
||
|
||
if (relli)
|
||
{
|
||
double start = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Start).toDouble();
|
||
double extend = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Extent).toDouble();
|
||
bool hasSector = (extend) < 360.0;
|
||
|
||
relli->enableSector();
|
||
|
||
if (hasSector)
|
||
{
|
||
double startAngle = start * MathConst::pi / 180.0;
|
||
double endAngle = (start + extend) * MathConst::pi / 180.0;
|
||
|
||
relli->setSectorStart(sin(startAngle), cos(startAngle));
|
||
relli->setSectorEnd(sin(endAngle), cos(endAngle));
|
||
}
|
||
else
|
||
{
|
||
relli->setSectorStart(0.0, 1.0);
|
||
relli->setSectorEnd(0.0, 1.0);
|
||
}
|
||
}
|
||
} // PlanEditor::onEditGraphicGeometry()
|
||
|
||
|
||
|
||
void PlanEditor::onMoveGraphicGeometry()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (m_internal->m_selectionList.isEmpty()) return;
|
||
|
||
createTransformRubberband<SituationMap::RB::RubberbandTransformMove>();
|
||
|
||
} // PlanEditor::onMoveGraphicGeometry()
|
||
|
||
|
||
void PlanEditor::onRotateGraphicGeometry()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (m_internal->m_selectionList.isEmpty()) return;
|
||
|
||
createTransformRubberband<SituationMap::RB::RubberbandTransformRotate>();
|
||
|
||
} // PlanEditor::onRotateGraphicGeometry()
|
||
|
||
|
||
void PlanEditor::onScaleGraphicGeometry()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
if (m_internal->m_selectionList.isEmpty()) return;
|
||
|
||
createTransformRubberband<SituationMap::RB::RubberbandTransformScale>();
|
||
|
||
} // PlanEditor::onScaleGraphicGeometry()
|
||
|
||
|
||
void PlanEditor::onDelete()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
for (auto uid : qAsConst(m_internal->m_selectionList))
|
||
removeFeature(uid, false);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("delete feature(s)", TR_UNDO_TOKEN));
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
|
||
} // onDelete()
|
||
|
||
|
||
void PlanEditor::onGroup()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
SituationMap::GeometryModel::NodeList nodeList;
|
||
SituationMap::GeometryModel::Node nodeToSelect;
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
for (auto uid : qAsConst(m_internal->m_selectionList))
|
||
{
|
||
SituationMap::GeometryModel::Node node = m_internal->m_geoModel->findPrimitive(uid);
|
||
|
||
if (!nodeToSelect.isValid()) nodeToSelect = node;
|
||
for (;;)
|
||
{
|
||
// go up to toplevel group node
|
||
const SituationMap::GeometryModel::Node &group = m_internal->m_geoModel->isInGroup(node);
|
||
if (!group.isValid()) break;
|
||
node = group;
|
||
}
|
||
|
||
if (!nodeList.contains(node)) nodeList += node;
|
||
}
|
||
|
||
m_internal->m_geoModel->createGroup(nodeList);
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("group", TR_UNDO_TOKEN));
|
||
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
|
||
|
||
onClearSelection();
|
||
setSelected(nodeToSelect, true, true, true);
|
||
|
||
} // PlanEditor::onGroup()
|
||
|
||
|
||
void PlanEditor::getChildNodes(const SituationMap::GeometryModel::Node &node, SituationMap::GeometryModel::NodeList &childNodes)
|
||
{
|
||
const auto nodeList = m_internal->m_geoModel->getGroupPrimitives(node);
|
||
for (const auto &subNode : nodeList)
|
||
{
|
||
if (SituationMap::GeometryModel::PrimitiveType::Node != m_internal->m_geoModel->getType(subNode))
|
||
childNodes << subNode;
|
||
else getChildNodes(subNode, childNodes);
|
||
}
|
||
} // void PlanEditor::getChildNodes(const SituationMap::GeometryModel::Node & node, SituationMap::GeometryModel::NodeList & childNodes )
|
||
|
||
|
||
void PlanEditor::onUngroup()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
SituationMap::GeometryModel::NodeList nodeList;
|
||
SituationMap::GeometryModel::NodeList selectedNodes;
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
for (auto uid : qAsConst(m_internal->m_selectionList))
|
||
{
|
||
SituationMap::GeometryModel::Node node = m_internal->m_geoModel->findPrimitive(uid);
|
||
|
||
for (;;)
|
||
{
|
||
const SituationMap::GeometryModel::Node &group = m_internal->m_geoModel->isInGroup(node);
|
||
if (!group.isValid()) break;
|
||
node = group;
|
||
}
|
||
|
||
if (!nodeList.contains(node)) nodeList += node;
|
||
}
|
||
|
||
for (const auto &node : qAsConst(nodeList))
|
||
{
|
||
getChildNodes(node, selectedNodes);
|
||
m_internal->m_geoModel->releaseGroup(node);
|
||
}
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("ungroup", TR_UNDO_TOKEN));
|
||
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
|
||
onUpdateView();
|
||
|
||
onClearSelection();
|
||
for (const auto &node : qAsConst(selectedNodes))
|
||
setSelected(node, true);
|
||
|
||
} // PlanEditor::onUngroup()
|
||
|
||
|
||
void PlanEditor::onRedo()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
// Maybe a pixelBasedTextbox is involved
|
||
if (m_internal->m_textBoxTextEdit)
|
||
delete m_internal->m_textEditorDialog;
|
||
|
||
m_internal->m_geoModel->redo();
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
|
||
} // PlanEditor::onRedo()
|
||
|
||
|
||
void PlanEditor::onUndo()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
// Maybe a pixelBasedTextbox is involved
|
||
if (m_internal->m_textBoxTextEdit)
|
||
delete m_internal->m_textEditorDialog;
|
||
|
||
m_internal->m_geoModel->undo();
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
|
||
} // PlanEditor::onUndo()
|
||
|
||
|
||
void PlanEditor::onUndoHistory()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
showHistory(m_internal -> m_dlgUndoHistory
|
||
, m_internal -> m_lwUndoHistory
|
||
, tr("Undo History")
|
||
, m_internal->m_geoModel->undoHistory());
|
||
|
||
if (m_internal -> m_lwUndoHistory)
|
||
{
|
||
m_internal -> m_lwUndoHistory -> headerItem() ->setText(0, tr("Undo Step"));
|
||
connect(m_internal -> m_lwUndoHistory, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem * undoItem)
|
||
{
|
||
if (undoItem)
|
||
{
|
||
bool ok = false;
|
||
unsigned int undoCount = undoItem->data(0, Qt::UserRole).toUInt(&ok);
|
||
|
||
if ((ok) && (undoCount > 0))
|
||
m_internal->m_geoModel->undo(undoCount);
|
||
}
|
||
m_internal -> m_dlgUndoHistory -> hide();
|
||
});
|
||
}
|
||
else ERROR_LOG(m_internal->m_logger) << "Undefined pointer in Undo History Dialog, can't show dialog.";
|
||
} // void PlanEditor::onUndoHistory()
|
||
|
||
|
||
|
||
void PlanEditor::onRedoHistory()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
showHistory(m_internal -> m_dlgRedoHistory
|
||
, m_internal -> m_lwRedoHistory
|
||
, tr("Redo History")
|
||
, m_internal->m_geoModel->redoHistory());
|
||
|
||
if (m_internal -> m_lwRedoHistory)
|
||
{
|
||
m_internal -> m_lwRedoHistory -> headerItem() ->setText(0, tr("Redo Step"));
|
||
connect(m_internal -> m_lwRedoHistory, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem * redoItem)
|
||
{
|
||
if (redoItem)
|
||
{
|
||
bool ok = false;
|
||
unsigned int redoCount = redoItem->data(0, Qt::UserRole).toUInt(&ok);
|
||
|
||
if ((ok) && (redoCount > 0))
|
||
m_internal->m_geoModel->undo(redoCount);
|
||
}
|
||
m_internal -> m_lwRedoHistory -> hide();
|
||
});
|
||
}
|
||
else ERROR_LOG(m_internal->m_logger) << "Undefined pointer in Redo History Dialog, can't show dialog.";
|
||
} // void PlanEditor::onRedoHistory()
|
||
|
||
void PlanEditor::showHistory(QPointer<LtsWidgets::LtsFramelessDialog> &dlgHistory
|
||
, QTreeWidget *&lwHistory
|
||
, const QString &title
|
||
, const QStringList &history)
|
||
{
|
||
if (nullptr == dlgHistory)
|
||
{
|
||
dlgHistory = new LtsWidgets::LtsFramelessDialog(m_internal -> m_gbPlanEditorMain, LtsWidgets::Behaviour::Popup);
|
||
|
||
QVBoxLayout *layout = new QVBoxLayout(dlgHistory);
|
||
lwHistory = new QTreeWidget(dlgHistory);
|
||
|
||
lwHistory -> setAlternatingRowColors(true);
|
||
lwHistory -> setColumnCount(2);
|
||
lwHistory -> headerItem() ->setText(1, QString());
|
||
|
||
lwHistory -> headerItem() ->setTextAlignment(0, Qt::AlignmentFlag::AlignLeft);
|
||
lwHistory -> headerItem() ->setTextAlignment(1, Qt::AlignmentFlag::AlignRight);
|
||
|
||
layout -> addWidget(new QLabel(title, dlgHistory), 0);
|
||
layout -> addWidget(lwHistory, 2);
|
||
|
||
connect(m_internal -> m_lwUndoHistory, &QObject::destroyed, this, [this](QObject *) { m_internal->m_lwUndoHistory = nullptr; });
|
||
}
|
||
|
||
if (nullptr != lwHistory)
|
||
{
|
||
lwHistory -> clear();
|
||
|
||
unsigned int tokenCount = (unsigned int) history.size();
|
||
for (const QString &token : history)
|
||
{
|
||
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << token << QString::number(tokenCount));
|
||
|
||
item->setData(0, Qt::UserRole, QVariant(tokenCount));
|
||
|
||
lwHistory -> insertTopLevelItem(0, item);
|
||
|
||
--tokenCount;
|
||
}
|
||
lwHistory->resizeColumnToContents(0);
|
||
lwHistory->resizeColumnToContents(1);
|
||
|
||
dlgHistory -> show();
|
||
}
|
||
} // PlanEditor::showHistory( ... )
|
||
|
||
|
||
void PlanEditor::onCopy()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
m_internal->m_nodeClipboard.clear();
|
||
m_internal->m_modelClipboard->clearModel();
|
||
|
||
QVector<SituationMap::GeometryModel::Node> nodesAddedClipboard;
|
||
|
||
for (SituationMap::UniqueMapId uid : qAsConst(m_internal->m_selectionList))
|
||
{
|
||
SituationMap::GeometryModel::Node node = m_internal->m_geoModel->findPrimitive(uid);
|
||
|
||
while (!node.parentNode().isRootNode())
|
||
{
|
||
if (!node.isValid()) break;
|
||
node = node.parentNode();
|
||
}
|
||
|
||
if (node.isValid())
|
||
{
|
||
if (!nodesAddedClipboard.contains(node))
|
||
{
|
||
nodesAddedClipboard.append(node);
|
||
const SituationMap::GeometryModel::Node ©Clipboard = m_internal->m_modelClipboard->copy(node);
|
||
m_internal->m_nodeClipboard.append(copyClipboard);
|
||
}
|
||
}
|
||
}
|
||
} // PlanEditor::onCopy()
|
||
|
||
|
||
void PlanEditor::onCut()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
onCopy();
|
||
onDelete();
|
||
} // PlanEditor::onCut()
|
||
|
||
|
||
void PlanEditor::onPaste()
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
if (!m_internal->m_nodeClipboard.isEmpty())
|
||
{
|
||
for (int i = 0; i < m_internal->m_nodeClipboard.size(); ++i)
|
||
{
|
||
// Insert copy of Node
|
||
const SituationMap::GeometryModel::Node &clipboardNode = m_internal->m_nodeClipboard.at(i);
|
||
const SituationMap::GeometryModel::Node ©Node = m_internal->m_geoModel->copy(clipboardNode);
|
||
|
||
// Move Node some Pixels, to make insertion visible
|
||
double pixelSize = m_internal->m_map->pixelSizeGeographic();
|
||
double dx = pixelSize * PasteDistance;
|
||
double dy = -dx;
|
||
|
||
m_internal -> m_geoModel -> translateNode( copyNode , dx, dy );
|
||
m_internal -> m_modelClipboard -> translateNode( clipboardNode, dx, dy );
|
||
}
|
||
}
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("paste", TR_UNDO_TOKEN));
|
||
|
||
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
|
||
|
||
} // PlanEditor::onPaste()
|
||
|
||
|
||
void PlanEditor::onSymbolModified( AdvancedSymbology::SymbologyType symbologyType
|
||
, const QString &sidcPattern
|
||
, const QString &symbolAttributes
|
||
, const SituationMap::SimpleValue<AdvancedSymbology::Injury> &participantState
|
||
, const SituationMap::SimpleValue<int> &participantPartyId
|
||
, const SituationMap::SimpleValue<int> &participantDamageId
|
||
, const QMap<SituationMap::Participant::TextModifier, SituationMap::SimpleValue<QString>> &participantTextModifier)
|
||
|
||
{
|
||
abortCurrentBboxRubberband();
|
||
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
for (SituationMap::UniqueMapId uid : qAsConst(m_internal->m_selectionList))
|
||
{
|
||
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
|
||
if (modelPrimitive.isValid())
|
||
{
|
||
// ToDo: check which symbol norm is the sidc
|
||
QString currentSidc = m_internal->m_geoModel->getAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC).toString();
|
||
|
||
if (AdvancedSymbology::SidcCodec::decodeSymbologyType(currentSidc) != symbologyType)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// Apply sidcPattern to sidc attribute of each selected feature
|
||
for (int i = 0; i < sidcPattern.size(); ++i)
|
||
{
|
||
if (sidcPattern[i] != QChar(uint('*'))) currentSidc[i] = sidcPattern[i];
|
||
}
|
||
|
||
#ifdef LTS_DEBUG
|
||
DEBUG_LOG(m_internal->m_logger) << "SidcPattern " << sidcPattern;
|
||
DEBUG_LOG(m_internal->m_logger) << "CurrentSidc " << currentSidc;
|
||
DEBUG_LOG(m_internal->m_logger) << "NewSidc " << currentSidc;
|
||
#endif
|
||
|
||
if (SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol == m_internal->m_geoModel->getType(modelPrimitive))
|
||
{
|
||
// It's a participant symbol with background color as defined in symbolColor
|
||
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC, currentSidc);
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC_Attributes, symbolAttributes);
|
||
}
|
||
|
||
if (SituationMap::GeometryModel::PrimitiveType::DictionarySymbol == m_internal->m_geoModel->getType(modelPrimitive))
|
||
{
|
||
// It's a symbol from ESRI DictionaryRenderer the symbol can have additinal attributes, the background color is fixed
|
||
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC, currentSidc);
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC_Attributes, symbolAttributes);
|
||
}
|
||
|
||
if (SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol == m_internal->m_geoModel->getType(modelPrimitive))
|
||
{
|
||
// It's a symbol from ESRI DictionaryRenderer the symbol can have additinal attributes, the background color is fixed
|
||
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC, currentSidc);
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC_Attributes, symbolAttributes);
|
||
if (participantState.changed())
|
||
{
|
||
m_internal->m_geoModel->setPrimitiveAttribute( modelPrimitive
|
||
, SituationMap::GeometryModel::Attribute::Injury
|
||
, static_cast<int>(participantState.value()) );
|
||
}
|
||
if (participantPartyId.changed())
|
||
{
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::ForceId, participantPartyId.value());
|
||
}
|
||
if (participantDamageId.changed())
|
||
{
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::DamageForceId, participantDamageId.value());
|
||
}
|
||
for (auto it = participantTextModifier.constBegin(); it != participantTextModifier.constEnd(); ++it)
|
||
{
|
||
const auto &mod = it.key();
|
||
const SituationMap::SimpleValue<QString> &value = it.value();
|
||
|
||
if (value.changed())
|
||
{
|
||
SituationMap::GeometryModel::Attribute geoModelAttribute = SituationMap::GeometryModel::Attribute::None;
|
||
switch (mod)
|
||
{
|
||
case SituationMap::Participant::TextModifier::EF_ReinforcedReduced : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_EF; break;
|
||
case SituationMap::Participant::TextModifier::G_StaffComments : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_G; break;
|
||
case SituationMap::Participant::TextModifier::H_AdditionalInformation : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_H; break;
|
||
case SituationMap::Participant::TextModifier::JKLNP : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_KLNPJ; break;
|
||
case SituationMap::Participant::TextModifier::M_HigherFormation : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_M; break;
|
||
case SituationMap::Participant::TextModifier::T_UniqueDesignation : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_T; break;
|
||
case SituationMap::Participant::TextModifier::V_Type : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_V; break;
|
||
case SituationMap::Participant::TextModifier::W_DateTimeGroup : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_W; break;
|
||
case SituationMap::Participant::TextModifier::XY_AltitudeLocation : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_XY; break;
|
||
case SituationMap::Participant::TextModifier::Z_Speed : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_Z; break;
|
||
case SituationMap::Participant::TextModifier::END : Q_ASSERT(false); break;
|
||
}
|
||
|
||
if (SituationMap::GeometryModel::Attribute::None != geoModelAttribute)
|
||
{
|
||
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, geoModelAttribute, value.value());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} // if isValid()
|
||
}
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(tr("modify symbol sidc", TR_UNDO_TOKEN));
|
||
} // void PlanEditor::onSymbolModified( const QString & sidcPattern, const QString & symbolAttributes )
|
||
|
||
|
||
void PlanEditor::onSymbolXmlAttrModified(const QString & undoToken, SituationMap::GeometryModel::Attribute attribute, const QVariant &value)
|
||
{
|
||
m_internal->m_geoModel->startUndoBlock();
|
||
{
|
||
for (SituationMap::UniqueMapId uid : qAsConst(m_internal->m_selectionList))
|
||
{
|
||
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
|
||
if (modelPrimitive.isValid())
|
||
{
|
||
if (SituationMap::GeometryModel::PrimitiveType::Symbol == m_internal->m_geoModel->getType(modelPrimitive))
|
||
{
|
||
m_internal->m_geoModel->setPrimitiveAttribute( modelPrimitive, attribute, value );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
m_internal->m_geoModel->endUndoBlock(undoToken);
|
||
} // void PlanEditor::onSymbolXmlAttrModified(const QString & undoToken, SituationMap::GeometryModel::Attribute attribute, const QVariant &value)
|
||
|
||
|
||
//#define IMPORT_GUEZ_SYMBOLS_FROM_FILE 1
|
||
|
||
static void importGuezXMLSymbolsFromFile(const AdvancedSymbology::SymbolDictionary &symbolDict)
|
||
{
|
||
Q_UNUSED(symbolDict);
|
||
|
||
#ifdef IMPORT_GUEZ_SYMBOLS_FROM_FILE
|
||
|
||
QMap<int, QString> symbolIdtoPPType;
|
||
|
||
const QString & dirPath = QStringLiteral("D:/Development/Projekte/SituationMap/Symbole-GUEZ");
|
||
QFile symbolDump(dirPath + QStringLiteral("/guez_symbole.unl"));
|
||
QFile typeDump(dirPath + QStringLiteral("/guez_typen.unl"));
|
||
|
||
if (typeDump.exists() && typeDump.open(QIODevice::ReadOnly | QIODevice::Text))
|
||
{
|
||
while (true)
|
||
{
|
||
const QByteArray & lineData = typeDump.readLine();
|
||
if (lineData.isEmpty()) break;
|
||
|
||
const QStringList &typeData = QString::fromLatin1(lineData).split(QLatin1Char('|'));
|
||
if (typeData.size() > 4)
|
||
{
|
||
bool valid = false;
|
||
int symbolId = typeData[3].toInt(&valid);
|
||
if (valid)
|
||
{
|
||
symbolIdtoPPType[symbolId] = typeData[2];
|
||
qCritical() << typeData[2] << " --->> " << symbolId;
|
||
}
|
||
}
|
||
}
|
||
typeDump.close();
|
||
}
|
||
|
||
|
||
if (symbolDump.exists() && symbolDump.open(QIODevice::ReadOnly|QIODevice::Text) )
|
||
{
|
||
const QString & guezSymbolDirName = QStringLiteral("GuezSymbols");
|
||
QDir guezSymbolRoot(dirPath);
|
||
QDir guezSymbolDir(dirPath + QStringLiteral("/") + guezSymbolDirName);
|
||
|
||
guezSymbolDir.removeRecursively();
|
||
guezSymbolRoot.mkdir(guezSymbolDirName);
|
||
|
||
QString xmlContent = QString::fromLatin1(symbolDump.readAll());
|
||
QString blockBegin = QStringLiteral("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||
QString blockEnd = QStringLiteral("</symbol>");
|
||
|
||
const QVector<QStringRef> & xmlSymbolVector = xmlContent.splitRef(blockEnd,QString::SplitBehavior::SkipEmptyParts);
|
||
for (auto xmlSymbolRef : qAsConst(xmlSymbolVector))
|
||
{
|
||
int xmlBegin = xmlSymbolRef.indexOf(blockBegin);
|
||
QString xmlSymbol = xmlSymbolRef.mid(xmlBegin).toString() + blockEnd + QStringLiteral("\n");
|
||
|
||
// replace some character to get a valid xml string:
|
||
|
||
xmlSymbol.replace( QStringLiteral(" =") , QStringLiteral("=") );
|
||
xmlSymbol.replace( QStringLiteral("= ") , QStringLiteral("=") );
|
||
xmlSymbol.replace( QStringLiteral("/ >") , QStringLiteral("/>") );
|
||
xmlSymbol.replace( QStringLiteral("\\n") , QStringLiteral("\n") );
|
||
xmlSymbol.replace( QStringLiteral("\\") , QStringLiteral("") );
|
||
|
||
// skip over empty symbols
|
||
int xmlEmptyCounter = xmlSymbol.indexOf(QStringLiteral("</graphic")) - xmlSymbol.indexOf(QStringLiteral("<graphic")) - 30;
|
||
|
||
if (xmlEmptyCounter < 0) continue;
|
||
|
||
AdvancedSymbology::SymbolProperties proper;
|
||
|
||
if (!symbolDict.setXmlSymbol(xmlSymbol,&proper))
|
||
{
|
||
if (xmlSymbolRef.mid(xmlBegin-2, 2) == QStringLiteral("||")) continue; // may be scrap, skip error message
|
||
|
||
qCritical() << "Insert XML symbol into symbology dictionary failed:";
|
||
qCritical() << ((xmlBegin < 0) ? xmlSymbolRef.toString() : xmlSymbol);
|
||
qCritical() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
|
||
continue;
|
||
}
|
||
|
||
if (symbolIdtoPPType.contains(proper.key().toInt())) // skip over symbol that are not used in type db
|
||
{
|
||
QFile guezSymbolXML(guezSymbolDir.absoluteFilePath(QStringLiteral("guez_symbol_%1.xml").arg(proper.key())));
|
||
|
||
if (guezSymbolXML.exists())
|
||
{
|
||
qCritical() << xmlSymbolRef.toString();
|
||
qCritical() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
|
||
qCritical() << "File \"" << guezSymbolXML.fileName() << "\"already exists!!!!!";
|
||
continue;
|
||
}
|
||
|
||
if (guezSymbolXML.open(QIODevice::OpenModeFlag::ReadWrite | QIODevice::OpenModeFlag::Text))
|
||
{
|
||
guezSymbolXML.write(xmlSymbol.toUtf8());
|
||
guezSymbolXML.close();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
symbolDict.removeXmlSymbol(proper.sidc());
|
||
}
|
||
}
|
||
symbolDump.close();
|
||
}
|
||
#endif // IMPORT_GUEZ_SYMBOLS_FROM_FILE
|
||
} // static void importGuezXMLSymbolsFromFile(AdvancedSymbology::SymbolDictionary & symbolDict)
|
||
|
||
} // namespace PlanEditor
|
||
|