426 lines
14 KiB
C++
Executable File
426 lines
14 KiB
C++
Executable File
/**
|
|
**
|
|
** @RDE_HEADER@
|
|
** plan_editor_internal.h
|
|
** $Id$
|
|
** $HeadURL$
|
|
** $Author$
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Hardware-Environment: Intel-PC
|
|
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
|
**
|
|
** Language ........: C++ 11
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Notes .........:
|
|
**
|
|
** 09.12.2015, JT : First edition for use with Qt5
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
|
|
#include "plan_editor.h"
|
|
|
|
#include "plan_editor_const.h"
|
|
#include "plan_editor_session.h"
|
|
|
|
#include "drop_event_manager.h"
|
|
|
|
#include "attribute_dialog_manager.h"
|
|
#include "favourites_action_manager.h"
|
|
#include "lookup_symbol_manager.h"
|
|
|
|
#include "model_tree_widget.h"
|
|
#include "logging.h"
|
|
|
|
#include "icon_names.h"
|
|
#include "setting_keys.h"
|
|
|
|
#include <ngltranslator/ngltranslator.h>
|
|
|
|
#include <LtsWidgets/lts_drag_icon.h>
|
|
#include <LtsWidgets/lts_drop_handler.h>
|
|
#include <LtsWidgets/lts_frameless_dialog.h>
|
|
#include <LtsWidgets/lts_grid_layout.h>
|
|
#include <LtsWidgets/lts_text_edit_dialog.h>
|
|
#include <LtsSession/lts_session.h>
|
|
#include <LtsSession/lts_session_data.h>
|
|
|
|
#include <Map/map.h>
|
|
|
|
#include <Map/abstract_map_object.h>
|
|
#include <Map/drop_event_manager.h>
|
|
#include <Map/object_factory.h>
|
|
#include <Map/coord_translation_functor.h>
|
|
#include <Map/geometry_model_renderer.h>
|
|
|
|
#include <Rubberbands/rubberband_transform.h>
|
|
|
|
#include <GeometryModel/geometry_model_factory.h>
|
|
#include <GeometryModel/geometry_pixelTextBox.h>
|
|
#include <Map/pixel_based_textbox_handler.h>
|
|
|
|
#include <QtCore/QPropertyAnimation>
|
|
#include <QtCore/QSettings>
|
|
#include <QtCore/QTimer>
|
|
#include <QtCore/QUrl>
|
|
|
|
#include <QtWidgets/QButtonGroup>
|
|
#include <QtWidgets/QCheckBox>
|
|
#include <QtWidgets/QColorDialog>
|
|
#include <QtWidgets/QComboBox>
|
|
#include <QtWidgets/QDial>
|
|
#include <QtWidgets/QFileDialog>
|
|
#include <QtWidgets/QGraphicsView>
|
|
#include <QtWidgets/QGroupBox>
|
|
#include <QtWidgets/QSpinBox>
|
|
#include <QtWidgets/QTextBrowser>
|
|
#include <QtWidgets/QToolButton>
|
|
#include <QtWebEngineWidgets/QWebEngineView>
|
|
|
|
#include <QApplication>
|
|
|
|
|
|
#include <QtWidgets/QTableView>
|
|
|
|
#include <QtWidgets/QTextEdit>
|
|
#include <QtWidgets/QTreeWidget>
|
|
|
|
#include <QtPrintSupport/QPrinter>
|
|
|
|
|
|
namespace PlanEditor
|
|
{
|
|
enum class UpdateViewMode
|
|
{
|
|
Scheduled,
|
|
Immediately,
|
|
Manually
|
|
};
|
|
|
|
|
|
enum class SelectionMode
|
|
{
|
|
Picking,
|
|
Line,
|
|
Lasso,
|
|
Rectangle,
|
|
PickingAndEdit
|
|
};
|
|
|
|
|
|
class PlanEditor::InternalData : public QObject
|
|
{
|
|
Q_OBJECT
|
|
friend class DropCreateLine;
|
|
|
|
public:
|
|
|
|
QString m_title;
|
|
|
|
PlanEditorSession m_session;
|
|
|
|
QPointer<SituationMap::Map> m_map;
|
|
|
|
QString m_logicalLayername;
|
|
SituationMap::GeometryModel *m_geoModel;
|
|
SituationMap::GeometryModelRenderer *m_geoModelRenderer;
|
|
|
|
|
|
QList<SituationMap::GeometryModel::Node> m_nodeClipboard;
|
|
SituationMap::GeometryModel *m_modelClipboard;
|
|
|
|
AttributeDialogManager *m_attributeDialogManager;
|
|
FavouritesActionManager *m_favouritesActionManager;
|
|
LookupSymbolManager *m_lookupSymbolManager;
|
|
|
|
UpdateViewMode m_updateViewMode;
|
|
SelectionMode m_selectionMode;
|
|
|
|
QList<LtsWidgets::LtsDragIcon *> m_ltsItems;
|
|
|
|
QList<QWidget *> m_symbolWidgets;
|
|
|
|
QPointer<LtsWidgets::LtsDialog> m_dlgDebug;
|
|
|
|
LtsWidgets::LtsDragIcon *m_btnUndo;
|
|
LtsWidgets::LtsDragIcon *m_btnRedo;
|
|
|
|
QPointer<QFileDialog> m_fileDialog; // using QPointer because the dialog can be removed by widget hierarchy and will get invalid
|
|
QString m_currentFileName;
|
|
|
|
QWebEngineView *m_viewHelp;
|
|
|
|
QGroupBox *m_gbPlanEditorMain;
|
|
|
|
|
|
QPointer<ModelTreeWidget> m_modelTreeWidget;
|
|
|
|
bool m_symbolDictLoaded;
|
|
|
|
QLineEdit *m_leSidc;
|
|
QPushButton *m_pbCreateSymb;
|
|
|
|
QTimer *m_delayedUpdateTimer;
|
|
QTimer *m_autosaveTimer;
|
|
|
|
QPointer<LtsWidgets::LtsFramelessDialog> m_dlgUndoHistory;
|
|
QPointer<LtsWidgets::LtsFramelessDialog> m_dlgRedoHistory;
|
|
|
|
QTreeWidget *m_lwUndoHistory;
|
|
QTreeWidget *m_lwRedoHistory;
|
|
|
|
QTextEdit *m_teDebug;
|
|
|
|
SituationMap::RefPointer<DropEventManager> m_dropEventManager;
|
|
|
|
QList<SituationMap::UniqueMapId> m_selectionList;
|
|
|
|
QString m_defaultPlanDirectory;
|
|
bool m_readStyleAttributesFromModel;
|
|
|
|
QString m_symbolCurrentSidc;
|
|
|
|
SituationMap::RB::RubberbandTransform *m_currentBboxRubberband;
|
|
|
|
std::function<void()> m_saveFunction;
|
|
|
|
QList<QPointF> m_rbBackupNodeCoordinates;
|
|
|
|
QVector<SituationMap::PBTB_ID> m_ourTextBoxIds; // relevant for PlanEditor
|
|
|
|
// while Editing:
|
|
SituationMap::PBTB_ID m_textBoxIdInEditing; // currentId
|
|
QPointer<QTextEdit> m_textBoxTextEdit; // display
|
|
QString m_htmlTextForCancelation; // cancel purpose
|
|
QPointer<LtsWidgets::LtsTextEditDialog> m_textEditorDialog; // editor
|
|
void resetTextBoxData()
|
|
{
|
|
m_textBoxIdInEditing.init();
|
|
m_textBoxTextEdit.clear();
|
|
m_htmlTextForCancelation.clear();
|
|
delete m_textEditorDialog;
|
|
m_textEditorDialog.clear();
|
|
}
|
|
|
|
QTimer *m_textBoxNotifyTimer{nullptr};
|
|
|
|
Logger &m_logger;
|
|
|
|
InternalData(SituationMap::Map *map, const PlanEditorSession &session, PlanEditor *me)
|
|
: QObject()
|
|
, m_title(QStringLiteral("PlanEditor"))
|
|
, m_session(session)
|
|
, m_map(map)
|
|
// , m_logicalLayername
|
|
, m_geoModel(SituationMap::GeometryModelFactory::singleton()->create())
|
|
, m_geoModelRenderer(nullptr) // -> initLogicalLayernameAndRenderer
|
|
, m_nodeClipboard()
|
|
, m_modelClipboard(SituationMap::GeometryModelFactory::singleton()->create())
|
|
, m_attributeDialogManager(new AttributeDialogManager(me, map, m_geoModel, m_session))
|
|
, m_favouritesActionManager(new FavouritesActionManager(me, map, m_session))
|
|
, m_lookupSymbolManager(nullptr)
|
|
, m_updateViewMode(UpdateViewMode::Scheduled)
|
|
, m_selectionMode(SelectionMode::Picking)
|
|
, m_ltsItems()
|
|
, m_symbolWidgets()
|
|
|
|
, m_dlgDebug() // type = QPointer
|
|
|
|
, m_btnUndo(nullptr)
|
|
, m_btnRedo(nullptr)
|
|
|
|
, m_fileDialog(new QFileDialog(m_session.topLevelWidget()))
|
|
, m_currentFileName()
|
|
, m_viewHelp(nullptr)
|
|
, m_gbPlanEditorMain(nullptr)
|
|
|
|
, m_modelTreeWidget() // type = QPointer
|
|
|
|
, m_symbolDictLoaded(false)
|
|
, m_leSidc(nullptr)
|
|
, m_pbCreateSymb(nullptr)
|
|
, m_delayedUpdateTimer(new QTimer(me))
|
|
, m_autosaveTimer(new QTimer(me))
|
|
|
|
, m_dlgUndoHistory() // type = QPointer
|
|
, m_dlgRedoHistory() // type = QPointer
|
|
, m_lwUndoHistory(nullptr)
|
|
, m_lwRedoHistory(nullptr)
|
|
|
|
, m_teDebug(nullptr)
|
|
, m_dropEventManager(new DropEventManager())
|
|
, m_selectionList()
|
|
, m_defaultPlanDirectory()
|
|
, m_readStyleAttributesFromModel(false)
|
|
|
|
, m_symbolCurrentSidc()
|
|
, m_currentBboxRubberband(nullptr)
|
|
, m_saveFunction()
|
|
, m_rbBackupNodeCoordinates()
|
|
, m_logger(getLogger("PlanEditor"))
|
|
|
|
{
|
|
this->initLogicalLayernameAndRenderer(QStringLiteral("PlanEditorLayer"), me); // default, may be overwritten in context of snapshot
|
|
|
|
// m_geoModel->setMaxUndoSteps(10);
|
|
|
|
m_lookupSymbolManager = new LookupSymbolManager(me, map, m_session);
|
|
|
|
// Make sure that the symbol model exists and has loaded symbol before enabling the gui ...
|
|
// Use a queued connect type because later updates of the model could be very expensive (see
|
|
// FavouritesActionManager::initFromDefaultSettings) and should not be done more than necessary!
|
|
//
|
|
connect(m_lookupSymbolManager, &LookupSymbolManager::readModelFinished, me, &PlanEditor::onEnableSymbolWidgets, Qt::ConnectionType::QueuedConnection);
|
|
|
|
m_geoModelRenderer -> setEditorMode(true);
|
|
|
|
QSettings settings;
|
|
QStringList fileHistoryList = settings.value(QLatin1String(FILEDIALOG_HISTORY_LIST_KEY)).toStringList();
|
|
QStringList fileFilter;
|
|
|
|
fileFilter << QLatin1String("Plan Geometry Model (*.plan)");
|
|
fileFilter << tr("Any files (*)");
|
|
|
|
m_fileDialog -> setFilter(QDir::AllDirs | QDir::Files | QDir::Drives);
|
|
m_fileDialog -> setHistory(fileHistoryList);
|
|
m_fileDialog -> setNameFilters(fileFilter);
|
|
m_fileDialog -> setWindowTitle(tr("Plan Editor - File Selection"));
|
|
|
|
QString locale(QString::fromLatin1(NGL::translationLocale()));
|
|
QString urlName= QStringLiteral("index.html");
|
|
// if (locale == QLatin1String("de_DE"))
|
|
// urlName = QStringLiteral("Start_de.htm");
|
|
// else
|
|
// urlName = QStringLiteral("Start_eng.htm");
|
|
|
|
QString url(QStringLiteral("file:///%1/%2/%3")); // dir, locale, filename
|
|
QString filePath(QStringLiteral("%1/../share/Lts/help/").arg(QApplication::applicationDirPath()));
|
|
|
|
m_viewHelp = new QWebEngineView(m_session.topLevelWidget());
|
|
m_viewHelp->setWindowFlag( Qt::WindowType::Dialog );
|
|
m_viewHelp->setWindowTitle(tr("Plan Editor - View Online Help"));
|
|
url = url.arg(filePath, locale, urlName);
|
|
m_viewHelp->page()->load(QUrl(url));
|
|
if (m_session.isLtsSession())
|
|
{
|
|
// QWebView in Qt5.9 doesn't like to be destroyed immediatelly - deleteLater is needed...
|
|
QObject::connect(m_session.ltsSession().data(), &LtsSession::LtsSession::sessionAboutToBeDestroyed,
|
|
me, [this]()
|
|
{
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
|
|
m_viewHelp->setParent(nullptr);
|
|
m_viewHelp->deleteLater();
|
|
#else
|
|
// N.Thoden, 24.01.2020
|
|
// should avoid memleak / warnings of AddressSanitizer (asan)
|
|
// (but the waring still exists :-()
|
|
delete m_viewHelp;;
|
|
#endif
|
|
m_viewHelp = nullptr;
|
|
});
|
|
}
|
|
|
|
if (m_geoModel == nullptr)
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " Creating Geometry Model failed.";
|
|
return;
|
|
}
|
|
if (m_geoModelRenderer == nullptr)
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " Creating Geometry Model Renderer failed.";
|
|
return;
|
|
}
|
|
|
|
m_map -> installDropEventManager(m_dropEventManager.get());
|
|
|
|
me -> connect(m_lookupSymbolManager, &LookupSymbolManager::addToSymbolFavourites
|
|
, m_favouritesActionManager, &FavouritesActionManager::onSymbolFavouriteAdd);
|
|
|
|
me -> connect(m_favouritesActionManager, &FavouritesActionManager::updateSymbolScopes
|
|
, m_lookupSymbolManager, &LookupSymbolManager::onUpdateSymbolScopes);
|
|
|
|
|
|
me -> connect(m_geoModel, &SituationMap::GeometryModel::typeError, me, &PlanEditor::onNoticeGeoModelTypeError);
|
|
me -> connect(m_geoModel, &SituationMap::GeometryModel::attributeError, me, &PlanEditor::onNoticeGeoModelAttributeError);
|
|
me -> connect(m_geoModel, &SituationMap::GeometryModel::modelError, me, &PlanEditor::onNoticeGeoModelModelError);
|
|
me -> connect(m_geoModel, &SituationMap::GeometryModel::criticalError, me, &PlanEditor::onNoticeGeoModelError);
|
|
|
|
me -> connect(m_geoModel, &SituationMap::GeometryModel::changed, me, &PlanEditor::onNoticeGeoModelUpdate);
|
|
|
|
me -> connect(m_geoModel, &SituationMap::GeometryModel::modificationCount, me, &PlanEditor::onGeoModelModified);
|
|
|
|
me -> connect(m_delayedUpdateTimer, &QTimer::timeout, me, &PlanEditor::onUpdateView);
|
|
me -> connect(m_autosaveTimer, &QTimer::timeout, me, &PlanEditor::onPlanAutoSave);
|
|
|
|
m_delayedUpdateTimer -> setSingleShot(true);
|
|
|
|
} /* InternalData */
|
|
|
|
void initLogicalLayernameAndRenderer(const QString &logicalLayername, QObject *parent)
|
|
{
|
|
m_logicalLayername = logicalLayername;
|
|
delete m_geoModelRenderer;
|
|
m_geoModelRenderer = m_map->createGeometryModelRenderer(m_logicalLayername, m_geoModel, parent);
|
|
}
|
|
|
|
void removeAutosaveFile()
|
|
{
|
|
const QString &tmp = QStringLiteral("/tmp/plan_") + QString::number(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
|
|
if (QFile::exists(tmp))
|
|
QFile::remove(tmp);
|
|
}
|
|
|
|
~InternalData()
|
|
{
|
|
m_favouritesActionManager->onSaveFavouritesToSettings();
|
|
m_favouritesActionManager->removeActionItems();
|
|
|
|
m_favouritesActionManager = nullptr; // it is child of planEditor and is delete by hierarchy when delete planEditor.
|
|
|
|
if (m_fileDialog)
|
|
{
|
|
// ToDo: Find a better way to shutdown the editor and store file history every time.
|
|
QSettings settings;
|
|
settings.setValue(QLatin1String(FILEDIALOG_HISTORY_LIST_KEY), m_fileDialog->history());
|
|
}
|
|
|
|
delete m_modelClipboard; m_modelClipboard = nullptr;
|
|
delete m_geoModel; m_geoModel = nullptr;
|
|
delete m_geoModelRenderer; m_geoModelRenderer = nullptr;
|
|
|
|
// ToDo
|
|
for (const auto &item : qAsConst(m_ltsItems))
|
|
m_session.removeMenuAction(item);
|
|
m_ltsItems.clear();
|
|
|
|
if (m_modelTreeWidget) { m_modelTreeWidget -> deleteLater(); m_modelTreeWidget = nullptr; }
|
|
if (m_dlgDebug) { m_dlgDebug -> deleteLater(); m_dlgDebug = nullptr; }
|
|
|
|
if (m_gbPlanEditorMain) { m_gbPlanEditorMain -> deleteLater(); m_gbPlanEditorMain = nullptr; }
|
|
|
|
m_autosaveTimer->stop();
|
|
delete m_autosaveTimer;
|
|
|
|
m_delayedUpdateTimer->stop();
|
|
delete m_delayedUpdateTimer;
|
|
|
|
} // ~InternalData()
|
|
|
|
InternalData(const InternalData &) = delete;
|
|
InternalData operator = (const InternalData &) = delete;
|
|
|
|
}; // InternalData
|
|
|
|
} // namespace PlanEditor
|