diff --git a/data/ArmarXGui/GuiDefaultConfigs/Statecharts.armarxgui b/data/ArmarXGui/GuiDefaultConfigs/Statecharts.armarxgui index 69de95b384e7463e6c0cb6f4d4c75c31f3d63fc4..d0c7d986d99845e8188471a9ee1edb847aef3cf5 100644 --- a/data/ArmarXGui/GuiDefaultConfigs/Statecharts.armarxgui +++ b/data/ArmarXGui/GuiDefaultConfigs/Statecharts.armarxgui @@ -1,7 +1,7 @@ [General] ConfigTitle="Statechart Programming" ConfigDescription="GUI layout for programming statecharts" -IconPath=":statechart-editor/states.svg" +IconPath="Statecharts.StatechartEditor.png" MainWindowGeometry=@ByteArray(\x1\xd9\xd0\xcb\0\x1\0\0\0\0\0\x18\0\0\0\x34\0\0\af\0\0\x4y\0\0\0\"\0\0\0U\0\0\a\\\0\0\x4o\0\0\0\0\0\0) DockWidgetsState="@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x1\0\0\0\x1\0\0\a;\0\0\x3\xc2\xfc\x2\0\0\0\x2\xfc\0\0\0\x43\0\0\x3\xc2\0\0\0\0\0\xff\xff\xff\xfc\x1\0\0\0\x2\xfc\0\0\0\0\0\0\x3\x32\0\0\0\0\0\xff\xff\xff\xfc\x2\0\0\0\x2\xfc\0\0\0\x43\0\0\x2%\0\0\0\0\0\xff\xff\xff\xfa\0\0\0\0\x2\0\0\0\x2\xfb\0\0\0$\0\x44\0o\0\x63\0k\0M\0\x65\0t\0\x61\0.\0L\0o\0g\0V\0i\0\x65\0w\0\x65\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\xfb\0\0\0(\0\x44\0o\0\x63\0k\0K\0i\0n\0\x65\0m\0\x61\0t\0i\0\x63\0U\0n\0i\0t\0G\0U\0I\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\xfb\0\0\0&\0\x44\0o\0\x63\0k\0P\0l\0\x61\0t\0\x66\0o\0r\0m\0U\0n\0i\0t\0G\0U\0I\x1\0\0\x2n\0\0\x1\x97\0\0\0\0\0\0\0\0\xfc\0\0\x3\x38\0\0\x4\x3\0\0\0\0\0\xff\xff\xff\xfa\0\0\0\0\x2\0\0\0\x2\xfb\0\0\0\x16\0\x44\0o\0\x63\0k\0R\0o\0\x62\0o\0t\0I\0K\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\xfb\0\0\0\x36\0\x44\0o\0\x63\0k\0V\0i\0s\0u\0\x61\0l\0i\0z\0\x61\0t\0i\0o\0n\0.\0\x33\0\x44\0 \0V\0i\0\x65\0w\0\x65\0r\x1\0\0\0\x43\0\0\x3[\0\0\0\0\0\0\0\0\xfc\0\0\0\x43\0\0\x3\xc2\0\0\0\x8c\x1\0\0\x1d\xfa\0\0\0\0\x2\0\0\0\x4\xfb\0\0\0(\0\x44\0o\0\x63\0k\0S\0t\0\x61\0t\0\x65\0\x63\0h\0\x61\0r\0t\0\x45\0\x64\0i\0t\0o\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\x62\0\xff\xff\xff\xfb\0\0\0(\0\x44\0o\0\x63\0k\0S\0t\0\x61\0t\0\x65\0\x63\0h\0\x61\0r\0t\0V\0i\0\x65\0w\0\x65\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0n\0\xff\xff\xff\xfb\0\0\0\x1a\0\x44\0o\0\x63\0k\0L\0o\0g\0V\0i\0\x65\0w\0\x65\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0n\0\xff\xff\xff\xfb\0\0\0\x34\0\x44\0o\0\x63\0k\0O\0\x62\0s\0\x65\0r\0v\0\x65\0r\0s\0.\0O\0\x62\0s\0\x65\0r\0v\0\x65\0r\0V\0i\0\x65\0w\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\x62\0\xff\xff\xff\0\0\0\0\0\0\x3\xc2\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x1\0\0\0\xe\0t\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)" WidgetCustomNames=LogViewer, Observers.ObserverView, StatechartEditor, StatechartViewer diff --git a/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.cpp b/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.cpp index a62d6d90ef1ee987b144ca6725c49818ca51b3ed..7bcb6bf27ccd8ed8cd5d6486bfe194843a0f4385 100644 --- a/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.cpp +++ b/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.cpp @@ -105,18 +105,21 @@ using namespace armarx; ArmarXMainWindow::ArmarXMainWindow(const armarx::ManagedIceObjectRegistryInterfacePtr& registry, const std::vector<string>& packages, const QString& configToLoad) : QMainWindow(NULL), + pluginCache(ArmarXManagerPtr::dynamicCast(registry)), defaultPackageNames(packages), mainSettings(QSettings::UserScope, ARMARX_ORGANIZATION, ARMARX_GUI_APPLICATION_NAME) { + mainWidgets = QStringList() << "Meta.LogViewer" << "Statecharts.StatechartEditor" << "Meta.SystemStateMonitor" << "Meta.ScenarioManager" << "MemoryX.WorkingMemoryGui"; + splashscreenPrefix = "v" + QString::fromStdString(Application::GetVersion()) + " - "; QPixmap pm(QString("://icons/ArmarX-Splashscreen.png")); splashSceen = new QSplashScreen(pm); - splashSceen->show(); + // splashSceen->show(); ui = new ::Ui::ArmarXMainWindow(); mutex3d.reset(new boost::recursive_mutex); ArmarXWidgetInfoPtr viewerWidgetInfo(new ArmarXWidgetInfo(ArmarXWidgetController::createInstance<Viewer3DWidget>, Viewer3DWidget().getWidgetIcon(), QIcon())); - availableWidgets[ARMARX_VIEWER_NAME] = viewerWidgetInfo; + pluginCache.cacheWidget(ARMARX_VIEWER_NAME, viewerWidgetInfo); guiWindowBaseName = ARMARX_GUI_APPLICATION_NAME; setWindowTitle(guiWindowBaseName); @@ -149,7 +152,8 @@ ArmarXMainWindow::ArmarXMainWindow(const armarx::ManagedIceObjectRegistryInterfa pluginDirs.insert(getLibraryPathFromPackage(packageName.c_str())); } loadPlugins(pluginDirs, false); - instantiatePlugins(); + pluginCache.preloadAsync(getFavoriteWidgets()); + // instantiatePlugins(); updateRecentlyOpenedFileList(); @@ -159,13 +163,18 @@ ArmarXMainWindow::ArmarXMainWindow(const armarx::ManagedIceObjectRegistryInterfa connectionStatusTimer->start(300); //changeLayout(2); QStringList recentlyFiles = mainSettings.value("RecentlyFiles").toStringList(); - splashSceen->finish(this); + // splashSceen->finish(this); + guiUseCaseSelector = new GuiUseCaseSelector(this, mainSettings.value("DoNotShowUseCaseDialog").toBool(), this); - if (!mainSettings.value("DoNotShowUseCaseDialog").toBool() && guiUseCaseSelector->exec() == QDialog::Accepted) + if (!configToLoad.isEmpty()) + { + loadGuiConfig(configToLoad); + } + else if (!mainSettings.value("DoNotShowUseCaseDialog").toBool() && guiUseCaseSelector->exec() == QDialog::Accepted) { QString path = guiUseCaseSelector->getSelectedConfigFilePath(); ARMARX_INFO << VAROUT(path); @@ -174,10 +183,6 @@ ArmarXMainWindow::ArmarXMainWindow(const armarx::ManagedIceObjectRegistryInterfa loadGuiConfig(path, false); } } - else if (!configToLoad.isEmpty()) - { - loadGuiConfig(configToLoad); - } else if (recentlyFiles.size() > 0 && mainSettings.value(CONFIG_LOAD_LAST_CONFIG).toBool()) { //set to false in case a plugin crashes the gui @@ -280,6 +285,14 @@ void ArmarXMainWindow::loadPlugins(const QStringList& fileNames) guiFiles.push_back(fileName); } + for (int i = 0; i < guiFiles.size(); i++) + { + QString fileName = guiFiles.at(i); + pluginCache.cachePlugin(fileName); + } + updateAvailableWidgetList(); + return; + omp_lock_t writelock; omp_init_lock(&writelock); @@ -323,6 +336,42 @@ QString ArmarXMainWindow::getLibraryPathFromPackage(const QString& packageName) return dir; } +QStringList ArmarXMainWindow::getFavoriteWidgets() +{ + auto widgetUsageHistory = mainSettings.value("WidgetUsageHistory").toList(); + std::map<QString, int> widgetUsage; + for (auto & widgetName : widgetUsageHistory) + { + if (widgetUsage.count(widgetName.toString()) == 0) + { + widgetUsage[widgetName.toString()] = 1; + } + else + { + widgetUsage[widgetName.toString()] += 1; + } + } + std::multimap<int, QString> ranking; + for (auto it = widgetUsage.begin(); it != widgetUsage.end(); it++) + { + ranking.insert(std::make_pair(it->second, it->first)); + } + int i = 0; + int favCount = mainSettings.value("FavoriteWidgetCount", 6).toInt(); + QStringList favoriteWidgetNames; + mainSettings.setValue("FavoriteWidgetCount", favCount); + for (auto it = ranking.rbegin(); it != ranking.rend() && i < favCount ; it++) + { + auto& widgetName = it->second; + if (!mainWidgets.contains(widgetName)) + { + favoriteWidgetNames << widgetName; + i++; + } + } + return favoriteWidgetNames; +} + void ArmarXMainWindow::loadPluginsFromPackage(const QString& packageName) { QSet<QString> pluginDirs; @@ -491,7 +540,7 @@ void ArmarXMainWindow::instantiatePlugin(QPluginLoader& loader) statusBar()->showMessage(QString::fromStdString(str.str()), 10000); splashSceen->showMessage(splashscreenPrefix + QString::fromStdString(str.str()), Qt::AlignJustify | Qt::AlignBottom); ARMARX_INFO << str.str(); - availableWidgets.insert(newWidgets.begin(), newWidgets.end()); + // availableWidgets.insert(newWidgets.begin(), newWidgets.end()); updateAvailableWidgetList(); ArmarXManagerPtr manager = ArmarXManagerPtr::dynamicCast(registry); @@ -510,27 +559,27 @@ void ArmarXMainWindow::instantiatePlugin(QPluginLoader& loader) bool ArmarXMainWindow::existsWidget(const QString& widgetName) { - WidgetCreatorMap::iterator it = availableWidgets.find(widgetName); - - return (it != availableWidgets.end()); + auto list = pluginCache.getAvailableWidgetNames(); + return list.contains(widgetName); } void ArmarXMainWindow::loadPlugin(QString filePath) { QFileInfo pathInfo(filePath); QString fileName(pathInfo.fileName()); + pluginCache.cachePlugin(filePath); ARMARX_INFO << "Plugin Path: " << pathInfo.absoluteFilePath().toStdString() << armarx::flush; - if (!loadedPluginFilepaths.contains(pathInfo.absoluteFilePath())) - { - QPluginLoader loader(filePath); - // ARMARX_INFO << "loader created" << armarx::flush; - instantiatePlugin(loader); - } - else - { - ARMARX_INFO << "Plugin already loaded" << armarx::flush; - } + // if (!loadedPluginFilepaths.contains(pathInfo.absoluteFilePath())) + // { + // QPluginLoader loader(filePath); + // // ARMARX_INFO << "loader created" << armarx::flush; + // instantiatePlugin(loader); + // } + // else + // { + // ARMARX_INFO << "Plugin already loaded" << armarx::flush; + // } } @@ -864,9 +913,9 @@ ArmarXWidgetControllerPtr ArmarXMainWindow::createArmarXWidget(QString widgetNam return NULL; } - WidgetCreatorMap::iterator it = availableWidgets.find(widgetName); + auto creator = pluginCache.getWidgetCreator(widgetName); - if (it == availableWidgets.end()) + if (!creator) { ArmarXWidgetController::showMessageBox("Could not find widget with Name: " + widgetName); return NULL; @@ -878,7 +927,7 @@ ArmarXWidgetControllerPtr ArmarXMainWindow::createArmarXWidget(QString widgetNam widgetUsage.pop_front(); } mainSettings.setValue("WidgetUsageHistory", widgetUsage); - ArmarXWidgetControllerPtr w = it->second->createInstance(); + ArmarXWidgetControllerPtr w = creator->createInstance(); w->setMainWindow(this); w->setInstanceName(customInstanceName); w->setTipDialog(tipDialog); @@ -1171,26 +1220,46 @@ void ArmarXMainWindow::updateAvailableWidgetList() ui->toolBar->clear(); - QStringList mainWidgets = QStringList() << "Meta.LogViewer" << "Statecharts.StatechartEditor" << "Meta.SystemStateMonitor" << "Meta.ScenarioManager" << "MemoryX.WorkingMemoryGui"; + QMap<QString, QAction*> actionList; - for (std::pair<QString, ArmarXWidgetInfoPtr> pair : availableWidgets) + for (std::pair<QString, ArmarXWidgetInfoPtr> pair : pluginCache.getAvailableWidgets()) { - if (!pair.second) - { - continue; - } + QString fullWidgetName = pair.first; QString widgetName = pair.first; widgetName = widgetName.remove(0, widgetName.lastIndexOf(".") + 1); widgetNameList << pair.first; - QIcon widgetIcon = pair.second->getIcon(); - QIcon categoryIcon = pair.second->getCategoryIcon(); + QIcon categoryIcon; + if (pair.second) + { + categoryIcon = pair.second->getCategoryIcon(); + } + else + { + if (QFile::exists(PluginCache::GetCategoryIconPath(pair.first))) + { + categoryIcon = QIcon(PluginCache::GetCategoryIconPath(pair.first)); + } + } auto menu = getCategoryMenu(pair.first.toStdString(), ui->menuAdd_Widget, categoryIcon); AddArmarXWidgetAction* action = new AddArmarXWidgetAction(widgetName, menu, this); + QIcon widgetIcon; + if (pair.second) + { + widgetIcon = pair.second->getIcon(); + } + else + { + if (QFile::exists(PluginCache::GetIconPath(pair.first))) + { + widgetIcon = QIcon(PluginCache::GetIconPath(pair.first)); + } + } action->setIcon(widgetIcon); action->setIconVisibleInMenu(true); + action->setData(pair.first); menu->addAction(action); @@ -1217,44 +1286,24 @@ void ArmarXMainWindow::updateAvailableWidgetList() ui->toolBar->addSeparator(); ui->toolBar->addWidget(searchField); - auto widgetUsageHistory = mainSettings.value("WidgetUsageHistory").toList(); - if (widgetUsageHistory.size() > 0) + auto favoriteWidgetNames = getFavoriteWidgets(); + + if (favoriteWidgetNames.size() > 0) { ui->toolBar->addSeparator(); auto label = new QLabel("Favorites:"); label->setToolTip("The favorites are generated from the usage frequency over the last X widget creations."); ui->toolBar->addWidget(label); } - std::map<QString, int> widgetUsage; - for (auto & widgetName : widgetUsageHistory) - { - if (widgetUsage.count(widgetName.toString()) == 0) - { - widgetUsage[widgetName.toString()] = 1; - } - else - { - widgetUsage[widgetName.toString()] += 1; - } - } - std::multimap<int, QString> ranking; - for (auto it = widgetUsage.begin(); it != widgetUsage.end(); it++) - { - ranking.insert(std::make_pair(it->second, it->first)); - } - int i = 0; - int favCount = mainSettings.value("FavoriteWidgetCount", 6).toInt(); - mainSettings.setValue("FavoriteWidgetCount", favCount); - for (auto it = ranking.rbegin(); it != ranking.rend() && i < favCount ; it++) + + + for (auto widgetName : favoriteWidgetNames) { - auto& widgetName = it->second; - if (actionList.contains(widgetName) && !mainWidgets.contains(widgetName)) + if (actionList.contains(widgetName)) { - ui->toolBar->addAction(actionList[it->second]); - i++; + ui->toolBar->addAction(actionList[widgetName]); } } - } void ArmarXMainWindow::updateOpenWidgetList() diff --git a/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h b/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h index 402bd113ec96cb63fc62543fc39ebe01a041c190..dfbf71038ecce9c7b5c837c9edbfcc90eebf4980 100644 --- a/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h +++ b/source/ArmarXGui/applications/ArmarXGui/ArmarXMainWindow.h @@ -25,6 +25,7 @@ #define ARMARXMAINWINDOW_H #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/PluginCache.h> // Qt #include <QMainWindow> @@ -116,6 +117,8 @@ namespace armarx bool existsWidget(const QString& widgetName); QString getLibraryPathFromPackage(const QString& packageName); + QStringList getFavoriteWidgets(); + public slots: void loadPluginsFromPackage(const QString& packageName); void loadGuiConfig(QString configFilepath = "", bool showAsOpenGuiConfig = true); @@ -183,6 +186,7 @@ namespace armarx void instantiatePlugins(); + PluginCache pluginCache; QDir pluginsDir; QStringList loadedPackages; std::vector<QPluginLoader*> pluginsToLoad; @@ -196,7 +200,7 @@ namespace armarx QStringList loadedPluginFilepaths; QList<QWidget*> widgetsList; - WidgetCreatorMap availableWidgets; + // WidgetCreatorMap availableWidgets; QMap<QString, SoNode*> viewer3DMap; @@ -223,6 +227,7 @@ namespace armarx QSplashScreen* splashSceen; QString splashscreenPrefix; GuiUseCaseSelector* guiUseCaseSelector; + QStringList mainWidgets; boost::shared_ptr<boost::recursive_mutex> mutex3d; diff --git a/source/ArmarXGui/applications/ArmarXGui/Widgets/UseCaseSelectorItem.cpp b/source/ArmarXGui/applications/ArmarXGui/Widgets/UseCaseSelectorItem.cpp index c804b290ac2e266c0b39139e8f138ef95196649e..0724ec7598b603f64bb72b3b40088c93ab627fe0 100644 --- a/source/ArmarXGui/applications/ArmarXGui/Widgets/UseCaseSelectorItem.cpp +++ b/source/ArmarXGui/applications/ArmarXGui/Widgets/UseCaseSelectorItem.cpp @@ -25,10 +25,12 @@ #include <ArmarXGui/applications/ArmarXGui/ui_UseCaseSelectorItem.h> #include <boost/filesystem/path.hpp> #include <ArmarXCore/core/logging/Logging.h> +#include <QFile> +#include <ArmarXGui/libraries/ArmarXGuiBase/PluginCache.h> namespace armarx { - UseCaseSelectorItem::UseCaseSelectorItem(const QString& title, const QString& description, const QString& configFilePath, const QString& packageName, const QString& iconPath, QWidget* parent) : + UseCaseSelectorItem::UseCaseSelectorItem(const QString& title, const QString& description, const QString& configFilePath, const QString& packageName, QString iconPath, QWidget* parent) : QWidget(parent), ui(new Ui::UseCaseSelectorItem), configFilePath(configFilePath) @@ -40,16 +42,29 @@ namespace armarx boost::filesystem::path p(configFilePath.toStdString()); p.filename().stem(); ui->filenameLabel->setText(QString(p.filename().string().c_str()) + " in " + packageName + " "); + QString finalPath = iconPath; if (!iconPath.isEmpty()) { - QPixmap pixmap(iconPath); - if (!pixmap.isNull()) + if (!QFile::exists(iconPath)) { - ui->iconLabel->setPixmap(pixmap.scaled(pixmapSize, pixmapSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + auto copy = iconPath; + finalPath = PluginCache::GetIconCachePath() + "resources/" + copy.remove(0, 1); } - else + if (!QFile::exists(finalPath)) { - ARMARX_INFO_S << "Cannot find image: " << iconPath.toStdString(); + finalPath = PluginCache::GetIconCachePath() + iconPath; + } + if (QFile::exists(finalPath)) + { + QPixmap pixmap(finalPath); + if (!pixmap.isNull()) + { + ui->iconLabel->setPixmap(pixmap.scaled(pixmapSize, pixmapSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + } + else + { + ARMARX_INFO_S << "Cannot find image: " << iconPath.toStdString(); + } } } } diff --git a/source/ArmarXGui/applications/ArmarXGui/Widgets/UseCaseSelectorItem.h b/source/ArmarXGui/applications/ArmarXGui/Widgets/UseCaseSelectorItem.h index 0beea8fa16d1fa239f91dd28e6bb3b29fbc5fde5..82bd69cbbad9e71eeb9fbbfe5e471820c22673a7 100644 --- a/source/ArmarXGui/applications/ArmarXGui/Widgets/UseCaseSelectorItem.h +++ b/source/ArmarXGui/applications/ArmarXGui/Widgets/UseCaseSelectorItem.h @@ -39,7 +39,7 @@ namespace armarx Q_OBJECT public: - explicit UseCaseSelectorItem(const QString& title, const QString& description, const QString& configFilePath, const QString& packageName, const QString& iconPath, QWidget* parent = 0); + explicit UseCaseSelectorItem(const QString& title, const QString& description, const QString& configFilePath, const QString& packageName, QString iconPath, QWidget* parent = 0); ~UseCaseSelectorItem(); QString getConfigFilePath() const; bool isHighlighted() const; diff --git a/source/ArmarXGui/gui-plugins/ScenarioManager/controller/SettingsController.cpp b/source/ArmarXGui/gui-plugins/ScenarioManager/controller/SettingsController.cpp index 1cf7c22437ff40621f64d1422b210bb005b296f3..610e6bbe2c2d6ca90304a5c706bea43d8a0ddb48 100644 --- a/source/ArmarXGui/gui-plugins/ScenarioManager/controller/SettingsController.cpp +++ b/source/ArmarXGui/gui-plugins/ScenarioManager/controller/SettingsController.cpp @@ -30,6 +30,7 @@ #include <ArmarXCore/util/ScenarioManagerCommon/parser/PidManager.h> #include <ArmarXCore/core/logging/Logging.h> #include <QStringList> +#include <QMessageBox> #include <QList> #include <QVariant> #include <QSettings> @@ -126,6 +127,18 @@ void SettingsController::showPackageAdderView() void SettingsController::addPackage(std::string name) { + for (auto package : *packages) + { + if (package->getName().compare(name) == 0) + { + QMessageBox box; + QString message(QString::fromStdString("Package " + name + " is already open")); + box.setText(message); + box.exec(); + return; + } + } + QSettings settings("KIT", "ScenarioManager"); QStringList packages = settings.value("packages").toStringList(); diff --git a/source/ArmarXGui/gui-plugins/ScenarioManager/gui/detailedapplicationview.cpp b/source/ArmarXGui/gui-plugins/ScenarioManager/gui/detailedapplicationview.cpp index 9988584f8031384665d0ae61d96139e128fec219..41b4db891be660db76b2bcea20f50b2c69915123 100644 --- a/source/ArmarXGui/gui-plugins/ScenarioManager/gui/detailedapplicationview.cpp +++ b/source/ArmarXGui/gui-plugins/ScenarioManager/gui/detailedapplicationview.cpp @@ -522,9 +522,13 @@ void DetailedApplicationView::itemChanged(QtProperty* property, const QVariant& else if (property->propertyName().compare("Instance Name") && properties->getProperty(property->propertyName().toStdString()).compare(value.toString().toStdString())) { lastAppInstance->modifyProperty(property->propertyName().toStdString(), property->valueText().toStdString()); - lastAppInstance->setDefaultPropertyEnabled(property->propertyName().toStdString(), true); - variantManager->setAttribute(property, QLatin1String("enabled"), true); - + if (value.toString().compare("<set value!>") + && value.toString().compare("::NOT_DEFINED::") + && value.toString().compare("::_NOT_SET_::")) + { + lastAppInstance->setDefaultPropertyEnabled(property->propertyName().toStdString(), true); + variantManager->setAttribute(property, QLatin1String("enabled"), true); + } updateTimer.start(UPDATE_TIMER_INTERVAL); } //showApplicationInstance(lastAppInstance); @@ -572,8 +576,8 @@ void DetailedApplicationView::itemAttributeChanged(QtProperty* property, const Q if (definition.isRequired()) { - properties->getProperties()->setProperty(property->propertyName().toStdString(), ""); - internalManager->setValue(property, ""); + properties->getProperties()->setProperty(property->propertyName().toStdString(), "::_NOT_SET_::"); + internalManager->setValue(property, "::_NOT_SET_::"); } else { diff --git a/source/ArmarXGui/gui-plugins/ScenarioManager/gui/scenarioitem.cpp b/source/ArmarXGui/gui-plugins/ScenarioManager/gui/scenarioitem.cpp index a4204bcf8b2ddd6b9d20d44e133ff95525a2edb5..765cf926faf76873542fbe0ad54b4c0f3c54dc40 100644 --- a/source/ArmarXGui/gui-plugins/ScenarioManager/gui/scenarioitem.cpp +++ b/source/ArmarXGui/gui-plugins/ScenarioManager/gui/scenarioitem.cpp @@ -75,27 +75,48 @@ void ScenarioItem::update() if (scenario.get() != nullptr) { m_itemData[0] = scenario->getName().c_str(); - std::string status = scenario->getStatus(); - if (status.compare("Running") == 0) - { - m_itemData[4] = "Running"; - } - else if (status.compare("Stopped") == 0) - { - m_itemData[4] = "Stopped"; - } - else if (status.compare("") == 0) - { - m_itemData[4] = "Unknown"; - } - else - { - m_itemData[4] = "Mixed"; - } + m_itemData[4] = QString::fromStdString(scenario->getStatus()); } else if (!packageName.empty() && applications->size() > 0) { m_itemData[0] = QString::fromStdString(packageName); + + std::string status = ""; + for (auto app : *applications) + { + if (status.compare("") == 0 && app->getStatus().compare("Running") == 0) + { + status = "Running"; + } + else if (status.compare("") == 0 && app->getStatus().compare("Stopped") == 0) + { + status = "Stopped"; + } + else if (status.compare("Running") == 0 && app->getStatus().compare("Running") == 0) + { + status = "Running"; + } + else if (status.compare("Stopped") == 0 && app->getStatus().compare("Stopped") == 0) + { + status = "Stopped"; + } + else if (status.compare("Running") == 0 && app->getStatus().compare("Stopped") == 0) + { + status = "Mixed"; + break; + } + else if (status.compare("Stopped") == 0 && app->getStatus().compare("Running") == 0) + { + status = "Mixed"; + break; + } + else + { + status = "Mixed"; + break; + } + } + m_itemData[4] = QString::fromStdString(status); } else { @@ -125,7 +146,6 @@ void ScenarioItem::update() { m_itemData[4] = "Unknown"; } - } } diff --git a/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/io/XmlReader.cpp b/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/io/XmlReader.cpp index da5fc414517b1e2d44f2bf068cb48b1ccd5acac8..a7f26e8403b4ec6aa583f5932147eacc1e086bb0 100644 --- a/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/io/XmlReader.cpp +++ b/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/io/XmlReader.cpp @@ -20,6 +20,7 @@ * GNU General Public License */ +#include <ArmarXCore/core/ArmarXManager.h> #include <ArmarXCore/observers/exceptions/user/UnknownTypeException.h> #include <ArmarXCore/util/json/JSONObject.h> #include "../../StatechartViewerPlugin/model/stateinstance/RegularState.h" @@ -34,8 +35,9 @@ using namespace armarx::exceptions::local; using namespace armarx::statechartio; using namespace armarx::statechartmodel; -XmlReader::XmlReader(Ice::CommunicatorPtr iceCommunicator) : - iceCommunicator(iceCommunicator) {} +XmlReader::XmlReader(Ice::CommunicatorPtr iceCommunicator, VariantInfoPtr info) : + iceCommunicator(iceCommunicator), + info(info) {} void XmlReader::parseXml(const QString& xmlString) { @@ -200,13 +202,36 @@ armarx::statechartmodel::StateParameterMap XmlReader::readParameterList(rapidxml if (!stateParameter->getDefaultValueJson().isEmpty()) { - try + std::function<bool(std::string, std::string)> loadVar; + loadVar = [&](std::string curType, std::string prevType) { - JSONObjectPtr jsonObject = new JSONObject(iceCommunicator); - jsonObject->fromString(stateParameter->getDefaultValueJson().toUtf8().data()); + if (curType == prevType) + { + return false; + } + try + { + + JSONObjectPtr jsonObject = new JSONObject(iceCommunicator); + jsonObject->fromString(stateParameter->getDefaultValueJson().toUtf8().data()); + + stateParameter->profileDefaultValues[QString::fromUtf8(StatechartProfiles::GetRootName().c_str())] = + {VariantContainerBasePtr::dynamicCast(jsonObject->deserializeIceObject()), stateParameter->getDefaultValueJson()}; + + } + catch (Ice::NoObjectFactoryException& e) + { + ARMARX_INFO_S << "Variant missing - trying to load variant " << e.type << " now"; + info->loadLibraryOfVariant(e.type); + ArmarXManager::RegisterKnownObjectFactoriesWithIce(iceCommunicator); + return loadVar(e.type, curType); + } + return true; + }; - stateParameter->profileDefaultValues[QString::fromUtf8(StatechartProfiles::GetRootName().c_str())] = - {VariantContainerBasePtr::dynamicCast(jsonObject->deserializeIceObject()), stateParameter->getDefaultValueJson()}; + try + { + loadVar("", "-"); } catch (exceptions::user::UnknownTypeException& e) { @@ -234,13 +259,34 @@ armarx::statechartmodel::StateParameterMap XmlReader::readParameterList(rapidxml QString valueJson = readAttribute(defaultValueCurNode, "value", true); VariantContainerBasePtr valueVariant; + std::function<bool(std::string, std::string)> loadVar; + loadVar = [&](std::string curType, std::string prevType) + { + if (curType == prevType) + { + return false; + } + try + { + + JSONObjectPtr jsonObject = new JSONObject(iceCommunicator); + jsonObject->fromString(valueJson.toUtf8().data()); + + valueVariant = VariantContainerBasePtr::dynamicCast(jsonObject->deserializeIceObject()); + } + catch (Ice::NoObjectFactoryException& e) + { + ARMARX_INFO_S << "Variant missing - trying to load variant " << e.type << " now"; + info->loadLibraryOfVariant(e.type); + ArmarXManager::RegisterKnownObjectFactoriesWithIce(iceCommunicator); + return loadVar(e.type, curType); + } + return true; + }; try { - JSONObjectPtr jsonObject = new JSONObject(iceCommunicator); - jsonObject->fromString(valueJson.toUtf8().data()); - - valueVariant = VariantContainerBasePtr::dynamicCast(jsonObject->deserializeIceObject()); + loadVar("", "-"); } catch (exceptions::user::UnknownTypeException& e) { diff --git a/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/io/XmlReader.h b/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/io/XmlReader.h index 314f572aff8081e22579a12f78378ed8e403010d..ce38e0884e9fd2d741e7af758d675c99edc99773 100644 --- a/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/io/XmlReader.h +++ b/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/io/XmlReader.h @@ -28,6 +28,7 @@ #include <ArmarXCore/core/IceManager.h> #include <ArmarXCore/core/exceptions/Exception.h> #include <ArmarXCore/core/rapidxml/rapidxml.hpp> +#include <ArmarXCore/observers/variant/VariantInfo.h> namespace armarx @@ -45,7 +46,7 @@ namespace armarx * Creates a new XmlReader. The ICE communicator is required for deserialization of parameter default values from JSON. * @param iceCommunicator Ice communicator. */ - XmlReader(Ice::CommunicatorPtr iceCommunicator); + XmlReader(Ice::CommunicatorPtr iceCommunicator, VariantInfoPtr info); /** * Parses the given XML document and builds a State object (that can be retrieved using getRootState()). @@ -77,6 +78,7 @@ namespace armarx QString readAttribute(rapidxml::xml_node<>* node, const QString& attributeName, bool required = true) const; Ice::CommunicatorPtr iceCommunicator; + VariantInfoPtr info; armarx::statechartmodel::StatePtr loadedState; bool hasSubstateByInstanceName(const QString& name) const; }; diff --git a/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/model/StateTreeModel.cpp b/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/model/StateTreeModel.cpp index e5c83ce3c826fee44b491887cf4f462a1527fb54..91fa0bfc62429ed69dd49126527c3cb675c90d77 100644 --- a/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/model/StateTreeModel.cpp +++ b/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/model/StateTreeModel.cpp @@ -15,9 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * - * @package - * @author - * @date + * @package + * @author + * @date * @copyright http://www.gnu.org/licenses/gpl-2.0.txt * GNU General Public License */ @@ -123,7 +123,7 @@ void StateTreeModel::loadNode(StateTreeNodePtr node, boost::filesystem::path par try { QString xml = GuiStatechartGroupXmlReader::ReadFileContents(QString::fromUtf8(nodePath.string().c_str())); - boost::shared_ptr<XmlReader> reader(new XmlReader(iceCommunicator)); + boost::shared_ptr<XmlReader> reader(new XmlReader(iceCommunicator, variantInfo)); reader->parseXml(xml); statechartmodel::StatePtr state = reader->getLoadedState(); state->setEditable(node->getGroup()->getWriteAccess() == StatechartGroup::eWritable); diff --git a/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/test/XmlReaderTest.cpp b/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/test/XmlReaderTest.cpp index 211796ccc10babaef584d92dc1429fd14032fdf7..8b246c6fa2c85e36e91c72bc147e46b6e736d00f 100644 --- a/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/test/XmlReaderTest.cpp +++ b/source/ArmarXGui/gui-plugins/StatechartEditorPlugin/test/XmlReaderTest.cpp @@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(testParseXml) QString xmlInput = armarx::RapidXmlReader::ReadFileContents("ArmarXGui/Teststate.xml").c_str(); - XmlReader xmlReader(ic); + XmlReader xmlReader(ic, armarx::VariantInfoPtr()); xmlReader.parseXml(xmlInput); StatePtr state = xmlReader.getLoadedState(); @@ -234,10 +234,10 @@ BOOST_AUTO_TEST_CASE(testAddReferences) "</Substates></State>"; QString subStateXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"RootStateName\" uuid=\"CF3662A8-9234-46BD-82C1-856344108823\" width=\"123\" height=\"456\"/>"; - XmlReader xmlReaderRootState(ic); + XmlReader xmlReaderRootState(ic, armarx::VariantInfoPtr()); xmlReaderRootState.parseXml(rootStateXml); - XmlReader xmlReaderSubState(ic); + XmlReader xmlReaderSubState(ic, armarx::VariantInfoPtr()); xmlReaderSubState.parseXml(subStateXml); StatePtr rootState = xmlReaderRootState.getLoadedState(); @@ -268,52 +268,52 @@ BOOST_AUTO_TEST_CASE(testInvalidXml) // Of course, we cannot test all possible armarx::ArmarXManager::RegisterKnownObjectFactoriesWithIce(ic); // Completely malformed - BOOST_CHECK_THROW(XmlReader(ic).parseXml("This is not XML!"), XmlReaderException); + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("This is not XML!"), XmlReaderException); // Wrong version number - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"0.1\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\"/>"), XmlReaderException); + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"0.1\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\"/>"), XmlReaderException); // Missing attribute (here: name) - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\"/>"), XmlReaderException); + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\"/>"), XmlReaderException); // Invalid value for parameter default - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<InputParameters><Parameter name=\"ParameterName\" type=\"string\" default=\"no JSON\" optional=\"no\"/></InputParameters>" "</State>"), XmlReaderException); // Invalid value for optional attribute of parameter - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<InputParameters><Parameter name=\"ParameterName\" type=\"string\" optional=\"maybe\"/></InputParameters>" "</State>"), XmlReaderException); // Duplicate parameter name - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<InputParameters><Parameter name=\"ParameterName\" type=\"string\" optional=\"yes\"/><Parameter name=\"ParameterName\" type=\"string\" optional=\"no\"/></InputParameters>" "</State>"), XmlReaderException); // Invalid substate type - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<Substates><BogusState name=\"SubstateName\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/></Substates>" "</State>"), XmlReaderException); // Duplicate substate name - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<Substates><EndState name=\"SubstateName\" event=\"foo\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/><EndState name=\"SubstateName\" event=\"bar\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/></Substates>" "</State>"), XmlReaderException); // Duplicate event name - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<Events><Event name=\"EventName\"/><Event name=\"EventName\"/></Events>" "</State>"), XmlReaderException); // Invalid start state name - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<Substates><LocalState name=\"LocalSubstateName\" refuuid=\"CF3662A8-9234-46BD-82C1-856344108823\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/></Substates>" "<StartState substateName=\"NotExistingSubstateName\"/>" "</State>"), XmlReaderException); // Invalid from state name for transition - XmlReader xmlReaderForInvalidFromState(ic); + XmlReader xmlReaderForInvalidFromState(ic, armarx::VariantInfoPtr()); xmlReaderForInvalidFromState.parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<Substates><LocalState name=\"LocalSubstateName\" refuuid=\"CF3662A8-9234-46BD-82C1-856344108823\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/><RemoteState name=\"RemoteSubstateName\" refuuid=\"148C7D1D-1DB4-4A67-893F-D22D36A88823\" proxyName=\"RemoteSubstateProxyName\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/></Substates>" "<Transitions><Transition from=\"NotExistingSubstateName\" to=\"RemoteSubstateName\" eventName=\"Transition1EventName\"/></Transitions>" @@ -321,13 +321,13 @@ BOOST_AUTO_TEST_CASE(testInvalidXml) // Of course, we cannot test all possible BOOST_CHECK_EQUAL(xmlReaderForInvalidFromState.getLoadedState()->getTransitions().size(), 0); // Invalid to state name for transition - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<Substates><LocalState name=\"LocalSubstateName\" refuuid=\"CF3662A8-9234-46BD-82C1-856344108823\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/><RemoteState name=\"RemoteSubstateName\" refuuid=\"148C7D1D-1DB4-4A67-893F-D22D36A88823\" proxyName=\"RemoteSubstateProxyName\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/></Substates>" "<Transitions><Transition from=\"LocalSubstateName\" to=\"NotExistingSubstateName\" eventName=\"Transition1EventName\"/></Transitions>" "</State>"), XmlReaderException); // Invalid sourceType name for parameter mapping - BOOST_CHECK_THROW(XmlReader(ic).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" + BOOST_CHECK_THROW(XmlReader(ic, armarx::VariantInfoPtr()).parseXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><State version=\"1.0\" name=\"Name\" uuid=\"09F54A1A-3A29-4560-B20C-299069288823\" width=\"0\" height=\"0\">" "<Substates><LocalState name=\"LocalSubstateName\" refuuid=\"CF3662A8-9234-46BD-82C1-856344108823\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/><RemoteState name=\"RemoteSubstateName\" refuuid=\"148C7D1D-1DB4-4A67-893F-D22D36A88823\" proxyName=\"RemoteSubstateProxyName\" left=\"0\" top=\"0\" boundingSquareSize=\"0\"/></Substates>" "<Transitions><Transition from=\"LocalSubstateName\" to=\"RemoteSubstateName\" eventName=\"Transition1EventName\"><ParameterMappings><ParameterMapping sourceType=\"invalidSourceType\" from=\"Transition1ParameterMappingSourceKey\" to=\"Transition1ParameterMappingDestinationKey\"/></ParameterMappings></Transition></Transitions>" "</State>"), XmlReaderException); diff --git a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/StateWatcher.cpp b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/StateWatcher.cpp index 1a6fd83e579abe105753a87527ddc3313b8ada61..2d3283bd25885d278f544aef87663ab6edd91d34 100644 --- a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/StateWatcher.cpp +++ b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/StateWatcher.cpp @@ -289,7 +289,7 @@ namespace armarx } else { - ARMARX_WARNING << "could not find state " << activeSubstateName; + ARMARX_INFO << "could not find state " << activeSubstateName; } } else diff --git a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/layout/LayoutController.cpp b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/layout/LayoutController.cpp index 0ddf2faeb1adbefaf87514a75284928686744ed3..15f882c28621a67ce411d498b4fb05e2ad10d957 100644 --- a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/layout/LayoutController.cpp +++ b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/layout/LayoutController.cpp @@ -15,9 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * - * @package - * @author - * @date + * @package + * @author + * @date * @copyright http://www.gnu.org/licenses/gpl-2.0.txt * GNU General Public License */ @@ -36,6 +36,7 @@ armarx::LayoutController::LayoutController(armarx::statechartmodel::StatePtr top idCounter(0), layoutingDisabled(!startEnabled) { + qRegisterMetaType<size_t>("size_t"); timer.setInterval(100); connect(&timer, SIGNAL(timeout()), this, SLOT(startNextLayouting()), Qt::QueuedConnection); diff --git a/source/ArmarXGui/libraries/ArmarXGuiBase/CMakeLists.txt b/source/ArmarXGui/libraries/ArmarXGuiBase/CMakeLists.txt index 7ee147a75de93c98bf9d5b050770e7a3e2cdae32..15bd2d4dad22736c3a8157e26a50bf015f343d6e 100644 --- a/source/ArmarXGui/libraries/ArmarXGuiBase/CMakeLists.txt +++ b/source/ArmarXGui/libraries/ArmarXGuiBase/CMakeLists.txt @@ -26,6 +26,7 @@ set(LIBS ArmarXCoreJsonObject set(LIB_FILES ArmarXWidgetController.cpp ArmarXComponentWidgetController.cpp + PluginCache.cpp widgets/CoinViewer.cpp widgets/editorfileopener.cpp widgets/IceProxyFinder.cpp @@ -43,6 +44,7 @@ set(LIB_FILES ArmarXWidgetController.cpp set(LIB_HEADERS ArmarXGuiInterface.h ArmarXGuiPlugin.h ArmarXWidgetController.h + PluginCache.h widgets/CoinViewer.h ArmarXComponentWidgetController.h widgets/editorfileopener.h diff --git a/source/ArmarXGui/libraries/ArmarXGuiBase/PluginCache.cpp b/source/ArmarXGui/libraries/ArmarXGuiBase/PluginCache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57f673dc5680ea14392374da3f10da6f94e132f5 --- /dev/null +++ b/source/ArmarXGui/libraries/ArmarXGuiBase/PluginCache.cpp @@ -0,0 +1,351 @@ +#include "PluginCache.h" + +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiInterface.h> + +#include <ArmarXCore/core/system/ArmarXDataPath.h> +#include <ArmarXCore/core/ArmarXManager.h> + +#include <QDateTime> +#include <QDirIterator> +#include <QFile> +#include <QResource> +#include <QCryptographicHash> + +namespace armarx +{ + + PluginCache::PluginCache(ArmarXManagerPtr manager) : + cachePath(GetIconCachePath()), + manager(manager) + { + QDir dir(cachePath); + if (!dir.exists()) + { + dir.mkpath("."); + } + + QSettings s(settingsOrganization, settingsApplicationName); + auto map = s.value("widgets").toMap(); + for (QString key : map.keys()) + { + QStringList w = map[key].toString().split(":"); + QStringList keyparts = key.split(":"); + if (w.size() == 3) + { + pluginData[key].pluginPath = keyparts[0]; + pluginData[key].lastModified = QDateTime::fromMSecsSinceEpoch(w[0].toLongLong()); + pluginData[key].hash = w[1].toAscii(); + ARMARX_INFO_S << "Widget: " << w[2]; + pluginData[key].widgets[w[2]] = ArmarXWidgetInfoPtr(); + } + } + } + + PluginCache::~PluginCache() + { + shutdown = true; + if (preloadFuture.valid()) + { + preloadFuture.wait(); + } + } + + bool PluginCache::cachePlugin(const QString& pluginPath) + { + if (pluginPath.isEmpty()) + { + return false; + } + bool found = false; + QFileInfo info(pluginPath) ; + ScopedRecursiveLock lock(cacheMutex); + for (auto & elem : pluginData) + { + // ARMARX_INFO_S << info.lastModified().toString() << elem.pluginPath; + if (elem.pluginPath == pluginPath) + { + if (info.lastModified() == elem.lastModified) + { + ARMARX_DEBUG_S << "Same timestamp"; + found = true; + } + else if (getHash(pluginPath) == elem.hash) + { + ARMARX_DEBUG_S << "Same hash"; + found = true; + } + else + { + ARMARX_VERBOSE_S << "Plugin filestamp is different - loading plugin again."; + } + break; + } + } + if (!found) + { + writeToCache(pluginPath); + return false; + } + ARMARX_INFO_S << "Found plugin " << pluginPath << " in cache"; + return true; + } + + bool PluginCache::cacheWidget(QString widgetName, ArmarXWidgetInfoPtr widgetCreator) + { + ScopedRecursiveLock lock(cacheMutex); + pluginData[""].widgets[widgetName] = widgetCreator; + return true; + } + + ArmarXWidgetInfoPtr PluginCache::getWidgetCreator(const QString& widgetName) + { + ScopedRecursiveLock lock(cacheMutex); + for (const PluginData & data : pluginData) + { + WidgetCreatorMap::const_iterator it = data.widgets.find(widgetName); + if (it != data.widgets.end()) + { + if (it->second) + { + return it->second; + } + } + } + PluginData data = loadFromCache(widgetName); + pluginData[data.pluginPath] = data; + WidgetCreatorMap::const_iterator it = data.widgets.find(widgetName); + if (it != data.widgets.end()) + { + return it->second; + } + return ArmarXWidgetInfoPtr(); + } + + QStringList PluginCache::getAvailableWidgetNames() const + { + ScopedRecursiveLock lock(cacheMutex); + QStringList result; + for (const PluginData & data : pluginData) + { + for (const auto & elem : data.widgets) + { + result << elem.first; + } + } + return result; + + } + + WidgetCreatorMap PluginCache::getAvailableWidgets() const + { + ScopedRecursiveLock lock(cacheMutex); + WidgetCreatorMap result; + for (const PluginData & data : pluginData) + { + result.insert(data.widgets.begin(), data.widgets.end()); + } + return result; + } + + void PluginCache::copyResourcesToCache() + { + QDirIterator it(":", QDirIterator::Subdirectories); + while (it.hasNext()) + { + QString path = it.next().remove(0, 1); + auto newPath = cachePath + "/resources/" + path; + QDir dir(newPath); + if (!dir.exists()) + { + dir.mkpath("."); + } + if (!path.isEmpty() && !QFile::exists(newPath)) + { + QFile::copy(it.next(), newPath); + } + } + } + + QString PluginCache::GetIconCachePath() + { + return QString(armarx::ArmarXDataPath::GetCachePath().c_str()) + "/icons/"; + } + + QString PluginCache::GetIconPath(const QString& widgetName) + { + return GetIconCachePath() + widgetName + ".png"; + } + + QString PluginCache::GetCategoryIconPath(const QString& widgetName) + { + return GetIconCachePath() + widgetName + "-category.png"; + } + + void PluginCache::preloadAsync(QStringList widgetNames, int delayMS) + { + widgetNames.removeDuplicates(); + auto preload = [this](QStringList widgetNames, int delayMS) + { + usleep(delayMS * 1000); + for (QString widgetName : widgetNames) + { + { + ScopedRecursiveLock lock(cacheMutex); + QString pluginPath; + for (PluginData & data : pluginData) + { + for (auto & elem : data.widgets) + { + if (shutdown) + { + return; + } + if (widgetName == elem.first) + { + pluginPath = data.pluginPath; + if (!data.pluginLoader && !pluginPath.isEmpty()) + { + auto pluginLoader = QSharedPointer<QPluginLoader>(new QPluginLoader(pluginPath)); + ARMARX_INFO_S << "Loading plugin " << pluginPath; + pluginLoader->load(); + // data.pluginLoader->load(); + break; + } + } + } + } + } + usleep(1000); // give others chance to get mutex + } + }; + preloadFuture = std::async(std::launch::async, preload, widgetNames, delayMS); + } + + void PluginCache::clearCacheFile() + { + QSettings s(settingsOrganization, settingsApplicationName); + s.clear(); + } + + QByteArray PluginCache::getHash(const QString& pluginPath) + { + QFile file(pluginPath); + QByteArray hashData; + if (file.open(QIODevice::ReadOnly)) + { + QByteArray fileData = file.readAll(); + hashData = QCryptographicHash::hash(fileData, QCryptographicHash::Md5); + } + return hashData.toHex(); + } + + void PluginCache::writeToCache(const QString& pluginPath) + { + auto start = IceUtil::Time::now(); + QByteArray hashData = getHash(pluginPath); + ARMARX_DEBUG_S << "Hashing took " << (IceUtil::Time::now() - start).toMicroSecondsDouble(); + QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath)); + auto widgets = loadPlugin(loader); + QSettings s(settingsOrganization, settingsApplicationName); + ARMARX_INFO_S << "Writing plugin " << pluginPath << " to cache"; + QMap<QString, QVariant> widgetMap = s.value("widgets").toMap(); + QDateTime time = QFileInfo(pluginPath).lastModified(); + for (auto & elem : widgets) + { + ARMARX_INFO_S << pluginPath << ": " << (QString::number(time.toMSecsSinceEpoch()) + ":" + hashData + ":" + elem.first); + widgetMap[pluginPath + ":" + elem.first] = QString::number(time.toMSecsSinceEpoch()) + ":" + hashData + ":" + elem.first; + } + + s.setValue("widgets", widgetMap); + + copyResourcesToCache(); + ScopedRecursiveLock lock(cacheMutex); + pluginData[pluginPath] = {loader, pluginPath, hashData, time, widgets}; + + } + + PluginData PluginCache::loadFromCache(const QString& widgetName) + { + ARMARX_INFO_S << "Loading widget " << widgetName << " from cache "; + QSettings s(settingsOrganization, settingsApplicationName); + QString pluginPath; + QSharedPointer<QPluginLoader> loader; + WidgetCreatorMap widgets; + QDateTime time; + QByteArray hash; + auto map = s.value("widgets").toMap(); + for (auto key : map.keys()) + { + QStringList w = map[key].toString().split(":"); + QStringList keyparts = key.split(":"); + if (w.size() == 3) + { + if (w[2] == widgetName) + { + pluginPath = keyparts[0]; + if (QFile::exists(pluginPath)) + { + hash = w[1].toAscii(); + loader = QSharedPointer<QPluginLoader>(new QPluginLoader(pluginPath)); + widgets = loadPlugin(loader); + time = QDateTime::fromMSecsSinceEpoch(w[0].toLongLong()); + break; + } + else + { + ARMARX_INFO_S << pluginPath << " does not exist"; + } + + } + } + + } + if (!loader) + { + ARMARX_WARNING_S << "Could not find " << widgetName << " in cache"; + } + if (manager) + { + manager->registerKnownObjectFactoriesWithIce(); + } + return PluginData {loader, pluginPath, hash, time, widgets}; + } + + WidgetCreatorMap PluginCache::loadPlugin(QSharedPointer<QPluginLoader> loader) + { + WidgetCreatorMap result; + ARMARX_INFO_S << "Loading plugin " << loader->fileName(); + loader->load(); + QObject* plugin = loader->instance(); + if (plugin) + { + ArmarXGuiInterface* newPlugin = qobject_cast<ArmarXGuiInterface*>(plugin); + if (newPlugin) + { + //ARMARX_INFO << "cast successful" << armarx::flush; + WidgetCreatorMap newWidgets = newPlugin->getProvidedWidgets(); + for (auto elem : newWidgets) + { + ArmarXWidgetInfoPtr info = elem.second; + QIcon icon = info->getIcon(); + if (!icon.isNull()) + { + icon.pixmap(64).save(GetIconPath(elem.first)); + } + icon = info->getCategoryIcon(); + if (!icon.isNull()) + { + icon.pixmap(64).save(GetCategoryIconPath(elem.first)); + } + } + result.insert(newWidgets.begin(), newWidgets.end()); + } + } + else + { + ARMARX_WARNING_S << "Instantiating plugin failed: " << loader->fileName(); + } + return result; + } + +} // namespace armarx diff --git a/source/ArmarXGui/libraries/ArmarXGuiBase/PluginCache.h b/source/ArmarXGui/libraries/ArmarXGuiBase/PluginCache.h new file mode 100644 index 0000000000000000000000000000000000000000..864ee7b0faa311b956d3408f3b5d5387ab5aedc8 --- /dev/null +++ b/source/ArmarXGui/libraries/ArmarXGuiBase/PluginCache.h @@ -0,0 +1,68 @@ +#ifndef _ARMARX_PLUGINCACHE_H +#define _ARMARX_PLUGINCACHE_H + +#include <boost/shared_ptr.hpp> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXWidgetController.h> +#include <QDateTime> +#include <QPluginLoader> +#include <QSet> +#include <future> + + +class QProgressDialog; + +class ArmarXWidgetInfo; +typedef boost::shared_ptr<ArmarXWidgetInfo> ArmarXWidgetInfoPtr; + +typedef armarx::ArmarXWidgetControllerPtr(*WidgetCreatorFunction)(); +typedef std::map<QString, ArmarXWidgetInfoPtr > WidgetCreatorMap; + +namespace armarx +{ + + struct PluginData + { + QSharedPointer<QPluginLoader> pluginLoader; + QString pluginPath; + QByteArray hash; + QDateTime lastModified; + WidgetCreatorMap widgets; + }; + + class PluginCache + { + public: + PluginCache(ArmarXManagerPtr manager); + ~PluginCache(); + bool cachePlugin(const QString& pluginPath); + bool cacheWidget(QString widgetName, ArmarXWidgetInfoPtr widgetCreator); + ArmarXWidgetInfoPtr getWidgetCreator(const QString& widgetName); + QStringList getAvailableWidgetNames() const; + WidgetCreatorMap getAvailableWidgets() const; + const QString settingsOrganization = "KIT"; + const QString settingsApplicationName = "PluginCache"; + void copyResourcesToCache(); + static QString GetIconCachePath(); + static QString GetIconPath(const QString& widgetName); + static QString GetCategoryIconPath(const QString& widgetName); + void preloadAsync(QStringList widgetNames, int delayMS = 1000); + void clearCacheFile(); + QByteArray getHash(const QString& pluginPath); + + protected: + void writeToCache(const QString& pluginPath); + PluginData loadFromCache(const QString& pluginPath); + WidgetCreatorMap loadPlugin(QSharedPointer<QPluginLoader> loader); + const QString cachePath; + QMap<QString, PluginData> pluginData; + ArmarXManagerPtr manager; + mutable RecursiveMutex cacheMutex; + std::future<void> preloadFuture; + bool shutdown = false; + + }; + typedef boost::shared_ptr<PluginCache> PluginCachePtr; + +} // namespace armarx + +#endif // ARMARX_PLUGINCACHE_H