35#include <QActionGroup>
38#include <QDesktopServices>
40#include <QDialogButtonBox>
46#include <QInputDialog>
57#include <QPlainTextEdit>
58#include <QPluginLoader>
62#include <QSignalMapper>
65#include <QStackedWidget>
67#include <QStringListModel>
71#include <QWidgetAction>
72#include <QtCore/QDirIterator>
73#include <QtSvg/QSvgRenderer>
75#include <SimoxUtility/algorithm/string/string_tools.h>
84#include <ArmarXGui/applications/ArmarXGui/ui_ArmarXMainWindow.h>
93#include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
94#include <Inventor/nodes/SoPerspectiveCamera.h>
103 static const char* ARMARX_GUI_APPLICATION_NAME =
"ArmarX";
105 static const char* CONFIG_LOAD_LAST_CONFIG =
"LoadLastConfig";
106 static const char* CONFIG_BLACKLISTED_TIPS =
"BlacklistedTips";
109 const std::vector<std::string>& packages,
110 const QString& configToLoad,
111 bool disablePreloading) :
114 defaultPackageNames(packages),
115 widgetsLocked(false),
117 ARMARX_GUI_APPLICATION_NAME +
".conf"),
118 mainSettings(QString(settingsFile.c_str()), QSettings::NativeFormat)
121 QMainWindow::separator {
122 width: 3px; /* when vertical */
123 height: 3px; /* when horizontal */
125 QMainWindow::separator:hover {
130 mainWidgetNames = QStringList() << "Meta.LogViewer"
131 <<
"Meta.SystemStateMonitor"
132 <<
"Meta.ScenarioManager"
133 <<
"Statecharts.StatechartEditor"
134 <<
"ArMem.MemoryViewer";
137 QPixmap pm(QString(
"://icons/ArmarX-Splashscreen.png"));
138 splashSceen =
new QSplashScreen(pm);
141 ui = new ::Ui::ArmarXMainWindow();
142 mutex3d = std::make_shared<std::recursive_mutex>();
149 setTag(ARMARX_GUI_APPLICATION_NAME);
150 QString username = qgetenv(
"USER");
151 if (username.isEmpty())
153 username = qgetenv(
"USERNAME");
156 guiWindowBaseName = QString{ARMARX_GUI_APPLICATION_NAME};
157 setWindowTitle(guiWindowBaseName);
158 this->registry = registry;
159 setAttribute(Qt::WA_QuitOnClose);
162 setCentralWidget(NULL);
165 tipDialog->setBlackListedStrings(
166 mainSettings.value(CONFIG_BLACKLISTED_TIPS).toStringList());
167 ui->actionLoadLastConfig->setChecked(mainSettings.value(CONFIG_LOAD_LAST_CONFIG).toBool());
170 connect(addWidgetAction,
171 SIGNAL(clicked(QString, QString)),
173 SLOT(createArmarXWidget(QString, QString)),
174 Qt::UniqueConnection);
177 connect(ui->actionLoadPlugin, SIGNAL(triggered()),
this, SLOT(pluginDialog()));
178 connect(ui->actionSave_Gui, SIGNAL(triggered()),
this, SLOT(saveGuiConfig()));
179 connect(ui->actionLoad_Gui_Config, SIGNAL(triggered()),
this, SLOT(
loadGuiConfig()));
180 connect(ui->actionQuit, SIGNAL(triggered()),
this, SLOT(close()));
181 connect(ui->actionSave_Gui_as, SIGNAL(triggered()),
this, SLOT(saveGuiConfigAs()));
182 connect(ui->actionFullscreen, SIGNAL(triggered()),
this, SLOT(enterFullscreenMode()));
183 connect(ui->actionLock_Widgets, SIGNAL(triggered()),
this, SLOT(toggleWidgetLock()));
186 emergencyStopWidget = EmergencyStopWidgetPtr::dynamicCast(
188 this->registry->addObject(ManagedIceObjectPtr::dynamicCast(emergencyStopWidget));
191 batteryWidget = BatteryWidgetPtr::dynamicCast(
193 this->registry->addObject(ManagedIceObjectPtr::dynamicCast(batteryWidget));
196 QSet<QString> pluginDirs;
198 for (
const std::string& packageName : packages)
202 loadPlugins(pluginDirs,
false);
203 this->enteredOnce =
true;
204 if (!disablePreloading)
213 connectionStatusTimer =
new QTimer(
this);
214 connect(connectionStatusTimer, SIGNAL(timeout()),
this, SLOT(updateStatusOfOpenWidgets()));
215 connectionStatusTimer->start(300);
217 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
218 splashSceen->finish(
this);
221 this, mainSettings.value(
"DoNotShowUseCaseDialog").toBool(),
this);
224 if (!configToLoad.isEmpty())
228 else if (!mainSettings.value(
"DoNotShowUseCaseDialog").toBool() &&
229 guiUseCaseSelector->exec() == QDialog::Accepted)
231 QString path = guiUseCaseSelector->getSelectedConfigFilePath();
238 else if (recentlyFiles.size() > 0 && mainSettings.value(CONFIG_LOAD_LAST_CONFIG).toBool())
241 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG,
false);
244 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG, ui->actionLoadLastConfig->isChecked());
249 QStringList defaultWidgets{
"Meta.LogViewer"};
250 for (
auto& widgetName : defaultWidgets)
254 createArmarXWidget(widgetName, widgetName);
259 mainSettings.setValue(
"DoNotShowUseCaseDialog", guiUseCaseSelector->getDoNotShowAgain());
265 connectionStatusTimer->stop();
266 mainSettings.setValue(CONFIG_BLACKLISTED_TIPS, tipDialog->getBlackListedStrings());
272 ArmarXMainWindow::removeViewerWidget(QObject* widget)
281 removeArmarXWidget(widget);
285 ArmarXMainWindow::setupViewerWidget()
289 return Viewer3DWidgetPtr::dynamicCast(
297 viewer->setMutex3D(mutex3d);
303 ArmarXMainWindow::pluginDialog()
305 QFileDialog dialog(
this);
306 dialog.setFileMode(QFileDialog::ExistingFiles);
307 dialog.setNameFilter(tr(
"Libraries (*.dll *.so *.dylib)"));
308 QStringList fileNames;
312 fileNames = dialog.selectedFiles();
315 foreach (QString filePath, fileNames)
317 pluginCache.removePluginFromCache(filePath);
324 ArmarXMainWindow::loadPlugins(
const QStringList& fileNames)
326 const QStringList suffixes = {
327 "_qt_plugin.so",
"GuiPlugin.so",
"GuiPlugin.dll",
"GuiPlugin.dylib"};
328 QStringList guiFiles;
329 for (
const QString& fileName : fileNames)
332 for (
const QString& suffix : suffixes)
334 if (fileName.endsWith(suffix))
336 guiFiles.push_back(fileName);
342 auto start = IceUtil::Time::now();
343 for (
int i = 0; i < guiFiles.size(); i++)
345 QString fileName = guiFiles.at(i);
346 if ((IceUtil::Time::now() - start).toSeconds() >= 2)
349 splashSceen->showMessage(splashscreenPrefix + fileName,
350 Qt::AlignJustify | Qt::AlignBottom);
351 qApp->processEvents();
353 pluginCache.cachePlugin(fileName);
355 updateAvailableWidgetList();
359 ArmarXMainWindow::addActionToToolBar(QAction* action,
bool allowText)
361 QToolButton* button =
new QToolButton(ui->toolBar);
363 std::optional<QSize> textSize;
366 button->setToolButtonStyle(Qt::ToolButtonStyle::ToolButtonTextBesideIcon);
367 button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
370 button->setText(action->text());
371 textSize = button->sizeHint();
374 button->setDefaultAction(action);
375 if (not action->icon().isNull())
377 const QSize maxSize{256, 24};
378 const QSize iconSize = action->icon().actualSize(maxSize);
381 button->setIconSize(iconSize);
382 button->setFixedSize(textSize.has_value() ? QSize{textSize->width() + iconSize.width(),
386 return ui->toolBar->addWidget(button);
394 QString dir = QString::fromStdString(libPaths);
395 dir = QDir::cleanPath(dir);
403 auto widgetUsageHistory = mainSettings.value(
"WidgetUsageHistory").toList();
404 std::map<QString, int> widgetUsage;
405 for (
auto& widgetName : widgetUsageHistory)
407 if (widgetUsage.count(widgetName.toString()) == 0)
409 widgetUsage[widgetName.toString()] = 1;
413 widgetUsage[widgetName.toString()] += 1;
416 std::multimap<int, QString> ranking;
417 for (
auto it = widgetUsage.begin(); it != widgetUsage.end(); it++)
419 ranking.insert(std::make_pair(it->second, it->first));
422 const int favCount = mainSettings.value(
"FavoriteWidgetCount", 6).toInt();
423 QStringList favoriteWidgetNames;
424 for (
auto it = ranking.rbegin(); it != ranking.rend() && i < favCount; it++)
426 auto& widgetName = it->second;
427 if (!mainWidgetNames.contains(widgetName))
429 favoriteWidgetNames << widgetName;
433 return favoriteWidgetNames;
439 QSet<QString> pluginDirs;
440 splashSceen->showMessage(splashscreenPrefix + packageName,
441 Qt::AlignJustify | Qt::AlignBottom);
442 qApp->processEvents();
444 ARMARX_INFO <<
"Looking for gui plugins in package " << packageName;
446 pluginDirs.insert(dir);
447 loadedPackages << packageName;
448 loadPlugins(pluginDirs,
false);
452 ArmarXMainWindow::loadPlugins(
const QString& pluginDir,
bool searchRecursive)
455 dirs.insert(pluginDir);
456 loadPlugins(dirs, searchRecursive);
460 ArmarXMainWindow::loadPlugins(
const QSet<QString>& pluginDirs,
bool searchRecursive)
467 QList<QDir> directoriesToCheck;
468 QStringList allFileNames;
470 for (
const auto& pluginDir : pluginDirs)
472 directoriesToCheck.push_back(QDir(pluginDir));
474 while (directoriesToCheck.size() > 0)
476 ARMARX_VERBOSE_S <<
"Checking dir : " + directoriesToCheck.front().absolutePath()
478 splashSceen->showMessage(splashscreenPrefix +
479 directoriesToCheck.front().absolutePath(),
480 Qt::AlignJustify | Qt::AlignBottom);
481 qApp->processEvents();
482 QDir currentPluginDir = directoriesToCheck.front();
483 directoriesToCheck.pop_front();
484 QString curPath = currentPluginDir.path();
486 if (curPath.length() == 0)
491 QStringList fileNames = currentPluginDir.entryList(filters, QDir::Files);
493 for (
auto& fileName : fileNames)
495 fileName = currentPluginDir.absoluteFilePath(fileName);
498 allFileNames.append(fileNames);
502 QDirIterator directoryIterator(currentPluginDir.absolutePath(),
504 QDir::Dirs | QDir::NoDotAndDotDot,
505 QDirIterator::Subdirectories);
507 while (directoryIterator.hasNext())
509 directoryIterator.next();
510 directoriesToCheck.push_back(QDir(directoryIterator.filePath()));
516 loadPlugins(allFileNames);
522 auto list = pluginCache.getAvailableWidgetNames();
523 return list.contains(widgetName);
529 QFileInfo pathInfo(filePath);
530 QString fileName(pathInfo.fileName());
531 pluginCache.cachePlugin(filePath);
532 ARMARX_INFO <<
"Plugin Path: " << pathInfo.absoluteFilePath().toStdString()
534 updateAvailableWidgetList();
555 ArmarXMainWindow::closeAllWidgets()
559 OpenWidgetMap listOpenWidgetsTemp = listOpenWidgets;
560 OpenWidgetMap::iterator it = listOpenWidgetsTemp.begin();
562 for (; it != listOpenWidgetsTemp.end(); ++it)
564 ARMARX_INFO <<
"Closing widget " << it.key() <<
" size: " << listOpenWidgetsTemp.size();
565 QDockWidget* w = it.value().first;
583 listOpenWidgets.clear();
585 this->configFilepath =
"";
590 ArmarXMainWindow::closeAllWidgetsWithDialog()
592 QMessageBox dialog(QMessageBox::Question,
593 tr(
"Closing all widgets"),
594 tr(
"Do you really want to close all widgets?"));
595 dialog.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
596 dialog.setDefaultButton(QMessageBox::Yes);
598 if (dialog.exec() == QMessageBox::Yes)
608 QDir path(configFilepath);
609 configFilepath = path.absolutePath();
611 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
612 recentlyFiles.removeAll(configFilepath);
613 recentlyFiles.push_front(configFilepath);
615 if (recentlyFiles.size() > 10)
617 recentlyFiles.pop_back();
620 mainSettings.setValue(
"RecentlyFiles", recentlyFiles);
623 std::vector<std::string>
626 return defaultPackageNames;
634 return Viewer3DWidgetPtr::dynamicCast(
647 if (configFilepath.length() == 0)
649 QFileDialog dialog(
this);
650 dialog.setFileMode(QFileDialog::ExistingFile);
651 dialog.setAcceptMode(QFileDialog::AcceptOpen);
652 QStringList nameFilters;
653 nameFilters <<
"ArmarX Gui-Files (*.armarxgui)"
654 <<
"All Files (*.*)";
655 dialog.setNameFilters(nameFilters);
659 if (dialog.selectedFiles().size() == 0)
664 configFilepath = dialog.selectedFiles()[0];
668 ARMARX_INFO <<
"load config dialog canceled" << std::endl;
676 QDir dir(configFilepath);
678 configFilepath = dir.absolutePath();
680 if (!QFile::exists(configFilepath))
683 "' does not exist.");
689 if (showAsOpenGuiConfig)
695 QSettings settings(configFilepath, QSettings::IniFormat);
698 if (settings.allKeys().size() == 0)
701 configFilepath +
"'!");
709 std::sort(packagesStd.begin(),
711 [](
const std::string& lhs,
const std::string& rhs) ->
bool
712 { return simox::alg::to_lower(lhs) < simox::alg::to_lower(rhs); });
714 QStringList packagesToLoad;
716 for (
const auto& pkg : packagesStd)
718 packagesToLoad.push_back(QString::fromStdString(pkg));
722 settings.setValue(
"loadedPackages", packagesToLoad);
726 foreach (QString package, packagesToLoad)
731 QStringList widgetNames = settings.value(
"WidgetCustomNames").toStringList();
732 foreach (QString widgetCustomName, widgetNames)
734 settings.beginGroup(widgetCustomName);
737 ARMARX_INFO <<
"Creating widget " << settings.value(
"WidgetBaseName").toString()
738 <<
"," << widgetCustomName;
740 settings.value(
"WidgetBaseName").toString(), widgetCustomName, &settings);
744 qApp->processEvents();
748 auto geometryByteArray = settings.value(
"MainWindowGeometry").toByteArray();
749 if (geometryByteArray.size() > 0)
752 restoreGeometry(geometryByteArray);
756 QRect geometry = settings.value(
"MainWindowGeometry").toRect();
757 setGeometry(geometry);
760 if (!restoreState(settings.value(
"DockWidgetsState").toByteArray()))
765 foreach (QString widgetCustomName, widgetNames)
767 settings.beginGroup(widgetCustomName);
768 OpenWidgetMap::iterator it = listOpenWidgets.find(widgetCustomName);
770 if (it != listOpenWidgets.end())
772 it->first->resize(settings.value(
"widgetWidth").toInt(),
773 settings.value(
"widgetHeight").toInt());
778 if (showAsOpenGuiConfig)
780 this->configFilepath = configFilepath;
783 updateOpenWidgetList();
784 QFileInfo file(configFilepath);
785 statusBar()->showMessage(
"'" + file.fileName() +
"' loaded.", 10000);
789 ArmarXMainWindow::saveGuiConfig()
791 if (configFilepath.length() == 0)
793 QFileDialog dialog(
this);
794 dialog.setFileMode(QFileDialog::AnyFile);
795 dialog.setAcceptMode(QFileDialog::AcceptSave);
796 QStringList nameFilters;
797 nameFilters <<
"ArmarX Gui-Files (*.armarxgui)"
798 <<
"All Files (*.*)";
799 dialog.setNameFilters(nameFilters);
803 if (dialog.selectedFiles().size() == 0)
808 QString file = dialog.selectedFiles()[0];
809 QFileInfo fileInfo(file);
811 if (fileInfo.suffix().isEmpty())
813 file +=
".armarxgui";
816 configFilepath = file;
825 QSettings settings(configFilepath, QSettings::IniFormat);
831 settings.setValue(
"loadedPackages", loadedPackages);
832 settings.setValue(
"MainWindowGeometry", geometry());
833 settings.setValue(
"DockWidgetsState", saveState());
834 QStringList widgetCustomNames;
835 OpenWidgetMap::iterator it = listOpenWidgets.begin();
837 for (; it != listOpenWidgets.end(); it++)
839 QString prefix = it.value().first->objectName();
841 settings.beginGroup(prefix);
846 settings.setValue(
"WidgetBaseName", w->getWidgetName());
847 settings.setValue(
"widgetWidth", w->getWidget()->width());
848 settings.setValue(
"widgetHeight", w->getWidget()->height());
849 w->saveSettings(&settings);
850 widgetCustomNames.push_back(prefix);
860 settings.setValue(
"WidgetCustomNames", widgetCustomNames);
861 ARMARX_INFO <<
"Saved config to " << configFilepath;
867 QFileInfo file(configFilepath);
868 statusBar()->showMessage(
"'" + file.fileName() +
"' saved.", 10000);
872 ArmarXMainWindow::saveGuiConfigAs()
874 configFilepath.clear();
881 if (filepath.length() > 0)
884 std::filesystem::path file(filepath.toStdString());
887 setWindowTitle(guiWindowBaseName +
" - " +
888 QString::fromStdString(file.filename().string()) +
" in " +
889 path.absolutePath());
893 setWindowTitle(guiWindowBaseName);
898 ArmarXMainWindow::createArmarXWidget(QString widgetName,
899 QString customInstanceName,
903 if (listOpenWidgets.find(
"Dock" + customInstanceName) != listOpenWidgets.end())
913 if (widgetName ==
"VisionX.PointCloudViewer")
915 ARMARX_INFO <<
"Creating SoQtExaminerViewer for " << widgetName.toStdString();
916 SoQtExaminerViewer(
nullptr,
"", TRUE, SoQtExaminerViewer::BUILD_NONE);
919 auto creator = pluginCache.getWidgetCreator(widgetName);
927 auto widgetUsage = mainSettings.value(
"WidgetUsageHistory").toList();
928 widgetUsage.push_back(widgetName);
929 if (widgetUsage.size() > widgetUsageHistoryLength)
931 widgetUsage.pop_front();
933 mainSettings.setValue(
"WidgetUsageHistory", widgetUsage);
938 w->setMainWindow(
this);
939 w->setInstanceName(customInstanceName);
940 w->setTipDialog(tipDialog);
944 w->loadSettings(settings);
946 else if (w->getConfigDialog(
this))
950 ManagedIceObjectPtr::dynamicCast(w->getConfigDialog().data());
954 comp->__setNoDelete(
true);
955 registry->addObject(comp,
false);
958 w->getConfigDialog()->setModal(
true);
960 w->getConfigDialog().data(), SIGNAL(accepted()), w.get(), SLOT(configAccepted()));
966 w->getConfigDialog().data(), SIGNAL(rejected()), w.get(), SLOT(configRejected()));
972 pendingWidgets.push_back(w);
973 w->getConfigDialog()->show();
974 w->getConfigDialog()->raise();
975 w->getConfigDialog()->activateWindow();
981 addArmarXWidget(w, !settings);
987 bool createViewerWidget)
989 for (
unsigned int i = 0; i < pendingWidgets.size(); ++i)
991 if (pendingWidgets[i].get() == newWidgetController.get())
993 pendingWidgets.erase(pendingWidgets.begin() + i);
998 QString widgetName = newWidgetController->getWidgetName();
999 QString customInstanceName = newWidgetController->getInstanceName();
1001 if (listOpenWidgets.find(customInstanceName) != listOpenWidgets.end())
1007 assert(widgetName == newWidgetController->getWidgetName());
1008 ArmarXDockWidget* dockWidget =
1009 new ArmarXDockWidget(customInstanceName, newWidgetController);
1011 connect(dockWidget, SIGNAL(destroyed(QObject*)),
this, SLOT(removeArmarXWidget(QObject*)));
1013 dockWidget->setArmarXWidget(newWidgetController->getWidget());
1014 dockWidget->setObjectName(customInstanceName);
1015 StatusDockWidgetTitleBar* customTitlebar =
new StatusDockWidgetTitleBar(dockWidget,
this);
1016 dockWidget->setTitleBarWidget(customTitlebar);
1017 customTitlebar->addCustomWidget(newWidgetController->getCustomTitlebarWidget(dockWidget));
1019 if (listOpenWidgets.find(dockWidget->objectName()) != listOpenWidgets.end())
1022 customInstanceName +
"' already exists.");
1027 QDockWidget* biggestOpenDockWidget = getBiggestOpenWidget();
1028 listOpenWidgets[customInstanceName] =
1029 qMakePair<QDockWidget*, ArmarXWidgetControllerPtr>(dockWidget, newWidgetController);
1030 addDockWidget(Qt::RightDockWidgetArea, dockWidget);
1031 newWidgetController->postDocking();
1033 QSize widgetStartSize = newWidgetController->getWidget()->size();
1034 if (widgetStartSize.width() * widgetStartSize.height() >= 400 * 400)
1035 if (biggestOpenDockWidget)
1037 tabifyDockWidget(biggestOpenDockWidget, dockWidget);
1041 dockWidget->raise();
1043 updateOpenWidgetList();
1046 newWidgetController->setMutex3D(mutex3d);
1048 QApplication::instance()
1054 registry->addObject(comp,
false);
1056 int timeoutMs = 30000;
1058 if (!comp->getObjectScheduler()->waitForObjectState(eManagedIceObjectInitialized,
1062 <<
" was not connected to Ice after " << timeoutMs / 1000
1063 <<
" seconds" << std::endl;
1070 SoNode* node = newWidgetController->getScene();
1076 OpenWidgetMap::Iterator it = listOpenWidgets.begin();
1078 for (; it != listOpenWidgets.end(); it++)
1080 viewerInstance = Viewer3DWidgetPtr::dynamicCast(it.value().second);
1088 if (!viewerInstance && createViewerWidget)
1092 viewerInstance = setupViewerWidget();
1095 SoSeparator* sep =
new SoSeparator;
1098 SoPerspectiveCamera* camera =
new SoPerspectiveCamera;
1100 sep->addChild(camera);
1101 sep->addChild(node);
1103 viewer3DMap[customInstanceName] = {sep, newWidgetController->getSceneConfigDialog()};
1108 return newWidgetController;
1114 for (
unsigned int i = 0; i < pendingWidgets.size(); ++i)
1116 if (pendingWidgets[i].get() == newWidgetController.get())
1118 pendingWidgets.erase(pendingWidgets.begin() + i);
1125 ArmarXMainWindow::removeArmarXWidget(QObject* widget)
1127 ARMARX_DEBUG <<
"removing widgetname: " << widget->objectName();
1128 QDockWidget* dockWidget = qobject_cast<QDockWidget*>(widget);
1131 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1133 for (; it != listOpenWidgets.end(); it++)
1135 if (widget == it.value().first)
1140 if (it.value().second)
1142 widgetName = it.value().second->getInstanceName();
1146 if (it.value().first)
1148 widgetName = it.value().first->objectName();
1153 listOpenWidgets.erase(it);
1154 updateOpenWidgetList();
1157 if (viewer3DMap.contains(widgetName) )
1159 auto& node = viewer3DMap[widgetName].node;
1166 ARMARX_DEBUG <<
"Removing from 3D list: " << widgetName;
1167 viewer3DMap.remove(widgetName);
1175 removeDockWidget(dockWidget);
1178 QPointer<QDockWidget>
1179 ArmarXMainWindow::getBiggestOpenWidget()
1181 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1182 QPointer<QDockWidget> biggestWidget = NULL;
1184 for (; it != listOpenWidgets.end(); it++)
1186 QDockWidget* dockWidget = it.value().first;
1188 if (!biggestWidget ||
1189 dockWidget->size().width() * dockWidget->size().height() >
1190 biggestWidget->size().width() * biggestWidget->size().height())
1192 biggestWidget = dockWidget;
1196 return biggestWidget;
1200 ArmarXMainWindow::getCategoryMenu(
const std::string& categoryString,
1204 Ice::StringSeq items = simox::alg::split(categoryString,
".");
1206 if (items.size() <= 1)
1211 auto actions = menu->actions();
1213 for (QAction* action : actions)
1215 if (action->text().toStdString() == *items.begin())
1217 items.erase(items.begin(), items.begin() + 1);
1218 std::string rest = simox::alg::join(items,
".");
1220 if (!action->menu())
1222 action->setMenu(
new QMenu(QString::fromStdString(*items.begin()),
this));
1225 if (action->icon().isNull() && !categoryIcon.isNull())
1227 action->setIcon(categoryIcon);
1228 action->setIconVisibleInMenu(
true);
1231 return getCategoryMenu(rest, action->menu(), categoryIcon);
1235 return menu->addMenu(QString::fromStdString(*items.begin()));
1239 ArmarXMainWindow::updateAvailableWidgetList()
1243 updatefavoriteActions();
1247 ui->menuAdd_Widget->clear();
1248 searchField =
new QLineEdit(ui->menuAdd_Widget);
1249 searchField->setToolTip(
"Search and add a new widget from all loaded ArmarX Gui Plugins");
1250 searchField->setMaximumWidth(250);
1251 searchField->setPlaceholderText(
"Widget Search");
1252 ui->toolBar->clear();
1254 QStringList widgetNameList;
1258 ui->toolBar->addWidget(emergencyStopWidget->getButtonWidget());
1261 ui->toolBar->addWidget(batteryWidget->getBatteryWidget());
1263 ui->toolBar->addSeparator();
1265 ui->toolBar->setIconSize(QSize(256, 24));
1267 QMap<QString, QAction*> actionsForToolBar;
1270 for (
const auto& [fullWidgetName, widgetInfo] : pluginCache.getAvailableWidgets())
1272 QString widgetName = fullWidgetName;
1273 widgetName = widgetName.remove(0, widgetName.lastIndexOf(
".") + 1);
1274 widgetNameList << fullWidgetName;
1278 categoryIcon = widgetInfo->getCategoryIcon();
1288 getCategoryMenu(fullWidgetName.toStdString(), ui->menuAdd_Widget, categoryIcon);
1289 AddArmarXWidgetAction* action =
new AddArmarXWidgetAction(widgetName, menu,
this);
1293 widgetIcon = widgetInfo->getIcon();
1302 action->setIcon(widgetIcon);
1303 action->setIconVisibleInMenu(
true);
1305 action->setData(fullWidgetName);
1306 menu->addAction(action);
1308 if (mainWidgetNames.contains(fullWidgetName))
1310 actionsForToolBar[fullWidgetName] = action;
1312 actionList[fullWidgetName] = action;
1314 action, SIGNAL(triggered()), action, SLOT(addArmarXWidget()), Qt::UniqueConnection);
1316 SIGNAL(clicked(QString, QString)),
1318 SLOT(createArmarXWidget(QString, QString)),
1319 Qt::UniqueConnection);
1323 for (
const QString& widgetName : mainWidgetNames)
1325 if (QAction* action = actionsForToolBar.value(widgetName))
1327 const bool allowText =
false;
1328 addActionToToolBar(action, allowText);
1331 addArVizGodotIcon();
1333 AddArmarXWidgetAction* completerAction =
1334 new AddArmarXWidgetAction(
"", ui->menuAdd_Widget,
this);
1335 InfixCompleter* completer =
new InfixCompleter(widgetNameList, searchField);
1337 searchField, SIGNAL(textEdited(QString)), completer, SLOT(setCompletionInfix(QString)));
1340 connect(completerAction, SIGNAL(accepted()), searchField, SLOT(clear()));
1341 connect(completerAction,
1342 SIGNAL(clicked(QString, QString)),
1344 SLOT(createArmarXWidget(QString, QString)),
1345 Qt::UniqueConnection);
1346 searchField->setCompleter(completer);
1349 ui->toolBar->addSeparator();
1350 ui->toolBar->addWidget(searchField);
1353 QString::fromUtf8(
"://icons/edit-add.ico"), QSize(), QIcon::Normal, QIcon::Off);
1354 openWidgetButton =
new QToolButton(
this);
1355 openWidgetButton->setEnabled(
false);
1356 openWidgetButton->setIcon(icon);
1357 openWidgetButton->setFixedSize({24, 24});
1358 openWidgetButton->setToolTip(
"Open selected widget");
1359 connect(openWidgetButton,
1362 SLOT(openWidgetButtonClicked()),
1363 Qt::UniqueConnection);
1364 ui->toolBar->addWidget(openWidgetButton);
1365 connect(searchField,
1366 SIGNAL(textChanged(QString)),
1368 SLOT(updateOpenWidgetButtonStatus(QString)),
1369 Qt::UniqueConnection);
1371 connect(searchField,
1372 SIGNAL(returnPressed()),
1374 SLOT(openWidgetButtonClicked()),
1375 Qt::UniqueConnection);
1378 ui->toolBar->addSeparator();
1379 favoritesLabel =
new QLabel(
"Favorites:");
1380 favoritesLabel->setToolTip(
"The favorites are generated from the usage frequency over "
1381 "the last X widget creations."
1382 " Rightclick to change the number of displayed favorites");
1383 ui->toolBar->addWidget(favoritesLabel);
1385 favoritesLabel->setContextMenuPolicy(Qt::CustomContextMenu);
1386 connect(favoritesLabel,
1387 SIGNAL(customContextMenuRequested(
const QPoint&)),
1389 SLOT(onContextMenuFavoritesRequested(
const QPoint&)));
1391 updatefavoriteActions();
1395 ArmarXMainWindow::updateOpenWidgetList()
1397 ui->menuWindows->clear();
1398 QAction* closeAllAction =
new QAction(
"Close all widgets", ui->menuWindows);
1399 connect(closeAllAction, SIGNAL(triggered()),
this, SLOT(closeAllWidgetsWithDialog()));
1400 ui->menuWindows->addAction(closeAllAction);
1401 ui->menuWindows->addSeparator();
1403 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1405 for (; it != listOpenWidgets.end(); it++)
1407 QDockWidget* dockWidget = it.value().first;
1408 QAction* action =
new QAction(dockWidget->objectName(), ui->menuWindows);
1409 action->setCheckable(
true);
1410 action->setChecked(!dockWidget->isHidden());
1412 connect(action, SIGNAL(toggled(
bool)), dockWidget, SLOT(setVisible(
bool)));
1414 ui->menuWindows->addAction(action);
1419 ArmarXMainWindow::addArVizGodotIcon()
1421 const char* path = std::getenv(
"arviz_godot_DIR");
1422 if (path ==
nullptr)
1427 std::filesystem::path buildDirectory(path);
1428 std::filesystem::path mainDirectory = buildDirectory.parent_path();
1430 std::filesystem::path binaryPath = buildDirectory /
"bin" /
"arviz-godot";
1431 std::filesystem::path iconPath =
1432 mainDirectory /
"source" /
"arviz_godot" /
"project" /
"icon.png";
1434 if (not std::filesystem::exists(binaryPath) or not std::filesystem::exists(iconPath))
1439 QIcon icon(iconPath.c_str());
1440 QString name(
"ArViz Godot");
1442 QAction* action =
new QAction(icon, name,
this);
1444 bool allowText =
false;
1445 addActionToToolBar(action, allowText);
1447 auto slot = [
this, binaryPath]()
1449 if (not std::filesystem::exists(binaryPath))
1451 QMessageBox errorBox;
1453 nullptr,
"Error",
"The ArViz Godot executable is no longer available.");
1473 int null = open(
"/dev/null", O_WRONLY);
1474 dup2(null, STDOUT_FILENO);
1475 dup2(null, STDERR_FILENO);
1477 execl(binaryPath.c_str(),
"arviz-godot",
nullptr);
1481 connect(action, &QAction::triggered,
this,
slot, Qt::UniqueConnection);
1487 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
1488 QMenu* menu = ui->menuRecently_Opened_Files;
1489 auto actions = menu->actions();
1491 for (QAction* action : actions)
1493 if (!action->isCheckable() && !action->isSeparator())
1495 menu->removeAction(action);
1499 foreach (QString file, recentlyFiles)
1504 action->setCheckable(
false);
1505 connect(action, SIGNAL(triggered()), action, SLOT(openFile()));
1506 menu->addAction(action);
1511 ArmarXMainWindow::updateStatusOfOpenWidgets()
1513 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1515 for (; it != listOpenWidgets.end(); it++)
1517 QDockWidget* dockWidget = it.value().first;
1520 qobject_cast<StatusDockWidgetTitleBar*>(dockWidget->titleBarWidget());
1522 if (titlebar && comp)
1525 ManagedIceObjectConnectivity con = comp->getConnectivity();
1526 QStringList dependencies;
1528 for (DependencyMap::iterator i = con.dependencies.begin();
1529 i != con.dependencies.end();
1532 ManagedIceObjectDependencyBasePtr& dep = i->second;
1534 if (!dep->getResolved() || comp->getState() == eManagedIceObjectStarted)
1536 dependencies << QString::fromStdString(dep->getName());
1540 titlebar->
changeStatus((ManagedIceObjectState)comp->getState(), dependencies);
1546 ArmarXMainWindow::enterFullscreenMode()
1549 ui->toolBar->hide();
1550 ui->menubar->hide();
1551 ui->statusbar->hide();
1554 leaveFullScreenActionF11 =
new QAction(
this);
1555 leaveFullScreenActionF11->setShortcut(Qt::Key_F11);
1556 connect(leaveFullScreenActionF11, SIGNAL(triggered()),
this, SLOT(leaveFullscreenMode()));
1557 addAction(leaveFullScreenActionF11);
1559 leaveFullScreenActionEsc =
new QAction(
this);
1560 leaveFullScreenActionEsc->setShortcut(Qt::Key_Escape);
1561 connect(leaveFullScreenActionEsc, SIGNAL(triggered()),
this, SLOT(leaveFullscreenMode()));
1562 addAction(leaveFullScreenActionEsc);
1566 ArmarXMainWindow::leaveFullscreenMode()
1569 removeAction(leaveFullScreenActionF11);
1570 leaveFullScreenActionF11 =
nullptr;
1572 removeAction(leaveFullScreenActionEsc);
1573 leaveFullScreenActionEsc =
nullptr;
1576 ui->toolBar->show();
1577 ui->menubar->show();
1578 ui->statusbar->show();
1582 ArmarXMainWindow::toggleWidgetLock()
1584 QList<ArmarXDockWidget*> dockWidgets = findChildren<ArmarXDockWidget*>();
1588 for (
auto& widget : dockWidgets)
1590 widget->unlockWidget();
1596 for (
auto& widget : dockWidgets)
1598 widget->lockWidget();
1602 widgetsLocked = !widgetsLocked;
1612 QAction(widgetName, parent), mainGui(mainGui)
1626 if (widgetName.isEmpty())
1628 QLineEdit* edit = qobject_cast<QLineEdit*>(sender());
1631 widgetName = edit->text();
1639 setText(widgetName);
1640 setData(widgetName);
1647 dialog->editWidgetName->setText(
"");
1648 dialog->editWidgetName->setText(this->text());
1650 if (!dialog->checkWidgetName(this->text()))
1652 dialog->setModal(
true);
1664 emit
clicked(this->
data().toString(), dialog->editWidgetName->text());
1671 scrollArea =
new QScrollArea();
1672 scrollArea->setWidgetResizable(
true);
1674 QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1675 scrollArea->setSizePolicy(sizePolicy);
1676 setWidget(scrollArea);
1678 savedTitleBar =
nullptr;
1690 scrollArea->setWidget(widget);
1706 emit destroyed(
this);
1714 ARMARX_INFO <<
"Locking widget: " << objectName();
1715 savedTitleBar = titleBarWidget();
1716 setTitleBarWidget(
new QWidget());
1726 ARMARX_INFO <<
"Unlocking widget: " << objectName();
1727 if (savedTitleBar !=
nullptr)
1729 QWidget* old = titleBarWidget();
1730 setTitleBarWidget(savedTitleBar);
1731 savedTitleBar =
nullptr;
1746 QAction(text, parent), mainGui(mainGui)
1755 mainGui->loadGuiConfig(text());
1760 armarx::ArmarXMainWindow::on_actionClear_tip_blacklist_triggered()
1762 tipDialog->setBlackListedStrings(QStringList());
1763 mainSettings.setValue(CONFIG_BLACKLISTED_TIPS, tipDialog->getBlackListedStrings());
1764 mainSettings.sync();
1769 armarx::ArmarXMainWindow::on_actionAbout_triggered()
1773 "ArmarX Graphical User Interface",
1774 QString(
"ArmarX is being developed at the High Performance Humanoid Technologies (H2T) "
1775 "lab at the Karlsruhe Institute of Technology (KIT)\nCopyright H2T, KIT, ") +
1776 QString(&__DATE__[7]) +
1781 armarx::ArmarXMainWindow::on_actionLoadLastConfig_toggled(
bool toggled)
1783 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG, toggled);
1784 mainSettings.sync();
1788 armarx::ArmarXMainWindow::on_actionArmarX_Documentation_triggered()
1790 QDesktopServices::openUrl(QUrl(
"http://armarx.humanoids.kit.edu/"));
1794 armarx::ArmarXMainWindow::on_actionOpen_Use_Case_triggered()
1796 guiUseCaseSelector->setCancelButtonText(
"Cancel");
1797 if (guiUseCaseSelector->exec() == QDialog::Accepted)
1799 QString path = guiUseCaseSelector->getSelectedConfigFilePath();
1801 if (!path.isEmpty())
1803 loadGuiConfig(path,
false);
1806 mainSettings.setValue(
"DoNotShowUseCaseDialog", guiUseCaseSelector->getDoNotShowAgain());
1810 armarx::ArmarXMainWindow::on_actionClear_plugin_cache_triggered()
1812 pluginCache.clearCacheFile();
1816 ArmarXMainWindow::updateOpenWidgetButtonStatus(QString widgetName)
1818 openWidgetButton->setEnabled(pluginCache.getAvailableWidgetNames().contains(widgetName));
1822 ArmarXMainWindow::openWidgetButtonClicked()
1824 addWidgetAction->triggered(searchField->text());
1828 ArmarXMainWindow::onContextMenuFavoritesRequested(
const QPoint& pos)
1832 auto numberOfFavIcons =
new QSpinBox(&menu);
1833 numberOfFavIcons->setRange(1, 100);
1834 numberOfFavIcons->setSingleStep(1);
1835 numberOfFavIcons->setValue(mainSettings.value(
"FavoriteWidgetCount", 6).toInt());
1836 numberOfFavIcons->setToolTip(
"Max number of favorites");
1837 connect(numberOfFavIcons,
1838 SIGNAL(valueChanged(
int)),
1840 SLOT(onNumberOfMaxFavoritesChanged(
int)));
1842 QWidgetAction* action =
new QWidgetAction{&menu};
1843 action->setDefaultWidget(numberOfFavIcons);
1844 menu.addAction(action);
1845 menu.exec(favoritesLabel->mapToGlobal(pos));
1849 ArmarXMainWindow::onNumberOfMaxFavoritesChanged(
int i)
1851 mainSettings.setValue(
"FavoriteWidgetCount", i);
1852 updatefavoriteActions();
1856 ArmarXMainWindow::updatefavoriteActions()
1859 if (favoriteActionWidgetNames == list
1866 favoriteActionWidgetNames = list;
1867 for (
auto* action : favoriteActions)
1869 ui->toolBar->removeAction(action);
1870 action->deleteLater();
1872 favoriteActions.clear();
1873 for (
auto widgetName : favoriteActionWidgetNames)
1875 if (actionList.contains(widgetName))
1877 bool allowText =
true;
1878 favoriteActions.emplace_back(addActionToToolBar(actionList[widgetName], allowText));
std::shared_ptr< ArmarXWidgetInfo > ArmarXWidgetInfoPtr
static std::string GetVersion()
The ArmarXDataPath class provides static methods to handle ArmarX data directories.
The ArmarXMainWindow class.
void loadPlugin(QString filePath)
loads a plugin with the given file path
ArmarXMainWindow(const armarx::ManagedIceObjectRegistryInterfacePtr ®istry, const std::vector< std::string > &packages, const QString &configToLoad, bool disablePreloading)
QString getLibraryPathFromPackage(const QString &packageName)
void appendFileToWindowTitle(const QString &filepath="")
void loadPluginsFromPackage(const QString &packageName)
~ArmarXMainWindow() override
void addToRecentlyOpenedFileList(QString configFilepath)
std::vector< std::string > getDefaultPackageNames()
getDefaultPackageNames returns the names of all packages which are searched for plugins when the Arma...
void closeRequest()
emitted, when the main window should be closed
QStringList getFavoriteWidgets()
void closeEvent(QCloseEvent *event) override
emits the closeRequest signal
void updateRecentlyOpenedFileList()
void loadGuiConfig(QString configFilepath="", bool showAsOpenGuiConfig=true)
bool existsWidget(const QString &widgetName)
Viewer3DWidgetPtr getViewerWidget()
Provides access to a viewer widget, if existent.
void updateSceneList(QMap< QString, Viewer3DInfo >)
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
std::string getLibraryPaths() const
Returns the library paths seperated by semi-colons.
static std::vector< std::string > FindAllArmarXSourcePackages()
void setTag(const LogTag &tag)
OpenRecentlyOpenedFileAction(QString text, QObject *parent=0, ArmarXMainWindow *mainGui=0)
static QString GetIconPath(const QString &widgetName)
static QString GetCategoryIconPath(const QString &widgetName)
The TipDialog is a dialog to show tips/hints to the user, which are optionally only shown once.
#define ARMARX_INFO
The normal logging level.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< ArmarXManager > ArmarXManagerPtr
IceUtil::Handle< ManagedIceObjectRegistryInterface > ManagedIceObjectRegistryInterfacePtr
IceUtil::Handle< Viewer3DWidget > Viewer3DWidgetPtr
const LogSender::manipulator flush
IceUtil::Handle< ArmarXWidgetController > ArmarXWidgetControllerPtr
IceInternal::Handle< ManagedIceObject > ManagedIceObjectPtr
std::function< void()> slot