25 #include <ArmarXGui/applications/ArmarXGui/ui_ArmarXMainWindow.h>
40 #include <QtCore/QDirIterator>
41 #include <QFileDialog>
44 #include <QInputDialog>
45 #include <QPushButton>
48 #include <QToolButton>
51 #include <QStringList>
52 #include <QPluginLoader>
55 #include <QGridLayout>
56 #include <QStackedWidget>
58 #include <QPlainTextEdit>
61 #include <QSignalMapper>
64 #include <QActionGroup>
65 #include <QModelIndex>
66 #include <QListWidget>
67 #include <QHBoxLayout>
68 #include <QDialogButtonBox>
69 #include <QProxyStyle>
71 #include <QDesktopServices>
74 #include <Inventor/nodes/SoPerspectiveCamera.h>
84 #include <QMessageBox>
85 #include <QScrollArea>
86 #include <QStringListModel>
88 #include <QWidgetAction>
90 #include <SimoxUtility/algorithm/string/string_tools.h>
92 #include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
93 #include <QtSvg/QSvgRenderer>
98 #include <sys/types.h>
106 #define ARMARX_ORGANIZATION "KIT"
107 #define ARMARX_GUI_APPLICATION_NAME "ArmarX"
109 #define CONFIG_LOAD_LAST_CONFIG "LoadLastConfig"
110 #define CONFIG_BLACKLISTED_TIPS "BlacklistedTips"
117 defaultPackageNames(packages),
118 widgetsLocked(false),
120 mainSettings(QString(settingsFile.c_str()), QSettings::NativeFormat)
123 QMainWindow::separator {
124 width: 3px; /* when vertical */
125 height: 3px; /* when horizontal */
127 QMainWindow::separator:hover {
132 mainWidgets = QStringList() << "Meta.LogViewer" <<
"Statecharts.StatechartEditor" <<
"Meta.SystemStateMonitor" <<
"Meta.ScenarioManager" <<
"MemoryX.WorkingMemoryGui";
135 QPixmap pm(QString(
"://icons/ArmarX-Splashscreen.png"));
136 splashSceen =
new QSplashScreen(pm);
139 ui = new ::Ui::ArmarXMainWindow();
140 mutex3d = std::make_shared<std::recursive_mutex>();
145 QString username = qgetenv(
"USER");
146 if (username.isEmpty())
148 username = qgetenv(
"USERNAME");
152 setWindowTitle(guiWindowBaseName);
153 this->registry = registry;
154 setAttribute(Qt::WA_QuitOnClose);
157 setCentralWidget(NULL);
164 connect(addWidgetAction, SIGNAL(clicked(QString, QString)),
this, SLOT(createArmarXWidget(QString, QString)), Qt::UniqueConnection);
167 connect(ui->actionLoadPlugin, SIGNAL(triggered()),
this, SLOT(pluginDialog()));
168 connect(ui->actionSave_Gui, SIGNAL(triggered()),
this, SLOT(saveGuiConfig()));
169 connect(ui->actionLoad_Gui_Config, SIGNAL(triggered()),
this, SLOT(
loadGuiConfig()));
170 connect(ui->actionQuit, SIGNAL(triggered()),
this, SLOT(close()));
171 connect(ui->actionSave_Gui_as, SIGNAL(triggered()),
this, SLOT(saveGuiConfigAs()));
172 connect(ui->actionFullscreen, SIGNAL(triggered()),
this, SLOT(enterFullscreenMode()));
173 connect(ui->actionLock_Widgets, SIGNAL(triggered()),
this, SLOT(toggleWidgetLock()));
176 emergencyStopWidget = EmergencyStopWidgetPtr::dynamicCast(ArmarXComponentWidgetController::createInstance<EmergencyStopWidget>());
177 this->registry->addObject(ManagedIceObjectPtr::dynamicCast(emergencyStopWidget));
180 QSet<QString> pluginDirs;
182 for (
const std::string& packageName : packages)
186 loadPlugins(pluginDirs,
false);
187 if (!disablePreloading)
196 connectionStatusTimer =
new QTimer(
this);
197 connect(connectionStatusTimer, SIGNAL(timeout()),
this, SLOT(updateStatusOfOpenWidgets()));
198 connectionStatusTimer->start(300);
200 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
201 splashSceen->finish(
this);
203 guiUseCaseSelector =
new GuiUseCaseSelector(
this, mainSettings.value(
"DoNotShowUseCaseDialog").toBool(),
this);
207 if (!configToLoad.isEmpty())
211 else if (!mainSettings.value(
"DoNotShowUseCaseDialog").toBool() && guiUseCaseSelector->exec() == QDialog::Accepted)
231 QStringList defaultWidgets {
"Meta.LogViewer"};
232 for (
auto& widgetName : defaultWidgets)
236 createArmarXWidget(widgetName, widgetName);
241 mainSettings.setValue(
"DoNotShowUseCaseDialog", guiUseCaseSelector->
getDoNotShowAgain());
247 connectionStatusTimer->stop();
255 void ArmarXMainWindow::removeViewerWidget(QObject* widget)
264 removeArmarXWidget(widget);
272 return Viewer3DWidgetPtr::dynamicCast(listOpenWidgets.find(
ARMARX_VIEWER_NAME).value().second);
278 viewer->setMutex3D(mutex3d);
285 void ArmarXMainWindow::pluginDialog()
287 QFileDialog dialog(
this);
288 dialog.setFileMode(QFileDialog::ExistingFiles);
289 dialog.setNameFilter(tr(
"Libraries (*.dll *.so *.dylib)"));
290 QStringList fileNames;
294 fileNames = dialog.selectedFiles();
297 foreach (QString filePath, fileNames)
305 void ArmarXMainWindow::loadPlugins(
const QStringList& fileNames)
307 QStringList guiFiles;
309 for (
int i = 0; i < fileNames.size(); i++)
311 QString fileName = fileNames.at(i);
314 if (!fileName.endsWith(
"GuiPlugin.so") && !fileName.endsWith(
"GuiPlugin.dll") && !fileName.endsWith(
"GuiPlugin.dylib"))
319 guiFiles.push_back(fileName);
321 auto start = IceUtil::Time::now();
322 for (
int i = 0; i < guiFiles.size(); i++)
324 QString fileName = guiFiles.at(i);
325 if ((IceUtil::Time::now() - start).toSeconds() >= 2)
328 splashSceen->showMessage(splashscreenPrefix + fileName,
329 Qt::AlignJustify | Qt::AlignBottom);
330 qApp->processEvents();
335 updateAvailableWidgetList();
338 QAction* ArmarXMainWindow::addActionToToolBar(QAction* action,
bool allowText)
340 QToolButton* button =
new QToolButton(ui->toolBar);
342 std::optional<QSize> textSize;
345 button->setToolButtonStyle(Qt::ToolButtonStyle::ToolButtonTextBesideIcon);
346 button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
349 button->setText(action->text());
350 textSize = button->sizeHint();
353 button->setDefaultAction(action);
354 if (not action->icon().isNull())
356 const QSize maxSize {256, 24};
357 const QSize iconSize = action->icon().actualSize(maxSize);
360 button->setIconSize(iconSize);
361 button->setFixedSize(textSize.has_value()
362 ? QSize{textSize->width() + iconSize.width(), iconSize.height()}
365 return ui->toolBar->addWidget(button);
372 QString dir = QString::fromStdString(libPaths);
373 dir = QDir::cleanPath(dir);
380 auto widgetUsageHistory = mainSettings.value(
"WidgetUsageHistory").toList();
381 std::map<QString, int> widgetUsage;
382 for (
auto& widgetName : widgetUsageHistory)
384 if (widgetUsage.count(widgetName.toString()) == 0)
386 widgetUsage[widgetName.toString()] = 1;
390 widgetUsage[widgetName.toString()] += 1;
393 std::multimap<int, QString> ranking;
394 for (
auto it = widgetUsage.begin(); it != widgetUsage.end(); it++)
396 ranking.insert(std::make_pair(it->second, it->first));
399 const int favCount = mainSettings.value(
"FavoriteWidgetCount", 6).toInt();
400 QStringList favoriteWidgetNames;
401 for (
auto it = ranking.rbegin(); it != ranking.rend() && i < favCount ; it++)
403 auto& widgetName = it->second;
404 if (!mainWidgets.contains(widgetName))
406 favoriteWidgetNames << widgetName;
410 return favoriteWidgetNames;
415 QSet<QString> pluginDirs;
416 splashSceen->showMessage(splashscreenPrefix + packageName,
417 Qt::AlignJustify | Qt::AlignBottom);
418 qApp->processEvents();
420 ARMARX_INFO <<
"Looking for gui plugins in package " << packageName;
422 pluginDirs.insert(dir);
423 loadedPackages << packageName;
424 loadPlugins(pluginDirs,
false);
428 void ArmarXMainWindow::loadPlugins(
const QString& pluginDir,
bool searchRecursive)
431 dirs.insert(pluginDir);
432 loadPlugins(dirs, searchRecursive);
436 void ArmarXMainWindow::loadPlugins(
const QSet<QString>& pluginDirs,
bool searchRecursive)
440 filters <<
"*.so" <<
"*.dll" <<
"*.dylib";
441 QList<QDir> directoriesToCheck;
442 QStringList allFileNames;
444 for (
const auto& pluginDir : pluginDirs)
446 directoriesToCheck.push_back(QDir(pluginDir));
448 while (directoriesToCheck.size() > 0)
450 ARMARX_VERBOSE_S <<
"Checking dir : " + directoriesToCheck.front().absolutePath() << std::endl;
451 splashSceen->showMessage(splashscreenPrefix + directoriesToCheck.front().absolutePath(),
452 Qt::AlignJustify | Qt::AlignBottom);
453 qApp->processEvents();
454 QDir currentPluginDir = directoriesToCheck.front();
455 directoriesToCheck.pop_front();
456 QString curPath = currentPluginDir.path();
458 if (curPath.length() == 0)
463 QStringList fileNames = currentPluginDir.entryList(filters, QDir::Files);
465 for (
auto& fileName : fileNames)
467 fileName = currentPluginDir.absoluteFilePath(fileName);
470 allFileNames.append(fileNames);
474 QDirIterator directoryIterator(currentPluginDir.absolutePath(), QStringList(), QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
476 while (directoryIterator.hasNext())
478 directoryIterator.next();
479 directoriesToCheck.push_back(QDir(directoryIterator.filePath()));
487 loadPlugins(allFileNames);
495 return list.contains(widgetName);
500 QFileInfo pathInfo(filePath);
501 QString fileName(pathInfo.fileName());
504 updateAvailableWidgetList();
529 void ArmarXMainWindow::closeAllWidgets()
533 OpenWidgetMap listOpenWidgetsTemp = listOpenWidgets;
534 OpenWidgetMap::iterator it = listOpenWidgetsTemp.begin();
536 for (; it != listOpenWidgetsTemp.end() ; ++it)
538 ARMARX_INFO <<
"Closing widget " << it.key() <<
" size: " << listOpenWidgetsTemp.size();
539 QDockWidget* w = it.value().first;
557 listOpenWidgets.clear();
559 this->configFilepath =
"";
563 void ArmarXMainWindow::closeAllWidgetsWithDialog()
565 QMessageBox dialog(QMessageBox::Question, tr(
"Closing all widgets"), tr(
"Do you really want to close all widgets?"));
580 QDir path(configFilepath);
581 configFilepath = path.absolutePath();
583 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
584 recentlyFiles.removeAll(configFilepath);
585 recentlyFiles.push_front(configFilepath);
587 if (recentlyFiles.size() > 10)
589 recentlyFiles.pop_back();
592 mainSettings.setValue(
"RecentlyFiles", recentlyFiles);
598 return defaultPackageNames;
606 return Viewer3DWidgetPtr::dynamicCast(listOpenWidgets.find(
ARMARX_VIEWER_NAME).value().second);
617 if (configFilepath.length() == 0)
619 QFileDialog dialog(
this);
620 dialog.setFileMode(QFileDialog::ExistingFile);
621 dialog.setAcceptMode(QFileDialog::AcceptOpen);
622 QStringList nameFilters;
623 nameFilters <<
"ArmarX Gui-Files (*.armarxgui)"
624 <<
"All Files (*.*)";
625 dialog.setNameFilters(nameFilters);
629 if (dialog.selectedFiles().size() == 0)
634 configFilepath = dialog.selectedFiles()[0];
638 ARMARX_INFO <<
"load config dialog canceled" << std::endl;
646 QDir dir(configFilepath);
648 configFilepath = dir.absolutePath();
650 if (!QFile::exists(configFilepath))
658 if (showAsOpenGuiConfig)
664 QSettings settings(configFilepath, QSettings::IniFormat);
667 if (settings.allKeys().size() == 0)
677 std::sort(packagesStd.begin(), packagesStd.end(),
678 [](
const std::string& lhs,
const std::string& rhs) ->
bool {
679 return simox::alg::to_lower(lhs) < simox::alg::to_lower(rhs);
682 QStringList packagesToLoad;
684 for(
const auto& pkg : packagesStd)
686 packagesToLoad.push_back(QString::fromStdString(pkg));
690 settings.setValue(
"loadedPackages", packagesToLoad);
694 foreach (QString package, packagesToLoad)
699 QStringList widgetNames = settings.value(
"WidgetCustomNames").toStringList();
700 foreach (QString widgetCustomName, widgetNames)
702 settings.beginGroup(widgetCustomName);
705 ARMARX_INFO <<
"Creating widget " << settings.value(
"WidgetBaseName").toString() <<
"," << widgetCustomName;
706 ArmarXWidgetControllerPtr widget = createArmarXWidget(settings.value(
"WidgetBaseName").toString(), widgetCustomName, &settings);
710 qApp->processEvents();
714 auto geometryByteArray = settings.value(
"MainWindowGeometry").toByteArray();
715 if (geometryByteArray.size() > 0)
718 restoreGeometry(geometryByteArray);
722 QRect geometry = settings.value(
"MainWindowGeometry").toRect();
723 setGeometry(geometry);
726 if (!restoreState(settings.value(
"DockWidgetsState").toByteArray()))
731 foreach (QString widgetCustomName, widgetNames)
733 settings.beginGroup(widgetCustomName);
734 OpenWidgetMap::iterator it = listOpenWidgets.find(widgetCustomName);
736 if (it != listOpenWidgets.end())
738 it->first->resize(settings.value(
"widgetWidth").toInt(), settings.value(
"widgetHeight").toInt());
743 if (showAsOpenGuiConfig)
745 this->configFilepath = configFilepath;
748 updateOpenWidgetList();
749 QFileInfo file(configFilepath);
750 statusBar()->showMessage(
"'" + file.fileName() +
"' loaded.", 10000);
755 void ArmarXMainWindow::saveGuiConfig()
757 if (configFilepath.length() == 0)
759 QFileDialog dialog(
this);
760 dialog.setFileMode(QFileDialog::AnyFile);
761 dialog.setAcceptMode(QFileDialog::AcceptSave);
762 QStringList nameFilters;
763 nameFilters <<
"ArmarX Gui-Files (*.armarxgui)"
764 <<
"All Files (*.*)";
765 dialog.setNameFilters(nameFilters);
769 if (dialog.selectedFiles().size() == 0)
774 QString file = dialog.selectedFiles()[0];
775 QFileInfo fileInfo(file);
777 if (fileInfo.suffix().isEmpty())
779 file +=
".armarxgui";
782 configFilepath = file;
792 QSettings settings(configFilepath, QSettings::IniFormat);
798 settings.setValue(
"loadedPackages", loadedPackages);
799 settings.setValue(
"MainWindowGeometry", geometry());
800 settings.setValue(
"DockWidgetsState", saveState());
801 QStringList widgetCustomNames;
802 OpenWidgetMap::iterator it = listOpenWidgets.begin();
804 for (; it != listOpenWidgets.end(); it++)
806 QString prefix = it.value().first->objectName();
808 settings.beginGroup(prefix);
813 settings.setValue(
"WidgetBaseName", w->getWidgetName());
814 settings.setValue(
"widgetWidth", w->getWidget()->width());
815 settings.setValue(
"widgetHeight", w->getWidget()->height());
816 w->saveSettings(&settings);
817 widgetCustomNames.push_back(prefix);
827 settings.setValue(
"WidgetCustomNames", widgetCustomNames);
828 ARMARX_INFO <<
"Saved config to " << configFilepath;
834 QFileInfo file(configFilepath);
835 statusBar()->showMessage(
"'" + file.fileName() +
"' saved.", 10000);
839 void ArmarXMainWindow::saveGuiConfigAs()
841 configFilepath.clear();
847 if (filepath.length() > 0)
850 std::filesystem::path file(filepath.toStdString());
853 setWindowTitle(guiWindowBaseName +
" - " + QString::fromStdString(file.filename().string()) +
" in " + path.absolutePath());
857 setWindowTitle(guiWindowBaseName);
863 ArmarXWidgetControllerPtr ArmarXMainWindow::createArmarXWidget(QString widgetName, QString customInstanceName, QSettings* settings)
866 if (listOpenWidgets.find(
"Dock" + customInstanceName) != listOpenWidgets.end())
876 if (widgetName ==
"VisionX.PointCloudViewer")
878 ARMARX_INFO <<
"Creating SoQtExaminerViewer for " << widgetName.toStdString();
879 SoQtExaminerViewer(
nullptr,
"", TRUE, SoQtExaminerViewer::BUILD_NONE);
889 auto widgetUsage = mainSettings.value(
"WidgetUsageHistory").toList();
890 widgetUsage.push_back(widgetName);
891 if (widgetUsage.size() > widgetUsageHistoryLength)
893 widgetUsage.pop_front();
895 mainSettings.setValue(
"WidgetUsageHistory", widgetUsage);
900 w->setMainWindow(
this);
901 w->setInstanceName(customInstanceName);
902 w->setTipDialog(tipDialog);
906 w->loadSettings(settings);
908 else if (w->getConfigDialog(
this))
915 comp->__setNoDelete(
true);
916 registry->addObject(comp,
false);
919 w->getConfigDialog()->setModal(
true);
920 connect(w->getConfigDialog().data(), SIGNAL(accepted()), w.get(), SLOT(configAccepted()));
922 connect(w->getConfigDialog().data(), SIGNAL(rejected()), w.get(), SLOT(configRejected()));
925 pendingWidgets.push_back(w);
926 w->getConfigDialog()->show();
927 w->getConfigDialog()->raise();
928 w->getConfigDialog()->activateWindow();
934 addArmarXWidget(w, !settings);
940 for (
unsigned int i = 0; i < pendingWidgets.size(); ++i)
942 if (pendingWidgets[i].get() == newWidgetController.get())
944 pendingWidgets.erase(pendingWidgets.begin() + i);
949 QString widgetName = newWidgetController->getWidgetName();
950 QString customInstanceName = newWidgetController->getInstanceName();
952 if (listOpenWidgets.find(customInstanceName) != listOpenWidgets.end())
958 assert(widgetName == newWidgetController->getWidgetName());
959 ArmarXDockWidget* dockWidget =
new ArmarXDockWidget(customInstanceName, newWidgetController);
961 connect(dockWidget, SIGNAL(destroyed(QObject*)),
this, SLOT(removeArmarXWidget(QObject*)));
963 dockWidget->setArmarXWidget(newWidgetController->getWidget());
964 dockWidget->setObjectName(customInstanceName);
965 StatusDockWidgetTitleBar* customTitlebar =
new StatusDockWidgetTitleBar(dockWidget,
this);
966 dockWidget->setTitleBarWidget(customTitlebar);
967 customTitlebar->addCustomWidget(newWidgetController->getCustomTitlebarWidget(dockWidget));
969 if (listOpenWidgets.find(dockWidget->objectName()) != listOpenWidgets.end())
976 QDockWidget* biggestOpenDockWidget = getBiggestOpenWidget();
977 listOpenWidgets[customInstanceName] = qMakePair<QDockWidget*, ArmarXWidgetControllerPtr>(dockWidget, newWidgetController);
978 addDockWidget(Qt::RightDockWidgetArea, dockWidget);
979 newWidgetController->postDocking();
981 QSize widgetStartSize = newWidgetController->getWidget()->size();
982 if (widgetStartSize.width() * widgetStartSize.height() >= 400 * 400)
983 if (biggestOpenDockWidget)
985 tabifyDockWidget(biggestOpenDockWidget, dockWidget);
991 updateOpenWidgetList();
994 newWidgetController->setMutex3D(mutex3d);
996 QApplication::instance()->processEvents();
1001 registry->addObject(comp,
false);
1003 int timeoutMs = 30000;
1005 if (!comp->getObjectScheduler()->waitForObjectState(eManagedIceObjectInitialized, timeoutMs))
1007 ARMARX_WARNING <<
"Widget " << customInstanceName <<
" was not connected to Ice after " << timeoutMs / 1000 <<
" seconds" << std::endl;
1015 SoNode* node = newWidgetController->getScene();
1021 OpenWidgetMap::Iterator it = listOpenWidgets.begin();
1023 for (; it != listOpenWidgets.end(); it++)
1025 viewerInstance = Viewer3DWidgetPtr::dynamicCast(it.value().second);
1033 if (!viewerInstance && createViewerWidget)
1037 viewerInstance = setupViewerWidget();
1040 SoSeparator* sep =
new SoSeparator;
1043 SoPerspectiveCamera* camera =
new SoPerspectiveCamera;
1045 sep->addChild(camera);
1046 sep->addChild(node);
1048 viewer3DMap[customInstanceName] = {sep, newWidgetController->getSceneConfigDialog()};
1053 return newWidgetController;
1058 for (
unsigned int i = 0; i < pendingWidgets.size(); ++i)
1060 if (pendingWidgets[i].get() == newWidgetController.get())
1062 pendingWidgets.erase(pendingWidgets.begin() + i);
1068 void ArmarXMainWindow::removeArmarXWidget(QObject* widget)
1070 ARMARX_DEBUG <<
"removing widgetname: " << widget->objectName();
1071 QDockWidget* dockWidget = qobject_cast<QDockWidget*>(widget);
1074 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1076 for (; it != listOpenWidgets.end(); it++)
1078 if (widget == it.value().first)
1083 if (it.value().second)
1085 widgetName = it.value().second->getInstanceName();
1090 if (it.value().first)
1092 widgetName = it.value().first->objectName();
1097 listOpenWidgets.erase(it);
1098 updateOpenWidgetList();
1101 if (viewer3DMap.contains(widgetName) )
1103 auto& node = viewer3DMap[widgetName].node;
1110 ARMARX_DEBUG <<
"Removing from 3D list: " << widgetName;
1111 viewer3DMap.remove(widgetName);
1119 removeDockWidget(dockWidget);
1122 QPointer<QDockWidget> ArmarXMainWindow::getBiggestOpenWidget()
1124 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1125 QPointer<QDockWidget> biggestWidget = NULL;
1127 for (; it != listOpenWidgets.end(); it++)
1129 QDockWidget* dockWidget = it.value().first;
1131 if (!biggestWidget || dockWidget->size().width() * dockWidget->size().height() > biggestWidget->size().width() * biggestWidget->size().height())
1133 biggestWidget = dockWidget;
1137 return biggestWidget;
1140 QMenu* ArmarXMainWindow::getCategoryMenu(
const std::string& categoryString, QMenu* menu, QIcon categoryIcon)
1144 if (items.size() <= 1)
1149 auto actions = menu->actions();
1151 for (QAction* action : actions)
1153 if (action->text().toStdString() == *items.begin())
1155 items.erase(items.begin(), items.begin() + 1);
1156 std::string rest = simox::alg::join(items,
".");
1158 if (!action->menu())
1160 action->setMenu(
new QMenu(QString::fromStdString(*items.begin()),
this));
1163 if (action->icon().isNull() && !categoryIcon.isNull())
1165 action->setIcon(categoryIcon);
1166 action->setIconVisibleInMenu(
true);
1169 return getCategoryMenu(rest, action->menu(), categoryIcon);
1173 return menu->addMenu(QString::fromStdString(*items.begin()));
1176 void ArmarXMainWindow::updateAvailableWidgetList()
1178 ui->menuAdd_Widget->clear();
1180 searchField =
new QLineEdit(ui->menuAdd_Widget);
1181 searchField->setToolTip(
"Search and add a new widget from all loaded ArmarX Gui Plugins");
1182 searchField->setMaximumWidth(250);
1183 searchField->setPlaceholderText(
"Widget Search");
1185 QStringList widgetNameList;
1187 ui->toolBar->clear();
1190 ui->toolBar->addWidget(emergencyStopWidget->getButtonWidget());
1192 ui->toolBar->setIconSize(QSize(256, 24));
1198 QString fullWidgetName = pair.first;
1199 QString widgetName = pair.first;
1200 widgetName = widgetName.remove(0, widgetName.lastIndexOf(
".") + 1);
1201 widgetNameList << pair.first;
1205 categoryIcon = pair.second->getCategoryIcon();
1214 auto menu = getCategoryMenu(pair.first.toStdString(), ui->menuAdd_Widget, categoryIcon);
1215 AddArmarXWidgetAction* action =
new AddArmarXWidgetAction(widgetName, menu,
this);
1219 widgetIcon = pair.second->getIcon();
1228 action->setIcon(widgetIcon);
1229 action->setIconVisibleInMenu(
true);
1231 action->setData(pair.first);
1232 menu->addAction(action);
1234 if (mainWidgets.contains(fullWidgetName))
1236 bool allowText =
false;
1237 addActionToToolBar(action, allowText);
1239 actionList[fullWidgetName] = action;
1240 connect(action, SIGNAL(triggered()), action, SLOT(addArmarXWidget()), Qt::UniqueConnection);
1241 connect(action, SIGNAL(clicked(QString, QString)),
this, SLOT(createArmarXWidget(QString, QString)), Qt::UniqueConnection);
1245 addArVizGodotIcon();
1247 AddArmarXWidgetAction* completerAction =
new AddArmarXWidgetAction(
"", ui->menuAdd_Widget,
this);
1248 InfixCompleter* completer =
new InfixCompleter(widgetNameList, searchField);
1249 connect(searchField, SIGNAL(textEdited(QString)), completer, SLOT(setCompletionInfix(QString)));
1252 connect(completerAction, SIGNAL(accepted()), searchField, SLOT(clear()));
1253 connect(completerAction, SIGNAL(clicked(QString, QString)),
this, SLOT(createArmarXWidget(QString, QString)), Qt::UniqueConnection);
1254 searchField->setCompleter(completer);
1256 ui->toolBar->addSeparator();
1257 ui->toolBar->addWidget(searchField);
1259 icon.addFile(QString::fromUtf8(
"://icons/edit-add.ico"), QSize(), QIcon::Normal,
QIcon::Off);
1260 openWidgetButton =
new QToolButton(
this);
1261 openWidgetButton->setEnabled(
false);
1262 openWidgetButton->setIcon(icon);
1263 openWidgetButton->setFixedSize({24, 24});
1264 openWidgetButton->setToolTip(
"Open selected widget");
1265 connect(openWidgetButton, SIGNAL(clicked()),
this, SLOT(openWidgetButtonClicked()), Qt::UniqueConnection);
1266 ui->toolBar->addWidget(openWidgetButton);
1267 connect(searchField, SIGNAL(textChanged(QString)),
this, SLOT(updateOpenWidgetButtonStatus(QString)), Qt::UniqueConnection);
1269 connect(searchField, SIGNAL(returnPressed()),
this, SLOT(openWidgetButtonClicked()), Qt::UniqueConnection);
1272 ui->toolBar->addSeparator();
1273 favoritesLabel =
new QLabel(
"Favorites:");
1274 favoritesLabel->setToolTip(
1275 "The favorites are generated from the usage frequency over the last X widget creations."
1276 " Rightclick to change the number of displayed favorites"
1278 ui->toolBar->addWidget(favoritesLabel);
1280 favoritesLabel->setContextMenuPolicy(Qt::CustomContextMenu);
1281 connect(favoritesLabel, SIGNAL(customContextMenuRequested(
const QPoint&)),
1282 this, SLOT(onContextMenuFavoritesRequested(
const QPoint&)));
1284 updatefavoriteActions();
1287 void ArmarXMainWindow::updateOpenWidgetList()
1289 ui->menuWindows->clear();
1290 QAction* closeAllAction =
new QAction(
"Close all widgets", ui->menuWindows);
1291 connect(closeAllAction, SIGNAL(triggered()),
this, SLOT(closeAllWidgetsWithDialog()));
1292 ui->menuWindows->addAction(closeAllAction);
1293 ui->menuWindows->addSeparator();
1295 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1297 for (; it != listOpenWidgets.end(); it++)
1299 QDockWidget* dockWidget = it.value().first;
1300 QAction* action =
new QAction(dockWidget ->objectName(), ui->menuWindows);
1301 action->setCheckable(
true);
1302 action->setChecked(!dockWidget ->isHidden());
1304 connect(action, SIGNAL(toggled(
bool)), dockWidget, SLOT(setVisible(
bool)));
1306 ui->menuWindows->addAction(action);
1311 void ArmarXMainWindow::addArVizGodotIcon()
1313 const char* path = std::getenv(
"arviz_godot_DIR");
1314 if (path ==
nullptr)
1319 std::filesystem::path buildDirectory(path);
1320 std::filesystem::path mainDirectory = buildDirectory.parent_path();
1322 std::filesystem::path binaryPath = buildDirectory /
"bin" /
"arviz-godot";
1323 std::filesystem::path iconPath = mainDirectory /
"source" /
"arviz_godot" /
"project" /
"icon.png";
1325 if (not std::filesystem::exists(binaryPath) or not std::filesystem::exists(iconPath))
1330 QIcon icon(iconPath.c_str());
1331 QString name(
"ArViz Godot");
1333 QAction* action =
new QAction(icon, name,
this);
1335 bool allowText =
false;
1336 addActionToToolBar(action, allowText);
1338 auto slot = [action,
this, binaryPath]()
1340 if (not std::filesystem::exists(binaryPath))
1342 QMessageBox errorBox;
1343 errorBox.critical(
nullptr,
"Error",
"The ArViz Godot executable is no longer available.");
1363 int null = open(
"/dev/null", O_WRONLY);
1364 dup2(
null, STDOUT_FILENO);
1365 dup2(
null, STDERR_FILENO);
1367 execl(binaryPath.c_str(),
"arviz-godot",
nullptr);
1371 connect(action, &QAction::triggered,
this,
slot, Qt::UniqueConnection);
1376 QStringList recentlyFiles = mainSettings.value(
"RecentlyFiles").toStringList();
1377 QMenu* menu = ui->menuRecently_Opened_Files;
1378 auto actions = menu->actions();
1380 for (QAction* action : actions)
1382 if (!action->isCheckable() && !action->isSeparator())
1384 menu->removeAction(action);
1388 foreach (QString file, recentlyFiles)
1392 action->setCheckable(
false);
1393 connect(action, SIGNAL(triggered()), action, SLOT(openFile()));
1394 menu->addAction(action);
1398 void ArmarXMainWindow::updateStatusOfOpenWidgets()
1400 OpenWidgetMap::iterator it = listOpenWidgets.begin();
1402 for (; it != listOpenWidgets.end(); it++)
1404 QDockWidget* dockWidget = it.value().first;
1408 if (titlebar && comp)
1411 ManagedIceObjectConnectivity con = comp->getConnectivity();
1412 QStringList dependencies;
1414 for (DependencyMap::iterator i = con.dependencies.begin(); i != con.dependencies.end(); i++)
1416 ManagedIceObjectDependencyBasePtr& dep = i->second;
1418 if (!dep->getResolved() || comp->getState() == eManagedIceObjectStarted)
1420 dependencies << QString::fromStdString(dep->getName());
1424 titlebar->
changeStatus((ManagedIceObjectState)comp->getState(), dependencies);
1429 void ArmarXMainWindow::enterFullscreenMode()
1432 ui->toolBar->hide();
1433 ui->menubar->hide();
1434 ui->statusbar->hide();
1437 leaveFullScreenActionF11 =
new QAction(
this);
1438 leaveFullScreenActionF11->setShortcut(Qt::Key_F11);
1439 connect(leaveFullScreenActionF11, SIGNAL(triggered()),
this, SLOT(leaveFullscreenMode()));
1440 addAction(leaveFullScreenActionF11);
1442 leaveFullScreenActionEsc =
new QAction(
this);
1443 leaveFullScreenActionEsc->setShortcut(Qt::Key_Escape);
1444 connect(leaveFullScreenActionEsc, SIGNAL(triggered()),
this, SLOT(leaveFullscreenMode()));
1445 addAction(leaveFullScreenActionEsc);
1448 void ArmarXMainWindow::leaveFullscreenMode()
1451 removeAction(leaveFullScreenActionF11);
1452 leaveFullScreenActionF11 =
nullptr;
1454 removeAction(leaveFullScreenActionEsc);
1455 leaveFullScreenActionEsc =
nullptr;
1458 ui->toolBar->show();
1459 ui->menubar->show();
1460 ui->statusbar->show();
1463 void ArmarXMainWindow::toggleWidgetLock()
1465 QList<ArmarXDockWidget*> dockWidgets = findChildren<ArmarXDockWidget*>();
1469 for (
auto& widget : dockWidgets)
1471 widget->unlockWidget();
1477 for (
auto& widget : dockWidgets)
1479 widget->lockWidget();
1483 widgetsLocked = !widgetsLocked;
1493 : QAction(widgetName, parent),
1507 if (widgetName.isEmpty())
1509 QLineEdit* edit = qobject_cast<QLineEdit*>(sender());
1512 widgetName = edit->text();
1520 setText(widgetName);
1521 setData(widgetName);
1532 dialog->setModal(
true);
1552 scrollArea =
new QScrollArea();
1553 scrollArea->setWidgetResizable(
true);
1555 QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1556 scrollArea->setSizePolicy(sizePolicy);
1557 setWidget(scrollArea);
1559 savedTitleBar =
nullptr;
1570 scrollArea->setWidget(widget);
1586 emit destroyed(
this);
1594 ARMARX_INFO <<
"Locking widget: " << objectName();
1595 savedTitleBar = titleBarWidget();
1596 setTitleBarWidget(
new QWidget());
1605 ARMARX_INFO <<
"Unlocking widget: " << objectName();
1606 if (savedTitleBar !=
nullptr)
1608 QWidget* old = titleBarWidget();
1609 setTitleBarWidget(savedTitleBar);
1610 savedTitleBar =
nullptr;
1626 QAction(text, parent),
1642 void armarx::ArmarXMainWindow::on_actionClear_tip_blacklist_triggered()
1644 tipDialog->setBlackListedStrings(QStringList());
1646 mainSettings.sync();
1650 void armarx::ArmarXMainWindow::on_actionAbout_triggered()
1652 QMessageBox::about(
this,
"ArmarX Graphical User Interface", QString(
"ArmarX is being developed at the High Performance Humanoid Technologies (H2T) lab at the Karlsruhe Institute of Technology (KIT)\nCopyright H2T, KIT, ")
1653 + QString(&__DATE__[ 7]) +
1657 void armarx::ArmarXMainWindow::on_actionLoadLastConfig_toggled(
bool toggled)
1660 mainSettings.sync();
1666 void armarx::ArmarXMainWindow::on_actionArmarX_Documentation_triggered()
1668 QDesktopServices::openUrl(QUrl(
"http://armarx.humanoids.kit.edu/"));
1671 void armarx::ArmarXMainWindow::on_actionOpen_Use_Case_triggered()
1673 guiUseCaseSelector->setCancelButtonText(
"Cancel");
1674 if (guiUseCaseSelector->exec() == QDialog::Accepted)
1676 QString path = guiUseCaseSelector->getSelectedConfigFilePath();
1678 if (!path.isEmpty())
1680 loadGuiConfig(path,
false);
1683 mainSettings.setValue(
"DoNotShowUseCaseDialog", guiUseCaseSelector->getDoNotShowAgain());
1687 void armarx::ArmarXMainWindow::on_actionClear_plugin_cache_triggered()
1689 pluginCache.clearCacheFile();
1692 void ArmarXMainWindow::updateOpenWidgetButtonStatus(QString widgetName)
1697 void ArmarXMainWindow::openWidgetButtonClicked()
1699 addWidgetAction->
triggered(searchField->text());
1702 void ArmarXMainWindow::onContextMenuFavoritesRequested(
const QPoint& pos)
1706 auto numberOfFavIcons =
new QSpinBox(&menu);
1707 numberOfFavIcons->setRange(1, 100);
1708 numberOfFavIcons->setSingleStep(1);
1709 numberOfFavIcons->setValue(mainSettings.value(
"FavoriteWidgetCount", 6).toInt());
1710 numberOfFavIcons->setToolTip(
"Max number of favorites");
1711 connect(numberOfFavIcons, SIGNAL(valueChanged(
int)),
this, SLOT(onNumberOfMaxFavoritesChanged(
int)));
1713 QWidgetAction* action =
new QWidgetAction{&menu};
1714 action->setDefaultWidget(numberOfFavIcons);
1715 menu.addAction(action);
1716 menu.exec(favoritesLabel->mapToGlobal(pos));
1719 void ArmarXMainWindow::onNumberOfMaxFavoritesChanged(
int i)
1721 mainSettings.setValue(
"FavoriteWidgetCount", i);
1722 updatefavoriteActions();
1725 void ArmarXMainWindow::updatefavoriteActions()
1729 favoriteActionWidgetNames ==
list
1736 favoriteActionWidgetNames =
list;
1737 for (
auto* action : favoriteActions)
1739 ui->toolBar->removeAction(action);
1740 action->deleteLater();
1742 favoriteActions.clear();
1743 for (
auto widgetName : favoriteActionWidgetNames)
1745 if (actionList.contains(widgetName))
1747 bool allowText =
true;
1748 favoriteActions.emplace_back(addActionToToolBar(actionList[widgetName], allowText));