/** ** ** @RDE_HEADER@ ** Do all the work for complex selection operations. ** $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 .........: ** ** 25.07.2016, JT : First edition for use with Qt5 ** ** ----------------------------------------------------------------------------------------------- */ #include "plan_editor.h" #include "plan_editor_const.h" #include "plan_editor_session.h" #include "dialog.h" #include "favourites_action_manager.h" #include "favourite_result_watcher.h" #include "symbol_favourites.h" #include "plan_editor_utils.h" #include "setting_keys.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace PlanEditor { const char *const ScopeFileSuffix = "FavouriteScope.xml"; class FavouriteProps { public: FavouriteProps() = default; ~FavouriteProps() = default; LtsWidgets::LtsDragIcon *m_actionWidget = nullptr; QPixmap m_actionIcon; QString m_scope; QString m_sidc; }; // FavouriteProps class ScopeProps { public: ScopeProps() = default; ~ScopeProps() = default; QAction *m_storeMenuAction = nullptr; QAction *m_saveMenuAction = nullptr; unsigned int m_symbolCount = 0; }; // ScopeProps class FavouritesActionManager::InternalData { public: PlanEditor *m_planEditor; SituationMap::Map *m_map; const PlanEditorSession &m_session; SymbolFavourites *m_symbolFavourites; QFileDialog *m_fileDialog; QMenu *m_favouriteStoreMenu; QMenu *m_favouriteSaveMenu; QList m_ltsItems; QMap m_scopeMap; QMap m_favouriteMap; AdvancedSymbology::SymbolResultWatcher m_symbolGuard; explicit InternalData(const PlanEditorSession &session) : m_planEditor(nullptr) , m_map(nullptr) , m_session(session) , m_symbolFavourites(SymbolFavourites::create()) , m_fileDialog(nullptr) , m_favouriteStoreMenu(nullptr) , m_favouriteSaveMenu(nullptr) , m_ltsItems() , m_scopeMap() , m_favouriteMap() , m_symbolGuard() {;} ~InternalData() { const auto copy = m_favouriteMap; for (const FavouriteProps &prop : copy) m_session.removeMenuAction(prop.m_actionWidget); m_favouriteMap.clear(); m_favouriteStoreMenu = nullptr; m_favouriteSaveMenu = nullptr; for (auto item : qAsConst(m_ltsItems)) m_session.removeMenuAction(item); m_ltsItems.clear(); delete m_symbolFavourites; m_symbolFavourites = nullptr; delete m_fileDialog; m_fileDialog = nullptr; } }; // FavouritesActionManager::InternalData FavouritesActionManager::FavouritesActionManager(PlanEditor *planEditor, SituationMap::Map *map, const PlanEditorSession &session) : QObject(planEditor) , m_internal(new InternalData(session)) { m_internal -> m_planEditor = planEditor; m_internal -> m_map = map; connect(m_internal->m_symbolFavourites, &SymbolFavourites::signalNewScope, this, &FavouritesActionManager::onNewFavouritesScope); connect(m_internal->m_symbolFavourites, &SymbolFavourites::signalNewSymbol, this, &FavouritesActionManager::onNewFavouritesSymbol); connect(m_internal->m_symbolFavourites, &SymbolFavourites::signalDeleteScope, this, &FavouritesActionManager::onDeleteFavouritesScope); connect(m_internal->m_symbolFavourites, &SymbolFavourites::signalDeleteSymbol, this, &FavouritesActionManager::onDeleteFavouritesSymbol); m_internal->m_fileDialog = new QFileDialog(nullptr); } // FavouritesActionManager::FavouritesActionManager( SituationMap::Map * map, LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget, QObject * parent ) void FavouritesActionManager::initMainMenu(bool retranslate) { LtsWidgets::PluginData pluginAction; pluginAction.layoutArea = LtsWidgets::LayoutArea::eMainTab; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Does not work any more! 2018/01/18 JT * pluginAction.identifier = QLatin1String("Separator-Favourite-Symbols"); pluginAction.createWidgetFunc = [](QWidget * parent) -> LtsWidgets::LtsDialog * { LtsWidgets::LtsDialog *separator = new Dialog(parent); QHBoxLayout *layout = new QHBoxLayout(separator); QFrame *line = new QFrame(separator); line->setLineWidth(2); line->setFrameStyle(QFrame::HLine); layout->addSpacing(5); layout->addWidget(line, 1); layout->addSpacing(5); return separator; }; // separator lambda m_internal->m_ltsItems += m_internal->m_session.addMenuAction(pluginAction); // make line separator * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ pluginAction.createWidgetFunc = [](QWidget *) -> LtsWidgets::LtsDialog * { return nullptr; }; // Mike's HACK pluginAction.menuGroup = tr("Favourite Symbols"); if (m_internal->m_session.isLtsSession()) { pluginAction.identifier = QLatin1String("FMS-Load-Scope"); pluginAction.menuIcon = QIcon(QStringLiteral("icon:library_load_scope.svg")); pluginAction.menuText = tr("Library Load Scope"); pluginAction.tooltip = tr("Load favourite scope from library"); if (!retranslate) { LtsWidgets::LtsDragIcon *btnLoad = m_internal->m_session.addMenuAction(pluginAction); m_internal->m_ltsItems += btnLoad; connect(btnLoad, &LtsWidgets::LtsDragIcon::clicked, this, &FavouritesActionManager::onScopeLoadViaSettingService); } else m_internal->m_session.addMenuAction(pluginAction); pluginAction.identifier = QLatin1String("FMS-Store-Scope"); pluginAction.menuIcon = QIcon(QStringLiteral("icon:library_save_scope.svg")); pluginAction.menuText = tr("Library Store Scope"); pluginAction.tooltip = tr("Store favourite scope into library"); if (!retranslate) { LtsWidgets::LtsDragIcon *btnStore = m_internal->m_session.addMenuAction(pluginAction); m_internal->m_ltsItems += btnStore; m_internal->m_favouriteStoreMenu = new QMenu(btnStore); btnStore->setMenu(m_internal->m_favouriteStoreMenu); connect(btnStore, &LtsWidgets::LtsDragIcon::clicked, this, [this]() { m_internal->m_favouriteStoreMenu -> exec(QCursor::pos()); }); } else m_internal->m_session.addMenuAction(pluginAction); } pluginAction.identifier = QLatin1String("File-Load-Scope"); pluginAction.menuIcon = QIcon(QLatin1String("icon:load.svg")); pluginAction.menuText = tr("Load from file"); pluginAction.tooltip = tr("Load scope from file"); if (!retranslate) { LtsWidgets::LtsDragIcon *btnLoad = m_internal->m_session.addMenuAction(pluginAction); m_internal->m_ltsItems += btnLoad; connect(btnLoad, &LtsWidgets::LtsDragIcon::clicked, this, &FavouritesActionManager::onScopeLoadFromFile); } else m_internal->m_session.addMenuAction(pluginAction); pluginAction.identifier = QLatin1String("File-Save"); pluginAction.menuIcon = QIcon(QLatin1String("icon:save.svg")); pluginAction.menuText = tr("Save to file"); pluginAction.tooltip = tr("Save scope to file"); if (!retranslate) { LtsWidgets::LtsDragIcon *btnStore = m_internal->m_session.addMenuAction(pluginAction); m_internal->m_ltsItems += btnStore; m_internal->m_favouriteSaveMenu = new QMenu(btnStore); btnStore->setMenu(m_internal->m_favouriteSaveMenu); connect(btnStore, &LtsWidgets::LtsDragIcon::clicked, this, [this]() { m_internal->m_favouriteSaveMenu -> exec(QCursor::pos()); }); } else m_internal->m_session.addMenuAction(pluginAction); } // void FavouritesActionManager::initMainMenu(bool retranslate) FavouritesActionManager::~FavouritesActionManager() { delete m_internal; } void FavouritesActionManager::initFromDefaultSettings() { #ifdef USE_QSETTINGS const QString &settingKey = QLatin1String(SYMBOL_FAVOURITES_SETTING_KEY); const QString &favouriteXML = QSettings().value(settingKey).toString(); m_internal->m_symbolFavourites->contentFromString(favouriteXML); #endif m_internal->m_planEditor->requestFileServiceReadDefaultSymbolFavourites(); } // void FavouritesActionManager::initFromDefaultSettings() void FavouritesActionManager::removeActionItems() { for (auto item : qAsConst(m_internal->m_ltsItems)) m_internal->m_session.removeMenuAction(item); m_internal->m_ltsItems.clear(); } // void FavouritesActionManager::removeActionItems() SymbolFavourites *FavouritesActionManager::symbolFavourites() const { return m_internal->m_symbolFavourites; } void FavouritesActionManager::onNewFavouritesScope(const QString &scope) { ScopeProps scopeProps; if (m_internal->m_favouriteStoreMenu) { scopeProps.m_storeMenuAction = m_internal->m_favouriteStoreMenu -> addAction(scope); connect(scopeProps.m_storeMenuAction, &QAction::triggered, this, [this, scope](bool) { onScopeStoreViaSettingService(scope); }); // lambda } scopeProps.m_saveMenuAction = m_internal->m_favouriteSaveMenu -> addAction(scope); connect(scopeProps.m_saveMenuAction, &QAction::triggered, this, [this, scope](bool) { onScopeSaveToFile(scope); }); // lambda m_internal -> m_scopeMap[scope] = scopeProps; emit updateSymbolScopes(m_internal->m_symbolFavourites->scopeList()); } // void FavouritesActionManager::onNewFavouritesScope( const QString & scope ) FavouriteProps &FavouritesActionManager::buildFavouriteAction(const QString &scope, const QString &sidc, const QString &name, const QPixmap &symbolPixmap) { LtsWidgets::PluginData pluginAction; FavouriteProps favourite; pluginAction.layoutArea = LtsWidgets::LayoutArea::eMainTab; pluginAction.menuGroup = scope; pluginAction.identifier = QLatin1String("Sidc ") + sidc; pluginAction.menuIcon = QIcon(symbolPixmap); pluginAction.menuText = name; pluginAction.tooltip = tr("Create '%1' symbol - SIDC %2").arg(name, sidc); pluginAction.dropHandlerKey = m_internal->m_planEditor->createSymbolDropEvent(sidc); pluginAction.directFunc = [this, sidc](const LtsWidgets::PluginData &) { m_internal->m_planEditor->onSymbolCreateRubberband(sidc,true); }; favourite.m_actionIcon = symbolPixmap; favourite.m_actionWidget = m_internal->m_session.addMenuAction(pluginAction); favourite.m_scope = scope; favourite.m_sidc = sidc; if (favourite.m_actionWidget) { QMenu *favouriteMenu = new QMenu(); QAction *rmFavouriteAction = favouriteMenu->addAction(tr("Remove from Favourite List")); connect(rmFavouriteAction, &QAction::triggered, this, [this, sidc](bool) { onSymbolFavouriteDelete(sidc); }); favourite.m_actionWidget->setMenu(favouriteMenu); rmFavouriteAction->setObjectName(QLatin1String("remove favourite ") + sidc); } m_internal->m_favouriteMap[sidc] = favourite; m_internal->m_scopeMap[scope].m_symbolCount++; return m_internal->m_favouriteMap[sidc]; } // FavouriteProps & FavouritesActionManager::buildFavouriteAction(const QString & scope, const QString & sidc, const QString & name, const QPixmap & icon ) FavouriteResultWatcher::FavouriteResultWatcher(FavouriteProps &favourite, AdvancedSymbology::SymbolDictionary &symbolDict, QObject *parent) : QObject(parent) , m_favourite(favourite) , m_symbolDict(symbolDict) , m_symbolGuard() { connect(&m_symbolGuard, &AdvancedSymbology::SymbolResultWatcher::resultReady, this, &FavouriteResultWatcher::onSymbolSearchResult); const QString &baseCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(m_favourite.m_sidc); const AdvancedSymbology::SymbolProperties &symbolProperties = m_symbolDict.symbolProperties(baseCode); if (!symbolProperties.key().isEmpty()) { m_favourite.m_actionWidget->setText(symbolProperties.name()); m_symbolGuard.setSymbolResult(symbolDict.findBaseSymbol(m_favourite.m_sidc)); } else deleteLater(); } // FavouriteResultWatcher::FavouriteResultWatcher(FavouriteProps & favourite, AdvancedSymbology::SymbolDictionary & symbolDict, QObject * parent) void FavouriteResultWatcher::onSymbolSearchResult() { QSharedPointer symbolResult = m_symbolGuard.symbolResult(); if (nullptr != symbolResult) { const QPixmap &symbolPixmap = QPixmap::fromImage(symbolResult->symbolImage().image()).scaled(ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio); m_favourite.m_actionIcon = symbolPixmap; m_favourite.m_actionWidget->setIcon(symbolPixmap); } deleteLater(); } // void FavouriteResultWatcher::onSymbolSearchResult() void FavouritesActionManager::onNewFavouritesSymbol(const QString &scope, const QString &sidc) { new FavouriteResultWatcher(buildFavouriteAction(scope, sidc, QString(), QPixmap()), m_internal->m_map->symbolDictionary(), this); } // void FavouritesActionManager::onNewFavouritesSymbol( const QString & scope, const QString & sidc ) void FavouritesActionManager::onDeleteFavouriteSymbol() { QObject *signalSender = sender(); if (signalSender) { const QString &sidc = signalSender->objectName(); onDeleteFavouritesSymbol(sidc); } } // void FavouritesActionManager::onDeleteFavouriteSymbol void FavouritesActionManager::removeScopeMenus(const QString &scope) { if (m_internal -> m_scopeMap.contains(scope)) { ScopeProps &scopeProps = m_internal->m_scopeMap[scope]; delete scopeProps.m_storeMenuAction; scopeProps.m_storeMenuAction = nullptr; delete scopeProps.m_saveMenuAction; scopeProps.m_saveMenuAction = nullptr; m_internal -> m_scopeMap.remove(scope); } } // void FavouritesActionManager::removeScopeMenus( const QString & scope ) void FavouritesActionManager::onDeleteFavouritesScope(const QString &scope) { removeScopeMenus(scope); QStringList scopeList = m_internal->m_symbolFavourites->scopeList(); // The scope is about to be deleted, but has not been removed from list scopeList.removeOne(scope); emit updateSymbolScopes(scopeList); } // void FavouritesActionManager::onDeleteFavouritesScope( const QString & scope ) void FavouritesActionManager::onDeleteFavouritesSymbol(const QString &sidc) { auto it = m_internal->m_favouriteMap.find(sidc); if (it != m_internal->m_favouriteMap.end()) { const FavouriteProps &favouriteProps = it.value(); QString scope = favouriteProps.m_scope; ScopeProps &scopeProps = m_internal->m_scopeMap[scope]; m_internal->m_session.removeMenuAction(favouriteProps.m_actionWidget); m_internal->m_favouriteMap.erase(it); if (scopeProps.m_symbolCount <= 1) removeScopeMenus(scope); else scopeProps.m_symbolCount--; } } // void FavouritesActionManager::onDeleteFavouritesSymbol( const QString & sidc ) void FavouritesActionManager::onSymbolFavouriteAdd(const QString &scope, const QString &sidc) { const AdvancedSymbology::SymbolDictionary &symbolDict = m_internal->m_map->symbolDictionary(); const AdvancedSymbology::SymbolProperties &symbolProps = symbolDict.symbolProperties(sidc); m_internal->m_symbolFavourites->addSymbolFavourite(sidc, scope, symbolProps.name()); } // void FavouritesActionManager::onSymbolFavouriteAdd( const QString & scope, const QString & sidc ) void FavouritesActionManager::onSymbolFavouriteDelete(const QString &sidc) { m_internal->m_symbolFavourites->removeSymbolFavourite(sidc); } void FavouritesActionManager::onSymbolFavouriteDeleteScope(const QString &scope) { m_internal->m_symbolFavourites->removeScope(scope); } // void FavouritesActionManager::onSymbolFavouriteDeleteScope( const QString & scope ) void FavouritesActionManager::onSaveFavouritesToSettings() { QSettings().setValue(QLatin1String(SYMBOL_FAVOURITES_SETTING_KEY), m_internal->m_symbolFavourites->toString()); } // void FavouritesActionManager::onSaveFavouritesToSettings() void FavouritesActionManager::onScopeSaveToFile(const QString &scope) { SymbolFavourites *scopeFavourites = SymbolFavourites::create(); if (m_internal->m_symbolFavourites->copyScope(scope, *scopeFavourites)) { const QString &xmlScope = scopeFavourites->toString(); // Under some conditions QFileDialog calls an processEvents() // To avoid this, create on demand // onScopeSaveToFile is only called on LTS_DEBUG if (!m_internal->m_fileDialog) m_internal->m_fileDialog = new QFileDialog(nullptr); m_internal->m_fileDialog->setAcceptMode(QFileDialog::AcceptMode::AcceptSave); m_internal->m_fileDialog->setDefaultSuffix(QLatin1String(ScopeFileSuffix)); m_internal->m_fileDialog->setNameFilter(QStringLiteral("*.%1").arg(QLatin1String(ScopeFileSuffix))); m_internal->m_fileDialog->setFileMode(QFileDialog::FileMode::AnyFile); m_internal->m_fileDialog->selectFile(scope + QStringLiteral(".%1").arg(QLatin1String(ScopeFileSuffix))); if (QDialog::DialogCode::Accepted == m_internal->m_fileDialog->exec()) { const QStringList &fileList = m_internal->m_fileDialog->selectedFiles(); if (!fileList.isEmpty()) { const QString &xmlFileName = fileList.first(); QFile file(xmlFileName, nullptr); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) QTextStream(&file) << xmlScope; else LtsWidgets::LtsMessageDialog::showMessage(m_internal->m_session.topLevelWidget(), tr("Open '%1' favourites xml file failed").arg(xmlFileName)); // Message reading file failed. } } } else LtsWidgets::LtsMessageDialog::showMessage(m_internal->m_session.topLevelWidget(), tr("Favourite scope '%1' to save doesn't exist").arg(scope)); delete scopeFavourites; } // void FavouritesActionManager::onScopeSaveToFile( const QString & scope ) QStringList FavouritesActionManager::onScopeLoadFromFile() { if (!m_internal->m_fileDialog) m_internal->m_fileDialog = new QFileDialog(nullptr); m_internal->m_fileDialog->setAcceptMode(QFileDialog::AcceptMode::AcceptOpen); m_internal->m_fileDialog->setDefaultSuffix(QLatin1String(ScopeFileSuffix)); m_internal->m_fileDialog->setNameFilter(QStringLiteral("*.%1").arg(QLatin1String(ScopeFileSuffix))); m_internal->m_fileDialog->setFileMode(QFileDialog::FileMode::ExistingFile); if (QDialog::DialogCode::Accepted == m_internal->m_fileDialog->exec()) { const QStringList &fileList = m_internal->m_fileDialog->selectedFiles(); if (!fileList.isEmpty()) { const QString &xmlFileName = fileList.first(); QFile file(xmlFileName, nullptr); SymbolFavourites *scopeFavourites = SymbolFavourites::createFromDevice(&file); if (scopeFavourites) { m_internal->m_symbolFavourites->includeSymbolFavourites(*scopeFavourites); return scopeFavourites->scopeList(); } else LtsWidgets::LtsMessageDialog::showMessage(m_internal->m_session.topLevelWidget(), tr("Reading or parsing '%1' favourites xml file failed").arg(xmlFileName)); // Message reading file failed. } } return QStringList(); } // QString FavouritesActionManager::onScopeLoadFromFile() void FavouritesActionManager::onScopeStoreViaSettingService(const QString &scope) { SymbolFavourites *scopeFavourites = SymbolFavourites::create(); if (m_internal->m_symbolFavourites->copyScope(scope, *scopeFavourites)) { const QString &xmlScope = scopeFavourites->toString(); m_internal->m_planEditor->requestFileServiceStoreSymbolFavourites(xmlScope); } else LtsWidgets::LtsMessageDialog::showMessage(m_internal->m_session.topLevelWidget(), tr("Favourite scope '%1' to save doesn't exist").arg(scope)); delete scopeFavourites; } // void FavouritesActionManager::onScopeStoreViaSetttingService( cosnt QString & scope ) QStringList FavouritesActionManager::onScopeLoadViaSettingService() { QString favouriteXMLString; m_internal->m_planEditor->requestFileServiceReadSymbolFavourites(favouriteXMLString); if (!favouriteXMLString.isEmpty()) { SymbolFavourites *scopeFavourites = SymbolFavourites::createFromString(favouriteXMLString); if (scopeFavourites) { m_internal->m_symbolFavourites->includeSymbolFavourites(*scopeFavourites); return scopeFavourites->scopeList(); } else LtsWidgets::LtsMessageDialog::showMessage(m_internal->m_session.topLevelWidget(), tr("Parsing favourites xml string failed")); // Message reading file failed. } return QStringList(); } // QStringList FavouritesActionManager::onScopeLoadViaSetttingService() } // namespace PlanEditor