26 #include <ArmarXGui/applications/ArmarXGui/ui_ArmarXMainWindow.h>
46 #include <sys/types.h>
50 #include <QActionGroup>
53 #include <QDesktopServices>
55 #include <QDialogButtonBox>
57 #include <QFileDialog>
58 #include <QGridLayout>
59 #include <QHBoxLayout>
61 #include <QInputDialog>
65 #include <QListWidget>
68 #include <QMessageBox>
69 #include <QModelIndex>
72 #include <QPlainTextEdit>
73 #include <QPluginLoader>
74 #include <QProxyStyle>
75 #include <QPushButton>
76 #include <QScrollArea>
77 #include <QSignalMapper>
80 #include <QStackedWidget>
81 #include <QStringList>
82 #include <QStringListModel>
84 #include <QToolButton>
86 #include <QWidgetAction>
87 #include <QtCore/QDirIterator>
88 #include <QtSvg/QSvgRenderer>
90 #include <SimoxUtility/algorithm/string/string_tools.h>
97 #include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
98 #include <Inventor/nodes/SoPerspectiveCamera.h>
109 static const char* CONFIG_LOAD_LAST_CONFIG =
"LoadLastConfig";
110 static const char* CONFIG_BLACKLISTED_TIPS =
"BlacklistedTips";
113 const std::vector<std::string>& packages,
114 const QString& configToLoad,
115 bool disablePreloading) :
118 defaultPackageNames(packages),
119 widgetsLocked(false),
122 mainSettings(QString(settingsFile.c_str()), QSettings::NativeFormat)
125 QMainWindow::separator {
126 width: 3px; /* when vertical */
127 height: 3px; /* when horizontal */
129 QMainWindow::separator:hover {
134 mainWidgetNames = QStringList() << "Meta.LogViewer"
135 <<
"Meta.SystemStateMonitor"
136 <<
"Meta.ScenarioManager"
137 <<
"Statecharts.StatechartEditor"
138 <<
"ArMem.MemoryViewer";
141 QPixmap pm(QString(
"://icons/ArmarX-Splashscreen.png"));
142 splashSceen =
new QSplashScreen(pm);
145 ui = new ::Ui::ArmarXMainWindow();
146 mutex3d = std::make_shared<std::recursive_mutex>();
148 new ArmarXWidgetInfo(ArmarXComponentWidgetController::createInstance<Viewer3DWidget>,
154 QString username = qgetenv(
"USER");
155 if (username.isEmpty())
157 username = qgetenv(
"USERNAME");
161 setWindowTitle(guiWindowBaseName);
162 this->registry = registry;
163 setAttribute(Qt::WA_QuitOnClose);
166 setCentralWidget(NULL);
169 tipDialog->setBlackListedStrings(
170 mainSettings.value(CONFIG_BLACKLISTED_TIPS).toStringList());
171 ui->actionLoadLastConfig->setChecked(mainSettings.value(CONFIG_LOAD_LAST_CONFIG).toBool());
174 connect(addWidgetAction,
175 SIGNAL(clicked(QString, QString)),
177 SLOT(createArmarXWidget(QString, QString)),
178 Qt::UniqueConnection);
181 connect(ui->actionLoadPlugin, SIGNAL(triggered()),
this, SLOT(pluginDialog()));
182 connect(ui->actionSave_Gui, SIGNAL(triggered()),
this, SLOT(saveGuiConfig()));
183 connect(ui->actionLoad_Gui_Config, SIGNAL(triggered()),
this, SLOT(
loadGuiConfig()));
184 connect(ui->actionQuit, SIGNAL(triggered()),
this, SLOT(close()));
185 connect(ui->actionSave_Gui_as, SIGNAL(triggered()),
this, SLOT(saveGuiConfigAs()));
186 connect(ui->actionFullscreen, SIGNAL(triggered()),
this, SLOT(enterFullscreenMode()));
187 connect(ui->actionLock_Widgets, SIGNAL(triggered()),
this, SLOT(toggleWidgetLock()));
190 emergencyStopWidget = EmergencyStopWidgetPtr::dynamicCast(
191 ArmarXComponentWidgetController::createInstance<EmergencyStopWidget>());
192 this->registry->addObject(ManagedIceObjectPtr::dynamicCast(emergencyStopWidget));
195 QSet<QString> pluginDirs;
197 for (
const std::string& packageName : packages)
201 loadPlugins(pluginDirs,
false);
202 if (!disablePreloading)
211 connectionStatusTimer =
new QTimer(
this);
212 connect(connectionStatusTimer, SIGNAL(timeout()),
this, SLOT(updateStatusOfOpenWidgets()));
213 connectionStatusTimer->start(300);
215 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
216 splashSceen->finish(
this);
219 this, mainSettings.value(
"DoNotShowUseCaseDialog").toBool(),
this);
222 if (!configToLoad.isEmpty())
226 else if (!mainSettings.value(
"DoNotShowUseCaseDialog").toBool() &&
227 guiUseCaseSelector->exec() == QDialog::Accepted)
236 else if (recentlyFiles.size() > 0 && mainSettings.value(CONFIG_LOAD_LAST_CONFIG).toBool())
239 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG,
false);
242 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG, ui->actionLoadLastConfig->isChecked());
247 QStringList defaultWidgets{
"Meta.LogViewer"};
248 for (
auto& widgetName : defaultWidgets)
252 createArmarXWidget(widgetName, widgetName);
257 mainSettings.setValue(
"DoNotShowUseCaseDialog", guiUseCaseSelector->
getDoNotShowAgain());
263 connectionStatusTimer->stop();
264 mainSettings.setValue(CONFIG_BLACKLISTED_TIPS, tipDialog->getBlackListedStrings());
270 ArmarXMainWindow::removeViewerWidget(QObject* widget)
279 removeArmarXWidget(widget);
283 ArmarXMainWindow::setupViewerWidget()
287 return Viewer3DWidgetPtr::dynamicCast(
295 viewer->setMutex3D(mutex3d);
301 ArmarXMainWindow::pluginDialog()
303 QFileDialog dialog(
this);
304 dialog.setFileMode(QFileDialog::ExistingFiles);
305 dialog.setNameFilter(tr(
"Libraries (*.dll *.so *.dylib)"));
306 QStringList fileNames;
310 fileNames = dialog.selectedFiles();
313 foreach (QString filePath, fileNames)
322 ArmarXMainWindow::loadPlugins(
const QStringList& fileNames)
324 const QStringList suffixes = {
325 "_qt_plugin.so",
"GuiPlugin.so",
"GuiPlugin.dll",
"GuiPlugin.dylib"};
326 QStringList guiFiles;
327 for (
const QString& fileName : fileNames)
330 for (
const QString& suffix : suffixes)
332 if (fileName.endsWith(suffix))
334 guiFiles.push_back(fileName);
340 auto start = IceUtil::Time::now();
341 for (
int i = 0; i < guiFiles.size(); i++)
343 QString fileName = guiFiles.at(i);
344 if ((IceUtil::Time::now() - start).toSeconds() >= 2)
347 splashSceen->showMessage(splashscreenPrefix + fileName,
348 Qt::AlignJustify | Qt::AlignBottom);
349 qApp->processEvents();
353 updateAvailableWidgetList();
357 ArmarXMainWindow::addActionToToolBar(QAction* action,
bool allowText)
359 QToolButton* button =
new QToolButton(ui->toolBar);
361 std::optional<QSize> textSize;
364 button->setToolButtonStyle(Qt::ToolButtonStyle::ToolButtonTextBesideIcon);
365 button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
368 button->setText(action->text());
369 textSize = button->sizeHint();
372 button->setDefaultAction(action);
373 if (not action->icon().isNull())
375 const QSize maxSize{256, 24};
376 const QSize iconSize = action->icon().actualSize(maxSize);
379 button->setIconSize(iconSize);
380 button->setFixedSize(textSize.has_value() ? QSize{textSize->width() + iconSize.width(),
384 return ui->toolBar->addWidget(button);
392 QString dir = QString::fromStdString(libPaths);
393 dir = QDir::cleanPath(dir);
401 auto widgetUsageHistory = mainSettings.value(
"WidgetUsageHistory").toList();
402 std::map<QString, int> widgetUsage;
403 for (
auto& widgetName : widgetUsageHistory)
405 if (widgetUsage.count(widgetName.toString()) == 0)
407 widgetUsage[widgetName.toString()] = 1;
411 widgetUsage[widgetName.toString()] += 1;
414 std::multimap<int, QString> ranking;
415 for (
auto it = widgetUsage.begin(); it != widgetUsage.end(); it++)
417 ranking.insert(std::make_pair(it->second, it->first));
420 const int favCount = mainSettings.value(
"FavoriteWidgetCount", 6).toInt();
421 QStringList favoriteWidgetNames;
422 for (
auto it = ranking.rbegin(); it != ranking.rend() && i < favCount; it++)
424 auto& widgetName = it->second;
425 if (!mainWidgetNames.contains(widgetName))
427 favoriteWidgetNames << widgetName;
431 return favoriteWidgetNames;
437 QSet<QString> pluginDirs;
438 splashSceen->showMessage(splashscreenPrefix + packageName,
439 Qt::AlignJustify | Qt::AlignBottom);
440 qApp->processEvents();
442 ARMARX_INFO <<
"Looking for gui plugins in package " << packageName;
444 pluginDirs.insert(dir);
445 loadedPackages << packageName;
446 loadPlugins(pluginDirs,
false);
450 ArmarXMainWindow::loadPlugins(
const QString& pluginDir,
bool searchRecursive)
453 dirs.insert(pluginDir);
454 loadPlugins(dirs, searchRecursive);
458 ArmarXMainWindow::loadPlugins(
const QSet<QString>& pluginDirs,
bool searchRecursive)
465 QList<QDir> directoriesToCheck;
466 QStringList allFileNames;
468 for (
const auto& pluginDir : pluginDirs)
470 directoriesToCheck.push_back(QDir(pluginDir));
472 while (directoriesToCheck.size() > 0)
474 ARMARX_VERBOSE_S <<
"Checking dir : " + directoriesToCheck.front().absolutePath()
476 splashSceen->showMessage(splashscreenPrefix +
477 directoriesToCheck.front().absolutePath(),
478 Qt::AlignJustify | Qt::AlignBottom);
479 qApp->processEvents();
480 QDir currentPluginDir = directoriesToCheck.front();
481 directoriesToCheck.pop_front();
482 QString curPath = currentPluginDir.path();
484 if (curPath.length() == 0)
489 QStringList fileNames = currentPluginDir.entryList(filters, QDir::Files);
491 for (
auto& fileName : fileNames)
493 fileName = currentPluginDir.absoluteFilePath(fileName);
496 allFileNames.append(fileNames);
500 QDirIterator directoryIterator(currentPluginDir.absolutePath(),
502 QDir::Dirs | QDir::NoDotAndDotDot,
503 QDirIterator::Subdirectories);
505 while (directoryIterator.hasNext())
507 directoryIterator.next();
508 directoriesToCheck.push_back(QDir(directoryIterator.filePath()));
514 loadPlugins(allFileNames);
521 return list.contains(widgetName);
527 QFileInfo pathInfo(filePath);
528 QString fileName(pathInfo.fileName());
530 ARMARX_INFO <<
"Plugin Path: " << pathInfo.absoluteFilePath().toStdString()
532 updateAvailableWidgetList();
553 ArmarXMainWindow::closeAllWidgets()
557 OpenWidgetMap listOpenWidgetsTemp = listOpenWidgets;
558 OpenWidgetMap::iterator it = listOpenWidgetsTemp.begin();
560 for (; it != listOpenWidgetsTemp.end(); ++it)
562 ARMARX_INFO <<
"Closing widget " << it.key() <<
" size: " << listOpenWidgetsTemp.size();
563 QDockWidget* w = it.value().first;
581 listOpenWidgets.clear();
583 this->configFilepath =
"";
588 ArmarXMainWindow::closeAllWidgetsWithDialog()
590 QMessageBox dialog(QMessageBox::Question,
591 tr(
"Closing all widgets"),
592 tr(
"Do you really want to close all widgets?"));
606 QDir path(configFilepath);
607 configFilepath = path.absolutePath();
609 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
610 recentlyFiles.removeAll(configFilepath);
611 recentlyFiles.push_front(configFilepath);
613 if (recentlyFiles.size() > 10)
615 recentlyFiles.pop_back();
618 mainSettings.setValue(
"RecentlyFiles", recentlyFiles);
621 std::vector<std::string>
624 return defaultPackageNames;
632 return Viewer3DWidgetPtr::dynamicCast(
645 if (configFilepath.length() == 0)
647 QFileDialog dialog(
this);
648 dialog.setFileMode(QFileDialog::ExistingFile);
649 dialog.setAcceptMode(QFileDialog::AcceptOpen);
650 QStringList nameFilters;
651 nameFilters <<
"ArmarX Gui-Files (*.armarxgui)"
652 <<
"All Files (*.*)";
653 dialog.setNameFilters(nameFilters);
657 if (dialog.selectedFiles().size() == 0)
662 configFilepath = dialog.selectedFiles()[0];
666 ARMARX_INFO <<
"load config dialog canceled" << std::endl;
674 QDir dir(configFilepath);
676 configFilepath = dir.absolutePath();
678 if (!QFile::exists(configFilepath))
681 "' does not exist.");
687 if (showAsOpenGuiConfig)
693 QSettings settings(configFilepath, QSettings::IniFormat);
696 if (settings.allKeys().size() == 0)
699 configFilepath +
"'!");
707 std::sort(packagesStd.begin(),
709 [](
const std::string& lhs,
const std::string& rhs) ->
bool
710 { return simox::alg::to_lower(lhs) < simox::alg::to_lower(rhs); });
712 QStringList packagesToLoad;
714 for (
const auto& pkg : packagesStd)
716 packagesToLoad.push_back(QString::fromStdString(pkg));
720 settings.setValue(
"loadedPackages", packagesToLoad);
724 foreach (QString package, packagesToLoad)
729 QStringList widgetNames = settings.value(
"WidgetCustomNames").toStringList();
730 foreach (QString widgetCustomName, widgetNames)
732 settings.beginGroup(widgetCustomName);
735 ARMARX_INFO <<
"Creating widget " << settings.value(
"WidgetBaseName").toString()
736 <<
"," << widgetCustomName;
738 settings.value(
"WidgetBaseName").toString(), widgetCustomName, &settings);
742 qApp->processEvents();
746 auto geometryByteArray = settings.value(
"MainWindowGeometry").toByteArray();
747 if (geometryByteArray.size() > 0)
750 restoreGeometry(geometryByteArray);
754 QRect geometry = settings.value(
"MainWindowGeometry").toRect();
755 setGeometry(geometry);
758 if (!restoreState(settings.value(
"DockWidgetsState").toByteArray()))
763 foreach (QString widgetCustomName, widgetNames)
765 settings.beginGroup(widgetCustomName);
766 OpenWidgetMap::iterator it = listOpenWidgets.find(widgetCustomName);
768 if (it != listOpenWidgets.end())
770 it->first->resize(settings.value(
"widgetWidth").toInt(),
771 settings.value(
"widgetHeight").toInt());
776 if (showAsOpenGuiConfig)
778 this->configFilepath = configFilepath;
781 updateOpenWidgetList();
782 QFileInfo file(configFilepath);
783 statusBar()->showMessage(
"'" + file.fileName() +
"' loaded.", 10000);
787 ArmarXMainWindow::saveGuiConfig()
789 if (configFilepath.length() == 0)
791 QFileDialog dialog(
this);
792 dialog.setFileMode(QFileDialog::AnyFile);
793 dialog.setAcceptMode(QFileDialog::AcceptSave);
794 QStringList nameFilters;
795 nameFilters <<
"ArmarX Gui-Files (*.armarxgui)"
796 <<
"All Files (*.*)";
797 dialog.setNameFilters(nameFilters);
801 if (dialog.selectedFiles().size() == 0)
806 QString file = dialog.selectedFiles()[0];
807 QFileInfo fileInfo(file);
809 if (fileInfo.suffix().isEmpty())
811 file +=
".armarxgui";
814 configFilepath = file;
823 QSettings settings(configFilepath, QSettings::IniFormat);
829 settings.setValue(
"loadedPackages", loadedPackages);
830 settings.setValue(
"MainWindowGeometry", geometry());
831 settings.setValue(
"DockWidgetsState", saveState());
832 QStringList widgetCustomNames;
833 OpenWidgetMap::iterator it = listOpenWidgets.begin();
835 for (; it != listOpenWidgets.end(); it++)
837 QString prefix = it.value().first->objectName();
839 settings.beginGroup(prefix);
844 settings.setValue(
"WidgetBaseName", w->getWidgetName());
845 settings.setValue(
"widgetWidth", w->getWidget()->width());
846 settings.setValue(
"widgetHeight", w->getWidget()->height());
847 w->saveSettings(&settings);
848 widgetCustomNames.push_back(prefix);
858 settings.setValue(
"WidgetCustomNames", widgetCustomNames);
859 ARMARX_INFO <<
"Saved config to " << configFilepath;
865 QFileInfo file(configFilepath);
866 statusBar()->showMessage(
"'" + file.fileName() +
"' saved.", 10000);
870 ArmarXMainWindow::saveGuiConfigAs()
872 configFilepath.clear();
879 if (filepath.length() > 0)
882 std::filesystem::path file(filepath.toStdString());
885 setWindowTitle(guiWindowBaseName +
" - " +
886 QString::fromStdString(file.filename().string()) +
" in " +
887 path.absolutePath());
891 setWindowTitle(guiWindowBaseName);
896 ArmarXMainWindow::createArmarXWidget(QString widgetName,
897 QString customInstanceName,
901 if (listOpenWidgets.find(
"Dock" + customInstanceName) != listOpenWidgets.end())
911 if (widgetName ==
"VisionX.PointCloudViewer")
913 ARMARX_INFO <<
"Creating SoQtExaminerViewer for " << widgetName.toStdString();
914 SoQtExaminerViewer(
nullptr,
"", TRUE, SoQtExaminerViewer::BUILD_NONE);
925 auto widgetUsage = mainSettings.value(
"WidgetUsageHistory").toList();
926 widgetUsage.push_back(widgetName);
927 if (widgetUsage.size() > widgetUsageHistoryLength)
929 widgetUsage.pop_front();
931 mainSettings.setValue(
"WidgetUsageHistory", widgetUsage);
936 w->setMainWindow(
this);
937 w->setInstanceName(customInstanceName);
938 w->setTipDialog(tipDialog);
942 w->loadSettings(settings);
944 else if (w->getConfigDialog(
this))
948 ManagedIceObjectPtr::dynamicCast(w->getConfigDialog().data());
952 comp->__setNoDelete(
true);
953 registry->addObject(comp,
false);
956 w->getConfigDialog()->setModal(
true);
958 w->getConfigDialog().data(), SIGNAL(accepted()), w.get(), SLOT(configAccepted()));
964 w->getConfigDialog().data(), SIGNAL(rejected()), w.get(), SLOT(configRejected()));
970 pendingWidgets.push_back(w);
971 w->getConfigDialog()->show();
972 w->getConfigDialog()->raise();
973 w->getConfigDialog()->activateWindow();
979 addArmarXWidget(w, !settings);
985 bool createViewerWidget)
987 for (
unsigned int i = 0; i < pendingWidgets.size(); ++i)
989 if (pendingWidgets[i].get() == newWidgetController.get())
991 pendingWidgets.erase(pendingWidgets.begin() + i);
996 QString widgetName = newWidgetController->getWidgetName();
997 QString customInstanceName = newWidgetController->getInstanceName();
999 if (listOpenWidgets.find(customInstanceName) != listOpenWidgets.end())
1005 assert(widgetName == newWidgetController->getWidgetName());
1006 ArmarXDockWidget* dockWidget =
1007 new ArmarXDockWidget(customInstanceName, newWidgetController);
1009 connect(dockWidget, SIGNAL(destroyed(QObject*)),
this, SLOT(removeArmarXWidget(QObject*)));
1011 dockWidget->setArmarXWidget(newWidgetController->getWidget());
1012 dockWidget->setObjectName(customInstanceName);
1013 StatusDockWidgetTitleBar* customTitlebar =
new StatusDockWidgetTitleBar(dockWidget,
this);
1014 dockWidget->setTitleBarWidget(customTitlebar);
1015 customTitlebar->addCustomWidget(newWidgetController->getCustomTitlebarWidget(dockWidget));
1017 if (listOpenWidgets.find(dockWidget->objectName()) != listOpenWidgets.end())
1020 customInstanceName +
"' already exists.");
1025 QDockWidget* biggestOpenDockWidget = getBiggestOpenWidget();
1026 listOpenWidgets[customInstanceName] =
1027 qMakePair<QDockWidget*, ArmarXWidgetControllerPtr>(dockWidget, newWidgetController);
1028 addDockWidget(Qt::RightDockWidgetArea, dockWidget);
1029 newWidgetController->postDocking();
1031 QSize widgetStartSize = newWidgetController->getWidget()->size();
1032 if (widgetStartSize.width() * widgetStartSize.height() >= 400 * 400)
1033 if (biggestOpenDockWidget)
1035 tabifyDockWidget(biggestOpenDockWidget, dockWidget);
1039 dockWidget->raise();
1041 updateOpenWidgetList();
1044 newWidgetController->setMutex3D(mutex3d);
1046 QApplication::instance()
1052 registry->addObject(comp,
false);
1054 int timeoutMs = 30000;
1056 if (!comp->getObjectScheduler()->waitForObjectState(eManagedIceObjectInitialized,
1060 <<
" was not connected to Ice after " << timeoutMs / 1000
1061 <<
" seconds" << std::endl;
1068 SoNode* node = newWidgetController->getScene();
1074 OpenWidgetMap::Iterator it = listOpenWidgets.begin();
1076 for (; it != listOpenWidgets.end(); it++)
1078 viewerInstance = Viewer3DWidgetPtr::dynamicCast(it.value().second);
1086 if (!viewerInstance && createViewerWidget)
1090 viewerInstance = setupViewerWidget();
1093 SoSeparator* sep =
new SoSeparator;
1096 SoPerspectiveCamera* camera =
new SoPerspectiveCamera;
1098 sep->addChild(camera);
1099 sep->addChild(node);
1101 viewer3DMap[customInstanceName] = {sep, newWidgetController->getSceneConfigDialog()};
1106 return newWidgetController;
1112 for (
unsigned int i = 0; i < pendingWidgets.size(); ++i)
1114 if (pendingWidgets[i].get() == newWidgetController.get())
1116 pendingWidgets.erase(pendingWidgets.begin() + i);
1123 ArmarXMainWindow::removeArmarXWidget(QObject* widget)
1125 ARMARX_DEBUG <<
"removing widgetname: " << widget->objectName();
1126 QDockWidget* dockWidget = qobject_cast<QDockWidget*>(widget);
1129 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1131 for (; it != listOpenWidgets.end(); it++)
1133 if (widget == it.value().first)
1138 if (it.value().second)
1140 widgetName = it.value().second->getInstanceName();
1144 if (it.value().first)
1146 widgetName = it.value().first->objectName();
1151 listOpenWidgets.erase(it);
1152 updateOpenWidgetList();
1155 if (viewer3DMap.contains(widgetName) )
1157 auto& node = viewer3DMap[widgetName].node;
1164 ARMARX_DEBUG <<
"Removing from 3D list: " << widgetName;
1165 viewer3DMap.remove(widgetName);
1173 removeDockWidget(dockWidget);
1176 QPointer<QDockWidget>
1177 ArmarXMainWindow::getBiggestOpenWidget()
1179 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1180 QPointer<QDockWidget> biggestWidget = NULL;
1182 for (; it != listOpenWidgets.end(); it++)
1184 QDockWidget* dockWidget = it.value().first;
1186 if (!biggestWidget ||
1187 dockWidget->size().width() * dockWidget->size().height() >
1188 biggestWidget->size().width() * biggestWidget->size().height())
1190 biggestWidget = dockWidget;
1194 return biggestWidget;
1198 ArmarXMainWindow::getCategoryMenu(
const std::string& categoryString,
1204 if (items.size() <= 1)
1209 auto actions = menu->actions();
1211 for (QAction* action : actions)
1213 if (action->text().toStdString() == *items.begin())
1215 items.erase(items.begin(), items.begin() + 1);
1216 std::string rest = simox::alg::join(items,
".");
1218 if (!action->menu())
1220 action->setMenu(
new QMenu(QString::fromStdString(*items.begin()),
this));
1223 if (action->icon().isNull() && !categoryIcon.isNull())
1225 action->setIcon(categoryIcon);
1226 action->setIconVisibleInMenu(
true);
1229 return getCategoryMenu(rest, action->menu(), categoryIcon);
1233 return menu->addMenu(QString::fromStdString(*items.begin()));
1237 ArmarXMainWindow::updateAvailableWidgetList()
1239 ui->menuAdd_Widget->clear();
1241 searchField =
new QLineEdit(ui->menuAdd_Widget);
1242 searchField->setToolTip(
"Search and add a new widget from all loaded ArmarX Gui Plugins");
1243 searchField->setMaximumWidth(250);
1244 searchField->setPlaceholderText(
"Widget Search");
1246 QStringList widgetNameList;
1248 ui->toolBar->clear();
1251 ui->toolBar->addWidget(emergencyStopWidget->getButtonWidget());
1253 ui->toolBar->setIconSize(QSize(256, 24));
1255 QMap<QString, QAction*> actionsForToolBar;
1260 QString widgetName = fullWidgetName;
1261 widgetName = widgetName.remove(0, widgetName.lastIndexOf(
".") + 1);
1262 widgetNameList << fullWidgetName;
1266 categoryIcon = widgetInfo->getCategoryIcon();
1276 getCategoryMenu(fullWidgetName.toStdString(), ui->menuAdd_Widget, categoryIcon);
1277 AddArmarXWidgetAction* action =
new AddArmarXWidgetAction(widgetName, menu,
this);
1281 widgetIcon = widgetInfo->getIcon();
1290 action->setIcon(widgetIcon);
1291 action->setIconVisibleInMenu(
true);
1293 action->setData(fullWidgetName);
1294 menu->addAction(action);
1296 if (mainWidgetNames.contains(fullWidgetName))
1298 actionsForToolBar[fullWidgetName] = action;
1300 actionList[fullWidgetName] = action;
1302 action, SIGNAL(triggered()), action, SLOT(addArmarXWidget()), Qt::UniqueConnection);
1304 SIGNAL(clicked(QString, QString)),
1306 SLOT(createArmarXWidget(QString, QString)),
1307 Qt::UniqueConnection);
1311 for (
const QString& widgetName : mainWidgetNames)
1313 if (QAction* action = actionsForToolBar.value(widgetName))
1315 const bool allowText =
false;
1316 addActionToToolBar(action, allowText);
1319 addArVizGodotIcon();
1321 AddArmarXWidgetAction* completerAction =
1322 new AddArmarXWidgetAction(
"", ui->menuAdd_Widget,
this);
1323 InfixCompleter* completer =
new InfixCompleter(widgetNameList, searchField);
1325 searchField, SIGNAL(textEdited(QString)), completer, SLOT(setCompletionInfix(QString)));
1328 connect(completerAction, SIGNAL(accepted()), searchField, SLOT(clear()));
1329 connect(completerAction,
1330 SIGNAL(clicked(QString, QString)),
1332 SLOT(createArmarXWidget(QString, QString)),
1333 Qt::UniqueConnection);
1334 searchField->setCompleter(completer);
1336 ui->toolBar->addSeparator();
1337 ui->toolBar->addWidget(searchField);
1340 QString::fromUtf8(
"://icons/edit-add.ico"), QSize(), QIcon::Normal,
QIcon::Off);
1341 openWidgetButton =
new QToolButton(
this);
1342 openWidgetButton->setEnabled(
false);
1343 openWidgetButton->setIcon(icon);
1344 openWidgetButton->setFixedSize({24, 24});
1345 openWidgetButton->setToolTip(
"Open selected widget");
1346 connect(openWidgetButton,
1349 SLOT(openWidgetButtonClicked()),
1350 Qt::UniqueConnection);
1351 ui->toolBar->addWidget(openWidgetButton);
1352 connect(searchField,
1353 SIGNAL(textChanged(QString)),
1355 SLOT(updateOpenWidgetButtonStatus(QString)),
1356 Qt::UniqueConnection);
1358 connect(searchField,
1359 SIGNAL(returnPressed()),
1361 SLOT(openWidgetButtonClicked()),
1362 Qt::UniqueConnection);
1365 ui->toolBar->addSeparator();
1366 favoritesLabel =
new QLabel(
"Favorites:");
1367 favoritesLabel->setToolTip(
"The favorites are generated from the usage frequency over "
1368 "the last X widget creations."
1369 " Rightclick to change the number of displayed favorites");
1370 ui->toolBar->addWidget(favoritesLabel);
1372 favoritesLabel->setContextMenuPolicy(Qt::CustomContextMenu);
1373 connect(favoritesLabel,
1374 SIGNAL(customContextMenuRequested(
const QPoint&)),
1376 SLOT(onContextMenuFavoritesRequested(
const QPoint&)));
1378 updatefavoriteActions();
1382 ArmarXMainWindow::updateOpenWidgetList()
1384 ui->menuWindows->clear();
1385 QAction* closeAllAction =
new QAction(
"Close all widgets", ui->menuWindows);
1386 connect(closeAllAction, SIGNAL(triggered()),
this, SLOT(closeAllWidgetsWithDialog()));
1387 ui->menuWindows->addAction(closeAllAction);
1388 ui->menuWindows->addSeparator();
1390 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1392 for (; it != listOpenWidgets.end(); it++)
1394 QDockWidget* dockWidget = it.value().first;
1395 QAction* action =
new QAction(dockWidget->objectName(), ui->menuWindows);
1396 action->setCheckable(
true);
1397 action->setChecked(!dockWidget->isHidden());
1399 connect(action, SIGNAL(toggled(
bool)), dockWidget, SLOT(setVisible(
bool)));
1401 ui->menuWindows->addAction(action);
1406 ArmarXMainWindow::addArVizGodotIcon()
1408 const char* path = std::getenv(
"arviz_godot_DIR");
1409 if (path ==
nullptr)
1414 std::filesystem::path buildDirectory(path);
1415 std::filesystem::path mainDirectory = buildDirectory.parent_path();
1417 std::filesystem::path binaryPath = buildDirectory /
"bin" /
"arviz-godot";
1418 std::filesystem::path iconPath =
1419 mainDirectory /
"source" /
"arviz_godot" /
"project" /
"icon.png";
1421 if (not std::filesystem::exists(binaryPath) or not std::filesystem::exists(iconPath))
1426 QIcon icon(iconPath.c_str());
1427 QString name(
"ArViz Godot");
1429 QAction* action =
new QAction(icon, name,
this);
1431 bool allowText =
false;
1432 addActionToToolBar(action, allowText);
1434 auto slot = [
this, binaryPath]()
1436 if (not std::filesystem::exists(binaryPath))
1438 QMessageBox errorBox;
1440 nullptr,
"Error",
"The ArViz Godot executable is no longer available.");
1460 int null = open(
"/dev/null", O_WRONLY);
1461 dup2(
null, STDOUT_FILENO);
1462 dup2(
null, STDERR_FILENO);
1464 execl(binaryPath.c_str(),
"arviz-godot",
nullptr);
1468 connect(action, &QAction::triggered,
this,
slot, Qt::UniqueConnection);
1474 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
1475 QMenu* menu = ui->menuRecently_Opened_Files;
1476 auto actions = menu->actions();
1478 for (QAction* action : actions)
1480 if (!action->isCheckable() && !action->isSeparator())
1482 menu->removeAction(action);
1486 foreach (QString file, recentlyFiles)
1491 action->setCheckable(
false);
1492 connect(action, SIGNAL(triggered()), action, SLOT(openFile()));
1493 menu->addAction(action);
1498 ArmarXMainWindow::updateStatusOfOpenWidgets()
1500 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1502 for (; it != listOpenWidgets.end(); it++)
1504 QDockWidget* dockWidget = it.value().first;
1507 qobject_cast<StatusDockWidgetTitleBar*>(dockWidget->titleBarWidget());
1509 if (titlebar && comp)
1512 ManagedIceObjectConnectivity con = comp->getConnectivity();
1513 QStringList dependencies;
1515 for (DependencyMap::iterator i = con.dependencies.begin();
1516 i != con.dependencies.end();
1519 ManagedIceObjectDependencyBasePtr& dep = i->second;
1521 if (!dep->getResolved() || comp->getState() == eManagedIceObjectStarted)
1523 dependencies << QString::fromStdString(dep->getName());
1527 titlebar->
changeStatus((ManagedIceObjectState)comp->getState(), dependencies);
1533 ArmarXMainWindow::enterFullscreenMode()
1536 ui->toolBar->hide();
1537 ui->menubar->hide();
1538 ui->statusbar->hide();
1541 leaveFullScreenActionF11 =
new QAction(
this);
1542 leaveFullScreenActionF11->setShortcut(Qt::Key_F11);
1543 connect(leaveFullScreenActionF11, SIGNAL(triggered()),
this, SLOT(leaveFullscreenMode()));
1544 addAction(leaveFullScreenActionF11);
1546 leaveFullScreenActionEsc =
new QAction(
this);
1547 leaveFullScreenActionEsc->setShortcut(Qt::Key_Escape);
1548 connect(leaveFullScreenActionEsc, SIGNAL(triggered()),
this, SLOT(leaveFullscreenMode()));
1549 addAction(leaveFullScreenActionEsc);
1553 ArmarXMainWindow::leaveFullscreenMode()
1556 removeAction(leaveFullScreenActionF11);
1557 leaveFullScreenActionF11 =
nullptr;
1559 removeAction(leaveFullScreenActionEsc);
1560 leaveFullScreenActionEsc =
nullptr;
1563 ui->toolBar->show();
1564 ui->menubar->show();
1565 ui->statusbar->show();
1569 ArmarXMainWindow::toggleWidgetLock()
1571 QList<ArmarXDockWidget*> dockWidgets = findChildren<ArmarXDockWidget*>();
1575 for (
auto& widget : dockWidgets)
1577 widget->unlockWidget();
1583 for (
auto& widget : dockWidgets)
1585 widget->lockWidget();
1589 widgetsLocked = !widgetsLocked;
1599 QAction(widgetName, parent), mainGui(mainGui)
1613 if (widgetName.isEmpty())
1615 QLineEdit* edit = qobject_cast<QLineEdit*>(sender());
1618 widgetName = edit->text();
1626 setText(widgetName);
1627 setData(widgetName);
1639 dialog->setModal(
true);
1658 scrollArea =
new QScrollArea();
1659 scrollArea->setWidgetResizable(
true);
1661 QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1662 scrollArea->setSizePolicy(sizePolicy);
1663 setWidget(scrollArea);
1665 savedTitleBar =
nullptr;
1677 scrollArea->setWidget(widget);
1693 emit destroyed(
this);
1701 ARMARX_INFO <<
"Locking widget: " << objectName();
1702 savedTitleBar = titleBarWidget();
1703 setTitleBarWidget(
new QWidget());
1713 ARMARX_INFO <<
"Unlocking widget: " << objectName();
1714 if (savedTitleBar !=
nullptr)
1716 QWidget* old = titleBarWidget();
1717 setTitleBarWidget(savedTitleBar);
1718 savedTitleBar =
nullptr;
1733 QAction(text, parent), mainGui(mainGui)
1747 armarx::ArmarXMainWindow::on_actionClear_tip_blacklist_triggered()
1749 tipDialog->setBlackListedStrings(QStringList());
1750 mainSettings.setValue(CONFIG_BLACKLISTED_TIPS, tipDialog->getBlackListedStrings());
1751 mainSettings.sync();
1756 armarx::ArmarXMainWindow::on_actionAbout_triggered()
1760 "ArmarX Graphical User Interface",
1761 QString(
"ArmarX is being developed at the High Performance Humanoid Technologies (H2T) "
1762 "lab at the Karlsruhe Institute of Technology (KIT)\nCopyright H2T, KIT, ") +
1763 QString(&__DATE__[7]) +
1768 armarx::ArmarXMainWindow::on_actionLoadLastConfig_toggled(
bool toggled)
1770 mainSettings.setValue(CONFIG_LOAD_LAST_CONFIG, toggled);
1771 mainSettings.sync();
1775 armarx::ArmarXMainWindow::on_actionArmarX_Documentation_triggered()
1777 QDesktopServices::openUrl(QUrl(
"http://armarx.humanoids.kit.edu/"));
1781 armarx::ArmarXMainWindow::on_actionOpen_Use_Case_triggered()
1783 guiUseCaseSelector->setCancelButtonText(
"Cancel");
1784 if (guiUseCaseSelector->exec() == QDialog::Accepted)
1786 QString path = guiUseCaseSelector->getSelectedConfigFilePath();
1788 if (!path.isEmpty())
1790 loadGuiConfig(path,
false);
1793 mainSettings.setValue(
"DoNotShowUseCaseDialog", guiUseCaseSelector->getDoNotShowAgain());
1797 armarx::ArmarXMainWindow::on_actionClear_plugin_cache_triggered()
1799 pluginCache.clearCacheFile();
1803 ArmarXMainWindow::updateOpenWidgetButtonStatus(QString widgetName)
1809 ArmarXMainWindow::openWidgetButtonClicked()
1811 addWidgetAction->
triggered(searchField->text());
1815 ArmarXMainWindow::onContextMenuFavoritesRequested(
const QPoint& pos)
1819 auto numberOfFavIcons =
new QSpinBox(&menu);
1820 numberOfFavIcons->setRange(1, 100);
1821 numberOfFavIcons->setSingleStep(1);
1822 numberOfFavIcons->setValue(mainSettings.value(
"FavoriteWidgetCount", 6).toInt());
1823 numberOfFavIcons->setToolTip(
"Max number of favorites");
1824 connect(numberOfFavIcons,
1825 SIGNAL(valueChanged(
int)),
1827 SLOT(onNumberOfMaxFavoritesChanged(
int)));
1829 QWidgetAction* action =
new QWidgetAction{&menu};
1830 action->setDefaultWidget(numberOfFavIcons);
1831 menu.addAction(action);
1832 menu.exec(favoritesLabel->mapToGlobal(pos));
1836 ArmarXMainWindow::onNumberOfMaxFavoritesChanged(
int i)
1838 mainSettings.setValue(
"FavoriteWidgetCount", i);
1839 updatefavoriteActions();
1843 ArmarXMainWindow::updatefavoriteActions()
1846 if (favoriteActionWidgetNames ==
list
1853 favoriteActionWidgetNames =
list;
1854 for (
auto* action : favoriteActions)
1856 ui->toolBar->removeAction(action);
1857 action->deleteLater();
1859 favoriteActions.clear();
1860 for (
auto widgetName : favoriteActionWidgetNames)
1862 if (actionList.contains(widgetName))
1864 bool allowText =
true;
1865 favoriteActions.emplace_back(addActionToToolBar(actionList[widgetName], allowText));