31 #include <sys/types.h>
35 #include <QActionGroup>
38 #include <QDesktopServices>
40 #include <QDialogButtonBox>
42 #include <QFileDialog>
43 #include <QGridLayout>
44 #include <QHBoxLayout>
46 #include <QInputDialog>
50 #include <QListWidget>
53 #include <QMessageBox>
54 #include <QModelIndex>
57 #include <QPlainTextEdit>
58 #include <QPluginLoader>
59 #include <QProxyStyle>
60 #include <QPushButton>
61 #include <QScrollArea>
62 #include <QSignalMapper>
65 #include <QStackedWidget>
66 #include <QStringList>
67 #include <QStringListModel>
69 #include <QToolButton>
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>
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),
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>();
144 new ArmarXWidgetInfo(ArmarXComponentWidgetController::createInstance<Viewer3DWidget>,
150 QString username = qgetenv(
"USER");
151 if (username.isEmpty())
153 username = qgetenv(
"USERNAME");
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(
187 ArmarXComponentWidgetController::createInstance<EmergencyStopWidget>());
188 this->registry->addObject(ManagedIceObjectPtr::dynamicCast(emergencyStopWidget));
191 batteryWidget = BatteryWidgetPtr::dynamicCast(
192 ArmarXComponentWidgetController::createInstance<BatteryWidget>());
193 this->registry->addObject(ManagedIceObjectPtr::dynamicCast(batteryWidget));
196 QSet<QString> pluginDirs;
198 for (
const std::string& packageName : packages)
202 loadPlugins(pluginDirs,
false);
203 if (!disablePreloading)
212 connectionStatusTimer =
new QTimer(
this);
213 connect(connectionStatusTimer, SIGNAL(timeout()),
this, SLOT(updateStatusOfOpenWidgets()));
214 connectionStatusTimer->start(300);
216 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
217 splashSceen->finish(
this);
220 this, mainSettings.value(
"DoNotShowUseCaseDialog").toBool(),
this);
223 if (!configToLoad.isEmpty())
227 else if (!mainSettings.value(
"DoNotShowUseCaseDialog").toBool() &&
228 guiUseCaseSelector->exec() == QDialog::Accepted)
237 else if (recentlyFiles.size() > 0 && mainSettings.value(CONFIG_LOAD_LAST_CONFIG).toBool())
240 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG,
false);
243 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG, ui->actionLoadLastConfig->isChecked());
248 QStringList defaultWidgets{
"Meta.LogViewer"};
249 for (
auto& widgetName : defaultWidgets)
253 createArmarXWidget(widgetName, widgetName);
258 mainSettings.setValue(
"DoNotShowUseCaseDialog", guiUseCaseSelector->
getDoNotShowAgain());
264 connectionStatusTimer->stop();
265 mainSettings.setValue(CONFIG_BLACKLISTED_TIPS, tipDialog->getBlackListedStrings());
271 ArmarXMainWindow::removeViewerWidget(QObject* widget)
280 removeArmarXWidget(widget);
284 ArmarXMainWindow::setupViewerWidget()
288 return Viewer3DWidgetPtr::dynamicCast(
296 viewer->setMutex3D(mutex3d);
302 ArmarXMainWindow::pluginDialog()
304 QFileDialog dialog(
this);
305 dialog.setFileMode(QFileDialog::ExistingFiles);
306 dialog.setNameFilter(tr(
"Libraries (*.dll *.so *.dylib)"));
307 QStringList fileNames;
311 fileNames = dialog.selectedFiles();
314 foreach (QString filePath, fileNames)
323 ArmarXMainWindow::loadPlugins(
const QStringList& fileNames)
325 const QStringList suffixes = {
326 "_qt_plugin.so",
"GuiPlugin.so",
"GuiPlugin.dll",
"GuiPlugin.dylib"};
327 QStringList guiFiles;
328 for (
const QString& fileName : fileNames)
331 for (
const QString& suffix : suffixes)
333 if (fileName.endsWith(suffix))
335 guiFiles.push_back(fileName);
341 auto start = IceUtil::Time::now();
342 for (
int i = 0; i < guiFiles.size(); i++)
344 QString fileName = guiFiles.at(i);
345 if ((IceUtil::Time::now() - start).toSeconds() >= 2)
348 splashSceen->showMessage(splashscreenPrefix + fileName,
349 Qt::AlignJustify | Qt::AlignBottom);
350 qApp->processEvents();
354 updateAvailableWidgetList();
358 ArmarXMainWindow::addActionToToolBar(QAction* action,
bool allowText)
360 QToolButton* button =
new QToolButton(ui->toolBar);
362 std::optional<QSize> textSize;
365 button->setToolButtonStyle(Qt::ToolButtonStyle::ToolButtonTextBesideIcon);
366 button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
369 button->setText(action->text());
370 textSize = button->sizeHint();
373 button->setDefaultAction(action);
374 if (not action->icon().isNull())
376 const QSize maxSize{256, 24};
377 const QSize iconSize = action->icon().actualSize(maxSize);
380 button->setIconSize(iconSize);
381 button->setFixedSize(textSize.has_value() ? QSize{textSize->width() + iconSize.width(),
385 return ui->toolBar->addWidget(button);
393 QString dir = QString::fromStdString(libPaths);
394 dir = QDir::cleanPath(dir);
402 auto widgetUsageHistory = mainSettings.value(
"WidgetUsageHistory").toList();
403 std::map<QString, int> widgetUsage;
404 for (
auto& widgetName : widgetUsageHistory)
406 if (widgetUsage.count(widgetName.toString()) == 0)
408 widgetUsage[widgetName.toString()] = 1;
412 widgetUsage[widgetName.toString()] += 1;
415 std::multimap<int, QString> ranking;
416 for (
auto it = widgetUsage.begin(); it != widgetUsage.end(); it++)
418 ranking.insert(std::make_pair(it->second, it->first));
421 const int favCount = mainSettings.value(
"FavoriteWidgetCount", 6).toInt();
422 QStringList favoriteWidgetNames;
423 for (
auto it = ranking.rbegin(); it != ranking.rend() && i < favCount; it++)
425 auto& widgetName = it->second;
426 if (!mainWidgetNames.contains(widgetName))
428 favoriteWidgetNames << widgetName;
432 return favoriteWidgetNames;
438 QSet<QString> pluginDirs;
439 splashSceen->showMessage(splashscreenPrefix + packageName,
440 Qt::AlignJustify | Qt::AlignBottom);
441 qApp->processEvents();
443 ARMARX_INFO <<
"Looking for gui plugins in package " << packageName;
445 pluginDirs.insert(dir);
446 loadedPackages << packageName;
447 loadPlugins(pluginDirs,
false);
451 ArmarXMainWindow::loadPlugins(
const QString& pluginDir,
bool searchRecursive)
454 dirs.insert(pluginDir);
455 loadPlugins(dirs, searchRecursive);
459 ArmarXMainWindow::loadPlugins(
const QSet<QString>& pluginDirs,
bool searchRecursive)
466 QList<QDir> directoriesToCheck;
467 QStringList allFileNames;
469 for (
const auto& pluginDir : pluginDirs)
471 directoriesToCheck.push_back(QDir(pluginDir));
473 while (directoriesToCheck.size() > 0)
475 ARMARX_VERBOSE_S <<
"Checking dir : " + directoriesToCheck.front().absolutePath()
477 splashSceen->showMessage(splashscreenPrefix +
478 directoriesToCheck.front().absolutePath(),
479 Qt::AlignJustify | Qt::AlignBottom);
480 qApp->processEvents();
481 QDir currentPluginDir = directoriesToCheck.front();
482 directoriesToCheck.pop_front();
483 QString curPath = currentPluginDir.path();
485 if (curPath.length() == 0)
490 QStringList fileNames = currentPluginDir.entryList(filters, QDir::Files);
492 for (
auto& fileName : fileNames)
494 fileName = currentPluginDir.absoluteFilePath(fileName);
497 allFileNames.append(fileNames);
501 QDirIterator directoryIterator(currentPluginDir.absolutePath(),
503 QDir::Dirs | QDir::NoDotAndDotDot,
504 QDirIterator::Subdirectories);
506 while (directoryIterator.hasNext())
508 directoryIterator.next();
509 directoriesToCheck.push_back(QDir(directoryIterator.filePath()));
515 loadPlugins(allFileNames);
522 return list.contains(widgetName);
528 QFileInfo pathInfo(filePath);
529 QString fileName(pathInfo.fileName());
531 ARMARX_INFO <<
"Plugin Path: " << pathInfo.absoluteFilePath().toStdString()
533 updateAvailableWidgetList();
554 ArmarXMainWindow::closeAllWidgets()
558 OpenWidgetMap listOpenWidgetsTemp = listOpenWidgets;
559 OpenWidgetMap::iterator it = listOpenWidgetsTemp.begin();
561 for (; it != listOpenWidgetsTemp.end(); ++it)
563 ARMARX_INFO <<
"Closing widget " << it.key() <<
" size: " << listOpenWidgetsTemp.size();
564 QDockWidget* w = it.value().first;
582 listOpenWidgets.clear();
584 this->configFilepath =
"";
589 ArmarXMainWindow::closeAllWidgetsWithDialog()
591 QMessageBox dialog(QMessageBox::Question,
592 tr(
"Closing all widgets"),
593 tr(
"Do you really want to close all widgets?"));
607 QDir path(configFilepath);
608 configFilepath = path.absolutePath();
610 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
611 recentlyFiles.removeAll(configFilepath);
612 recentlyFiles.push_front(configFilepath);
614 if (recentlyFiles.size() > 10)
616 recentlyFiles.pop_back();
619 mainSettings.setValue(
"RecentlyFiles", recentlyFiles);
622 std::vector<std::string>
625 return defaultPackageNames;
633 return Viewer3DWidgetPtr::dynamicCast(
646 if (configFilepath.length() == 0)
648 QFileDialog dialog(
this);
649 dialog.setFileMode(QFileDialog::ExistingFile);
650 dialog.setAcceptMode(QFileDialog::AcceptOpen);
651 QStringList nameFilters;
652 nameFilters <<
"ArmarX Gui-Files (*.armarxgui)"
653 <<
"All Files (*.*)";
654 dialog.setNameFilters(nameFilters);
658 if (dialog.selectedFiles().size() == 0)
663 configFilepath = dialog.selectedFiles()[0];
667 ARMARX_INFO <<
"load config dialog canceled" << std::endl;
675 QDir dir(configFilepath);
677 configFilepath = dir.absolutePath();
679 if (!QFile::exists(configFilepath))
682 "' does not exist.");
688 if (showAsOpenGuiConfig)
694 QSettings settings(configFilepath, QSettings::IniFormat);
697 if (settings.allKeys().size() == 0)
700 configFilepath +
"'!");
708 std::sort(packagesStd.begin(),
710 [](
const std::string& lhs,
const std::string& rhs) ->
bool
711 { return simox::alg::to_lower(lhs) < simox::alg::to_lower(rhs); });
713 QStringList packagesToLoad;
715 for (
const auto& pkg : packagesStd)
717 packagesToLoad.push_back(QString::fromStdString(pkg));
721 settings.setValue(
"loadedPackages", packagesToLoad);
725 foreach (QString package, packagesToLoad)
730 QStringList widgetNames = settings.value(
"WidgetCustomNames").toStringList();
731 foreach (QString widgetCustomName, widgetNames)
733 settings.beginGroup(widgetCustomName);
736 ARMARX_INFO <<
"Creating widget " << settings.value(
"WidgetBaseName").toString()
737 <<
"," << widgetCustomName;
739 settings.value(
"WidgetBaseName").toString(), widgetCustomName, &settings);
743 qApp->processEvents();
747 auto geometryByteArray = settings.value(
"MainWindowGeometry").toByteArray();
748 if (geometryByteArray.size() > 0)
751 restoreGeometry(geometryByteArray);
755 QRect geometry = settings.value(
"MainWindowGeometry").toRect();
756 setGeometry(geometry);
759 if (!restoreState(settings.value(
"DockWidgetsState").toByteArray()))
764 foreach (QString widgetCustomName, widgetNames)
766 settings.beginGroup(widgetCustomName);
767 OpenWidgetMap::iterator it = listOpenWidgets.find(widgetCustomName);
769 if (it != listOpenWidgets.end())
771 it->first->resize(settings.value(
"widgetWidth").toInt(),
772 settings.value(
"widgetHeight").toInt());
777 if (showAsOpenGuiConfig)
779 this->configFilepath = configFilepath;
782 updateOpenWidgetList();
783 QFileInfo file(configFilepath);
784 statusBar()->showMessage(
"'" + file.fileName() +
"' loaded.", 10000);
788 ArmarXMainWindow::saveGuiConfig()
790 if (configFilepath.length() == 0)
792 QFileDialog dialog(
this);
793 dialog.setFileMode(QFileDialog::AnyFile);
794 dialog.setAcceptMode(QFileDialog::AcceptSave);
795 QStringList nameFilters;
796 nameFilters <<
"ArmarX Gui-Files (*.armarxgui)"
797 <<
"All Files (*.*)";
798 dialog.setNameFilters(nameFilters);
802 if (dialog.selectedFiles().size() == 0)
807 QString file = dialog.selectedFiles()[0];
808 QFileInfo fileInfo(file);
810 if (fileInfo.suffix().isEmpty())
812 file +=
".armarxgui";
815 configFilepath = file;
824 QSettings settings(configFilepath, QSettings::IniFormat);
830 settings.setValue(
"loadedPackages", loadedPackages);
831 settings.setValue(
"MainWindowGeometry", geometry());
832 settings.setValue(
"DockWidgetsState", saveState());
833 QStringList widgetCustomNames;
834 OpenWidgetMap::iterator it = listOpenWidgets.begin();
836 for (; it != listOpenWidgets.end(); it++)
838 QString prefix = it.value().first->objectName();
840 settings.beginGroup(prefix);
845 settings.setValue(
"WidgetBaseName", w->getWidgetName());
846 settings.setValue(
"widgetWidth", w->getWidget()->width());
847 settings.setValue(
"widgetHeight", w->getWidget()->height());
848 w->saveSettings(&settings);
849 widgetCustomNames.push_back(prefix);
859 settings.setValue(
"WidgetCustomNames", widgetCustomNames);
860 ARMARX_INFO <<
"Saved config to " << configFilepath;
866 QFileInfo file(configFilepath);
867 statusBar()->showMessage(
"'" + file.fileName() +
"' saved.", 10000);
871 ArmarXMainWindow::saveGuiConfigAs()
873 configFilepath.clear();
880 if (filepath.length() > 0)
883 std::filesystem::path file(filepath.toStdString());
886 setWindowTitle(guiWindowBaseName +
" - " +
887 QString::fromStdString(file.filename().string()) +
" in " +
888 path.absolutePath());
892 setWindowTitle(guiWindowBaseName);
897 ArmarXMainWindow::createArmarXWidget(QString widgetName,
898 QString customInstanceName,
902 if (listOpenWidgets.find(
"Dock" + customInstanceName) != listOpenWidgets.end())
912 if (widgetName ==
"VisionX.PointCloudViewer")
914 ARMARX_INFO <<
"Creating SoQtExaminerViewer for " << widgetName.toStdString();
915 SoQtExaminerViewer(
nullptr,
"", TRUE, SoQtExaminerViewer::BUILD_NONE);
926 auto widgetUsage = mainSettings.value(
"WidgetUsageHistory").toList();
927 widgetUsage.push_back(widgetName);
928 if (widgetUsage.size() > widgetUsageHistoryLength)
930 widgetUsage.pop_front();
932 mainSettings.setValue(
"WidgetUsageHistory", widgetUsage);
937 w->setMainWindow(
this);
938 w->setInstanceName(customInstanceName);
939 w->setTipDialog(tipDialog);
943 w->loadSettings(settings);
945 else if (w->getConfigDialog(
this))
949 ManagedIceObjectPtr::dynamicCast(w->getConfigDialog().data());
953 comp->__setNoDelete(
true);
954 registry->addObject(comp,
false);
957 w->getConfigDialog()->setModal(
true);
959 w->getConfigDialog().data(), SIGNAL(accepted()), w.get(), SLOT(configAccepted()));
965 w->getConfigDialog().data(), SIGNAL(rejected()), w.get(), SLOT(configRejected()));
971 pendingWidgets.push_back(w);
972 w->getConfigDialog()->show();
973 w->getConfigDialog()->raise();
974 w->getConfigDialog()->activateWindow();
980 addArmarXWidget(w, !settings);
986 bool createViewerWidget)
988 for (
unsigned int i = 0; i < pendingWidgets.size(); ++i)
990 if (pendingWidgets[i].get() == newWidgetController.get())
992 pendingWidgets.erase(pendingWidgets.begin() + i);
997 QString widgetName = newWidgetController->getWidgetName();
998 QString customInstanceName = newWidgetController->getInstanceName();
1000 if (listOpenWidgets.find(customInstanceName) != listOpenWidgets.end())
1006 assert(widgetName == newWidgetController->getWidgetName());
1007 ArmarXDockWidget* dockWidget =
1008 new ArmarXDockWidget(customInstanceName, newWidgetController);
1010 connect(dockWidget, SIGNAL(destroyed(QObject*)),
this, SLOT(removeArmarXWidget(QObject*)));
1012 dockWidget->setArmarXWidget(newWidgetController->getWidget());
1013 dockWidget->setObjectName(customInstanceName);
1014 StatusDockWidgetTitleBar* customTitlebar =
new StatusDockWidgetTitleBar(dockWidget,
this);
1015 dockWidget->setTitleBarWidget(customTitlebar);
1016 customTitlebar->addCustomWidget(newWidgetController->getCustomTitlebarWidget(dockWidget));
1018 if (listOpenWidgets.find(dockWidget->objectName()) != listOpenWidgets.end())
1021 customInstanceName +
"' already exists.");
1026 QDockWidget* biggestOpenDockWidget = getBiggestOpenWidget();
1027 listOpenWidgets[customInstanceName] =
1028 qMakePair<QDockWidget*, ArmarXWidgetControllerPtr>(dockWidget, newWidgetController);
1029 addDockWidget(Qt::RightDockWidgetArea, dockWidget);
1030 newWidgetController->postDocking();
1032 QSize widgetStartSize = newWidgetController->getWidget()->size();
1033 if (widgetStartSize.width() * widgetStartSize.height() >= 400 * 400)
1034 if (biggestOpenDockWidget)
1036 tabifyDockWidget(biggestOpenDockWidget, dockWidget);
1040 dockWidget->raise();
1042 updateOpenWidgetList();
1045 newWidgetController->setMutex3D(mutex3d);
1047 QApplication::instance()
1053 registry->addObject(comp,
false);
1055 int timeoutMs = 30000;
1057 if (!comp->getObjectScheduler()->waitForObjectState(eManagedIceObjectInitialized,
1061 <<
" was not connected to Ice after " << timeoutMs / 1000
1062 <<
" seconds" << std::endl;
1069 SoNode* node = newWidgetController->getScene();
1075 OpenWidgetMap::Iterator it = listOpenWidgets.begin();
1077 for (; it != listOpenWidgets.end(); it++)
1079 viewerInstance = Viewer3DWidgetPtr::dynamicCast(it.value().second);
1087 if (!viewerInstance && createViewerWidget)
1091 viewerInstance = setupViewerWidget();
1094 SoSeparator* sep =
new SoSeparator;
1097 SoPerspectiveCamera* camera =
new SoPerspectiveCamera;
1099 sep->addChild(camera);
1100 sep->addChild(node);
1102 viewer3DMap[customInstanceName] = {sep, newWidgetController->getSceneConfigDialog()};
1107 return newWidgetController;
1113 for (
unsigned int i = 0; i < pendingWidgets.size(); ++i)
1115 if (pendingWidgets[i].get() == newWidgetController.get())
1117 pendingWidgets.erase(pendingWidgets.begin() + i);
1124 ArmarXMainWindow::removeArmarXWidget(QObject* widget)
1126 ARMARX_DEBUG <<
"removing widgetname: " << widget->objectName();
1127 QDockWidget* dockWidget = qobject_cast<QDockWidget*>(widget);
1130 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1132 for (; it != listOpenWidgets.end(); it++)
1134 if (widget == it.value().first)
1139 if (it.value().second)
1141 widgetName = it.value().second->getInstanceName();
1145 if (it.value().first)
1147 widgetName = it.value().first->objectName();
1152 listOpenWidgets.erase(it);
1153 updateOpenWidgetList();
1156 if (viewer3DMap.contains(widgetName) )
1158 auto& node = viewer3DMap[widgetName].node;
1165 ARMARX_DEBUG <<
"Removing from 3D list: " << widgetName;
1166 viewer3DMap.remove(widgetName);
1174 removeDockWidget(dockWidget);
1177 QPointer<QDockWidget>
1178 ArmarXMainWindow::getBiggestOpenWidget()
1180 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1181 QPointer<QDockWidget> biggestWidget = NULL;
1183 for (; it != listOpenWidgets.end(); it++)
1185 QDockWidget* dockWidget = it.value().first;
1187 if (!biggestWidget ||
1188 dockWidget->size().width() * dockWidget->size().height() >
1189 biggestWidget->size().width() * biggestWidget->size().height())
1191 biggestWidget = dockWidget;
1195 return biggestWidget;
1199 ArmarXMainWindow::getCategoryMenu(
const std::string& categoryString,
1205 if (items.size() <= 1)
1210 auto actions = menu->actions();
1212 for (QAction* action : actions)
1214 if (action->text().toStdString() == *items.begin())
1216 items.erase(items.begin(), items.begin() + 1);
1217 std::string rest = simox::alg::join(items,
".");
1219 if (!action->menu())
1221 action->setMenu(
new QMenu(QString::fromStdString(*items.begin()),
this));
1224 if (action->icon().isNull() && !categoryIcon.isNull())
1226 action->setIcon(categoryIcon);
1227 action->setIconVisibleInMenu(
true);
1230 return getCategoryMenu(rest, action->menu(), categoryIcon);
1234 return menu->addMenu(QString::fromStdString(*items.begin()));
1238 ArmarXMainWindow::updateAvailableWidgetList()
1240 ui->menuAdd_Widget->clear();
1242 searchField =
new QLineEdit(ui->menuAdd_Widget);
1243 searchField->setToolTip(
"Search and add a new widget from all loaded ArmarX Gui Plugins");
1244 searchField->setMaximumWidth(250);
1245 searchField->setPlaceholderText(
"Widget Search");
1247 QStringList widgetNameList;
1249 ui->toolBar->clear();
1252 ui->toolBar->addWidget(emergencyStopWidget->getButtonWidget());
1255 ui->toolBar->addWidget(batteryWidget->getBatteryWidget());
1257 ui->toolBar->addSeparator();
1259 ui->toolBar->setIconSize(QSize(256, 24));
1261 QMap<QString, QAction*> actionsForToolBar;
1266 QString widgetName = fullWidgetName;
1267 widgetName = widgetName.remove(0, widgetName.lastIndexOf(
".") + 1);
1268 widgetNameList << fullWidgetName;
1272 categoryIcon = widgetInfo->getCategoryIcon();
1282 getCategoryMenu(fullWidgetName.toStdString(), ui->menuAdd_Widget, categoryIcon);
1283 AddArmarXWidgetAction* action =
new AddArmarXWidgetAction(widgetName, menu,
this);
1287 widgetIcon = widgetInfo->getIcon();
1296 action->setIcon(widgetIcon);
1297 action->setIconVisibleInMenu(
true);
1299 action->setData(fullWidgetName);
1300 menu->addAction(action);
1302 if (mainWidgetNames.contains(fullWidgetName))
1304 actionsForToolBar[fullWidgetName] = action;
1306 actionList[fullWidgetName] = action;
1308 action, SIGNAL(triggered()), action, SLOT(addArmarXWidget()), Qt::UniqueConnection);
1310 SIGNAL(clicked(QString, QString)),
1312 SLOT(createArmarXWidget(QString, QString)),
1313 Qt::UniqueConnection);
1317 for (
const QString& widgetName : mainWidgetNames)
1319 if (QAction* action = actionsForToolBar.value(widgetName))
1321 const bool allowText =
false;
1322 addActionToToolBar(action, allowText);
1325 addArVizGodotIcon();
1327 AddArmarXWidgetAction* completerAction =
1328 new AddArmarXWidgetAction(
"", ui->menuAdd_Widget,
this);
1329 InfixCompleter* completer =
new InfixCompleter(widgetNameList, searchField);
1331 searchField, SIGNAL(textEdited(QString)), completer, SLOT(setCompletionInfix(QString)));
1334 connect(completerAction, SIGNAL(accepted()), searchField, SLOT(clear()));
1335 connect(completerAction,
1336 SIGNAL(clicked(QString, QString)),
1338 SLOT(createArmarXWidget(QString, QString)),
1339 Qt::UniqueConnection);
1340 searchField->setCompleter(completer);
1342 ui->toolBar->addSeparator();
1343 ui->toolBar->addWidget(searchField);
1346 QString::fromUtf8(
"://icons/edit-add.ico"), QSize(), QIcon::Normal,
QIcon::Off);
1347 openWidgetButton =
new QToolButton(
this);
1348 openWidgetButton->setEnabled(
false);
1349 openWidgetButton->setIcon(icon);
1350 openWidgetButton->setFixedSize({24, 24});
1351 openWidgetButton->setToolTip(
"Open selected widget");
1352 connect(openWidgetButton,
1355 SLOT(openWidgetButtonClicked()),
1356 Qt::UniqueConnection);
1357 ui->toolBar->addWidget(openWidgetButton);
1358 connect(searchField,
1359 SIGNAL(textChanged(QString)),
1361 SLOT(updateOpenWidgetButtonStatus(QString)),
1362 Qt::UniqueConnection);
1364 connect(searchField,
1365 SIGNAL(returnPressed()),
1367 SLOT(openWidgetButtonClicked()),
1368 Qt::UniqueConnection);
1371 ui->toolBar->addSeparator();
1372 favoritesLabel =
new QLabel(
"Favorites:");
1373 favoritesLabel->setToolTip(
"The favorites are generated from the usage frequency over "
1374 "the last X widget creations."
1375 " Rightclick to change the number of displayed favorites");
1376 ui->toolBar->addWidget(favoritesLabel);
1378 favoritesLabel->setContextMenuPolicy(Qt::CustomContextMenu);
1379 connect(favoritesLabel,
1380 SIGNAL(customContextMenuRequested(
const QPoint&)),
1382 SLOT(onContextMenuFavoritesRequested(
const QPoint&)));
1384 updatefavoriteActions();
1388 ArmarXMainWindow::updateOpenWidgetList()
1390 ui->menuWindows->clear();
1391 QAction* closeAllAction =
new QAction(
"Close all widgets", ui->menuWindows);
1392 connect(closeAllAction, SIGNAL(triggered()),
this, SLOT(closeAllWidgetsWithDialog()));
1393 ui->menuWindows->addAction(closeAllAction);
1394 ui->menuWindows->addSeparator();
1396 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1398 for (; it != listOpenWidgets.end(); it++)
1400 QDockWidget* dockWidget = it.value().first;
1401 QAction* action =
new QAction(dockWidget->objectName(), ui->menuWindows);
1402 action->setCheckable(
true);
1403 action->setChecked(!dockWidget->isHidden());
1405 connect(action, SIGNAL(toggled(
bool)), dockWidget, SLOT(setVisible(
bool)));
1407 ui->menuWindows->addAction(action);
1412 ArmarXMainWindow::addArVizGodotIcon()
1414 const char* path = std::getenv(
"arviz_godot_DIR");
1415 if (path ==
nullptr)
1420 std::filesystem::path buildDirectory(path);
1421 std::filesystem::path mainDirectory = buildDirectory.parent_path();
1423 std::filesystem::path binaryPath = buildDirectory /
"bin" /
"arviz-godot";
1424 std::filesystem::path iconPath =
1425 mainDirectory /
"source" /
"arviz_godot" /
"project" /
"icon.png";
1427 if (not std::filesystem::exists(binaryPath) or not std::filesystem::exists(iconPath))
1432 QIcon icon(iconPath.c_str());
1433 QString name(
"ArViz Godot");
1435 QAction* action =
new QAction(icon, name,
this);
1437 bool allowText =
false;
1438 addActionToToolBar(action, allowText);
1440 auto slot = [
this, binaryPath]()
1442 if (not std::filesystem::exists(binaryPath))
1444 QMessageBox errorBox;
1446 nullptr,
"Error",
"The ArViz Godot executable is no longer available.");
1466 int null = open(
"/dev/null", O_WRONLY);
1467 dup2(
null, STDOUT_FILENO);
1468 dup2(
null, STDERR_FILENO);
1470 execl(binaryPath.c_str(),
"arviz-godot",
nullptr);
1474 connect(action, &QAction::triggered,
this,
slot, Qt::UniqueConnection);
1480 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
1481 QMenu* menu = ui->menuRecently_Opened_Files;
1482 auto actions = menu->actions();
1484 for (QAction* action : actions)
1486 if (!action->isCheckable() && !action->isSeparator())
1488 menu->removeAction(action);
1492 foreach (QString file, recentlyFiles)
1497 action->setCheckable(
false);
1498 connect(action, SIGNAL(triggered()), action, SLOT(openFile()));
1499 menu->addAction(action);
1504 ArmarXMainWindow::updateStatusOfOpenWidgets()
1506 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1508 for (; it != listOpenWidgets.end(); it++)
1510 QDockWidget* dockWidget = it.value().first;
1513 qobject_cast<StatusDockWidgetTitleBar*>(dockWidget->titleBarWidget());
1515 if (titlebar && comp)
1518 ManagedIceObjectConnectivity con = comp->getConnectivity();
1519 QStringList dependencies;
1521 for (DependencyMap::iterator i = con.dependencies.begin();
1522 i != con.dependencies.end();
1525 ManagedIceObjectDependencyBasePtr& dep = i->second;
1527 if (!dep->getResolved() || comp->getState() == eManagedIceObjectStarted)
1529 dependencies << QString::fromStdString(dep->getName());
1533 titlebar->
changeStatus((ManagedIceObjectState)comp->getState(), dependencies);
1539 ArmarXMainWindow::enterFullscreenMode()
1542 ui->toolBar->hide();
1543 ui->menubar->hide();
1544 ui->statusbar->hide();
1547 leaveFullScreenActionF11 =
new QAction(
this);
1548 leaveFullScreenActionF11->setShortcut(Qt::Key_F11);
1549 connect(leaveFullScreenActionF11, SIGNAL(triggered()),
this, SLOT(leaveFullscreenMode()));
1550 addAction(leaveFullScreenActionF11);
1552 leaveFullScreenActionEsc =
new QAction(
this);
1553 leaveFullScreenActionEsc->setShortcut(Qt::Key_Escape);
1554 connect(leaveFullScreenActionEsc, SIGNAL(triggered()),
this, SLOT(leaveFullscreenMode()));
1555 addAction(leaveFullScreenActionEsc);
1559 ArmarXMainWindow::leaveFullscreenMode()
1562 removeAction(leaveFullScreenActionF11);
1563 leaveFullScreenActionF11 =
nullptr;
1565 removeAction(leaveFullScreenActionEsc);
1566 leaveFullScreenActionEsc =
nullptr;
1569 ui->toolBar->show();
1570 ui->menubar->show();
1571 ui->statusbar->show();
1575 ArmarXMainWindow::toggleWidgetLock()
1577 QList<ArmarXDockWidget*> dockWidgets = findChildren<ArmarXDockWidget*>();
1581 for (
auto& widget : dockWidgets)
1583 widget->unlockWidget();
1589 for (
auto& widget : dockWidgets)
1591 widget->lockWidget();
1595 widgetsLocked = !widgetsLocked;
1605 QAction(widgetName, parent), mainGui(mainGui)
1619 if (widgetName.isEmpty())
1621 QLineEdit* edit = qobject_cast<QLineEdit*>(sender());
1624 widgetName = edit->text();
1632 setText(widgetName);
1633 setData(widgetName);
1645 dialog->setModal(
true);
1664 scrollArea =
new QScrollArea();
1665 scrollArea->setWidgetResizable(
true);
1667 QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1668 scrollArea->setSizePolicy(sizePolicy);
1669 setWidget(scrollArea);
1671 savedTitleBar =
nullptr;
1683 scrollArea->setWidget(widget);
1699 emit destroyed(
this);
1707 ARMARX_INFO <<
"Locking widget: " << objectName();
1708 savedTitleBar = titleBarWidget();
1709 setTitleBarWidget(
new QWidget());
1719 ARMARX_INFO <<
"Unlocking widget: " << objectName();
1720 if (savedTitleBar !=
nullptr)
1722 QWidget* old = titleBarWidget();
1723 setTitleBarWidget(savedTitleBar);
1724 savedTitleBar =
nullptr;
1739 QAction(text, parent), mainGui(mainGui)
1753 armarx::ArmarXMainWindow::on_actionClear_tip_blacklist_triggered()
1755 tipDialog->setBlackListedStrings(QStringList());
1756 mainSettings.setValue(CONFIG_BLACKLISTED_TIPS, tipDialog->getBlackListedStrings());
1757 mainSettings.sync();
1762 armarx::ArmarXMainWindow::on_actionAbout_triggered()
1766 "ArmarX Graphical User Interface",
1767 QString(
"ArmarX is being developed at the High Performance Humanoid Technologies (H2T) "
1768 "lab at the Karlsruhe Institute of Technology (KIT)\nCopyright H2T, KIT, ") +
1769 QString(&__DATE__[7]) +
1774 armarx::ArmarXMainWindow::on_actionLoadLastConfig_toggled(
bool toggled)
1776 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG, toggled);
1777 mainSettings.sync();
1781 armarx::ArmarXMainWindow::on_actionArmarX_Documentation_triggered()
1783 QDesktopServices::openUrl(QUrl(
"http://armarx.humanoids.kit.edu/"));
1787 armarx::ArmarXMainWindow::on_actionOpen_Use_Case_triggered()
1789 guiUseCaseSelector->setCancelButtonText(
"Cancel");
1790 if (guiUseCaseSelector->exec() == QDialog::Accepted)
1792 QString path = guiUseCaseSelector->getSelectedConfigFilePath();
1794 if (!path.isEmpty())
1796 loadGuiConfig(path,
false);
1799 mainSettings.setValue(
"DoNotShowUseCaseDialog", guiUseCaseSelector->getDoNotShowAgain());
1803 armarx::ArmarXMainWindow::on_actionClear_plugin_cache_triggered()
1805 pluginCache.clearCacheFile();
1809 ArmarXMainWindow::updateOpenWidgetButtonStatus(QString widgetName)
1815 ArmarXMainWindow::openWidgetButtonClicked()
1817 addWidgetAction->
triggered(searchField->text());
1821 ArmarXMainWindow::onContextMenuFavoritesRequested(
const QPoint& pos)
1825 auto numberOfFavIcons =
new QSpinBox(&menu);
1826 numberOfFavIcons->setRange(1, 100);
1827 numberOfFavIcons->setSingleStep(1);
1828 numberOfFavIcons->setValue(mainSettings.value(
"FavoriteWidgetCount", 6).toInt());
1829 numberOfFavIcons->setToolTip(
"Max number of favorites");
1830 connect(numberOfFavIcons,
1831 SIGNAL(valueChanged(
int)),
1833 SLOT(onNumberOfMaxFavoritesChanged(
int)));
1835 QWidgetAction* action =
new QWidgetAction{&menu};
1836 action->setDefaultWidget(numberOfFavIcons);
1837 menu.addAction(action);
1838 menu.exec(favoritesLabel->mapToGlobal(pos));
1842 ArmarXMainWindow::onNumberOfMaxFavoritesChanged(
int i)
1844 mainSettings.setValue(
"FavoriteWidgetCount", i);
1845 updatefavoriteActions();
1849 ArmarXMainWindow::updatefavoriteActions()
1852 if (favoriteActionWidgetNames ==
list
1859 favoriteActionWidgetNames =
list;
1860 for (
auto* action : favoriteActions)
1862 ui->toolBar->removeAction(action);
1863 action->deleteLater();
1865 favoriteActions.clear();
1866 for (
auto widgetName : favoriteActionWidgetNames)
1868 if (actionList.contains(widgetName))
1870 bool allowText =
true;
1871 favoriteActions.emplace_back(addActionToToolBar(actionList[widgetName], allowText));