26#include <QCoreApplication>
27#include <QInputDialog>
36#include <IceUtil/UUID.h>
38#include <SimoxUtility/algorithm/string/string_tools.h>
42#include <ArmarXCore/interface/statechart/RemoteStateOffererIce.h>
64 setlocale(LC_ALL,
"C");
66 QSettings s(
"KIT",
"ArmarXStatechartEditor");
67 config.lockRemoteStates = s.value(
"lockRemoteStates",
true).toBool();
68 config.searchPaths = s.value(
"searchPaths").toStringList();
80 QSettings s(
"KIT",
"ArmarXStatechartEditor");
81 s.setValue(
"lockRemoteStates",
config.lockRemoteStates);
82 s.setValue(
"searchPaths",
config.searchPaths);
89 if (basePath.isEmpty())
97 for (std::filesystem::recursive_directory_iterator end, dir(basePath.toUtf8().data());
98 dir != end &&
getState() < eManagedIceObjectExiting;
101 std::string path(dir->path().c_str());
103 if (dir->path().extension() ==
".scgxml")
106 if (path.find(
"deprecated") != std::string::npos)
108 ARMARX_INFO <<
"Skipping deprecated Statechart Group " << path;
112 result << dir->path().c_str();
118 QCoreApplication::processEvents();
122 catch (std::exception& e)
139 QTimer::singleShot(0,
this, SLOT(initWidget()));
142 stateWatcher,
"StateWatcher" + IceUtil::generateUUID(),
false);
153 if (executionStatusTask)
155 executionStatusTask->stop();
176 if (settings->contains(
"selectedProfile"))
178 config.selectedProfile = profiles->getProfileByName(
179 settings->value(
"selectedProfile").toString().toStdString());
187 config.selectedProfile = profiles->getProfileByName(profiles->GetRootName());
190 config.openAllStatesWasSelected = settings->value(
"openAllStatesSelected",
false).toBool();
211 if (
config.selectedProfile)
213 settings->setValue(
"selectedProfile",
214 QString::fromStdString(
config.selectedProfile->getName()));
217 settings->setValue(
"openAllStatesSelected",
config.openAllStatesWasSelected);
225 if (node && node->getState())
227 int index = editor->getStateTabWidget()->getStateTab(node->getState());
229 "You can move states by holding the SHIFT + left click button. You can move the "
230 "scene by holding ALT + move mouse.",
231 "State Interaction");
235 editor->getStateTabWidget()->addStateTab(node->getState());
239 editor->getStateTabWidget()->setCurrentIndex(
index);
247 treeController->saveAll();
257 treeController->selectNodeByState(view->
getStateInstance()->getStateClass());
266 QList<QString> selectedProxies;
276 if (d.exec() == QDialog::Accepted)
294 if (d.exec() == QDialog::Accepted)
297 config.searchPaths.removeDuplicates();
306 stateEditorController->setLockRemoteStatesByDefault(
config.lockRemoteStates);
314 editor->getUI()->treeViewProgressBar->show();
315 editor->getUI()->treeViewProgressBar->setMaximum(groups.size());
317 foreach (QString groupPath, groups)
319 treeController->onOpenGroup(groupPath);
320 editor->getUI()->treeViewProgressBar->setValue(i);
322 qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
324 editor->getUI()->treeViewProgressBar->hide();
330 paths.removeDuplicates();
332 foreach (QString path, paths)
342 StatechartView* view = editor->getUI()->stateTabWidget->currentStateview();
356 if (stateInstance && stateInstance->getStateClass())
358 StateTreeNodePtr node = treeController->getNodeByState(stateInstance->getStateClass());
362 std::string filePath = node->getBoostCppFilePath().c_str();
371 watcher->removePath(path);
372 std::string fileContent;
374 if (std::filesystem::exists(path.toUtf8().data()))
376 watcher->addPath(path);
381 fileContent =
"<cpp missing>";
384 int line = editor->getUI()->textEditCppCode->textCursor().blockNumber();
385 QTextCursor cursor = editor->getUI()->textEditCppCode->textCursor();
386 cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, line);
387 editor->getUI()->textEditCppCode->setText(QString::fromUtf8(fileContent.c_str()));
388 editor->getUI()->textEditCppCode->setTextCursor(cursor);
394 editor->getUI()->textEditCppCode->find(
"::CreateInstance(");
395 editor->getUI()->textEditCppCode->find(
"::onEnter()", QTextDocument::FindBackward);
401 editor->getUI()->textEditCppCode->find(
"::CreateInstance(");
402 editor->getUI()->textEditCppCode->find(
"::run()", QTextDocument::FindBackward);
408 editor->getUI()->textEditCppCode->find(
"::CreateInstance(");
409 editor->getUI()->textEditCppCode->find(
"::onBreak()", QTextDocument::FindBackward);
415 editor->getUI()->textEditCppCode->find(
"::CreateInstance(");
416 editor->getUI()->textEditCppCode->find(
"::onExit()", QTextDocument::FindBackward);
424 if (editor->getUI()->stateTabWidget->currentStateview())
428 editor->getUI()->stateTabWidget->currentStateview()->getScene()->selectedItems();
430 for (QGraphicsItem* item : selection)
451 auto node = treeController->getNodeByState(state);
453 if (node && node->isState())
455 treeController->openStateCPP(node);
467 editor->getStateTabWidget()->clear();
473 StatechartView* view = editor->getUI()->stateTabWidget->currentStateview();
474 if (!executedOpenedGroup)
482 if (node->isPublic())
484 treeController->executeGroupWithDependencies(
487 executedOpenedGroup = node->getGroup();
488 editor->getUI()->toolButtonRunState->setIcon(QIcon(
":/icons/delete.ico"));
489 editor->getUI()->toolButtonRunState->setToolTip(
490 "Stop the Statechart Group");
491 editor->getUI()->toolButtonWatchStateExecution->setEnabled(
false);
492 editor->getUI()->labelExecutionState->setVisible(
true);
493 alreadyWatchingState =
false;
494 executionStatusTask->start();
498 QMessageBox::warning(
500 "Execution not possible",
501 "You can only execute public state. Right-click on the state in the "
502 "tree view on the left and select 'Public State'.");
508 QMessageBox::warning(
510 "Execution not possible",
511 "You need to open a state before executing it with this button.");
516 if (executedOpenedGroup)
518 treeController->stopGroupExecutionWithDependencies(executedOpenedGroup);
519 executedOpenedGroup.reset();
520 executionStatusTask->stop();
521 editor->getUI()->labelExecutionState->setVisible(
false);
523 editor->getUI()->toolButtonRunState->setToolTip(
"Start the Statechart Group");
524 editor->getUI()->toolButtonRunState->setIcon(QIcon(
":/icons/run.svg"));
525 editor->getUI()->toolButtonWatchStateExecution->setEnabled(
true);
530 std::function<void(
StateItem * state)> unsubscriptionLamba;
531 unsubscriptionLamba = [&](
StateItem* state)
533 stateWatcher->unsubscribeState(state);
538 unsubscriptionLamba(stateInstance);
547 StatechartEditorController::updateExecutionButtonStatus()
549 bool changeToWaiting =
false;
550 QString labelText =
"";
551 if (executedOpenedGroup)
553 std::string proxyName =
554 executedOpenedGroup->getName().toStdString() +
"StateComponentAppManager";
556 executedOpenedGroup->getName().toStdString() +
557 "RemoteStateOfferer";
558 ArmarXManagerInterfacePrx stateComponentProxy =
566 else if (stateComponentProxy)
568 auto state = stateComponentProxy->getObjectState(objName);
569 if (state != eManagedIceObjectStarted)
573 stateComponentProxy->getObjectConnectivity(objName).dependencies)
575 ManagedIceObjectDependencyBasePtr dep = elem.second;
576 if (!dep->getResolved())
578 if (deps.size() >= 2)
580 deps.push_back(
"...");
585 deps.push_back(dep->getName());
589 labelText =
"Waiting for dependencies: " +
590 QString::fromStdString(simox::alg::join(deps,
", "));
591 changeToWaiting =
true;
596 labelText =
"Waiting for statechart group to start";
597 changeToWaiting =
true;
600 catch (
const Ice::Exception& e)
602 labelText =
"Waiting for statechart group to start (ice-exception catched)";
603 changeToWaiting =
true;
608 labelText =
"Waiting for statechart group to start (exception catched)";
609 changeToWaiting =
true;
612 if (!changeToWaiting)
614 labelText =
"Statechart group is running";
615 if (editor->getUI()->toolButtonWatchStateExecution->isChecked() &&
616 !alreadyWatchingState)
622 QMetaObject::invokeMethod(editor->getUI()->labelExecutionState,
624 Qt::QueuedConnection,
625 Q_ARG(QString, labelText));
630 StatechartEditorController::watchState(
const std::string& objName)
632 RemoteStateOffererInterfacePrx statechartHandler =
635 StatechartView* view = editor->getUI()->stateTabWidget->currentStateview();
638 std::string globalStateName =
640 view->getStateInstance()->getStateClass()->getStateName().toStdString();
641 QMap<QString, StateInstanceData> instanceData =
642 view->getScene()->getStateInstanceData();
643 auto toplevelPathString = view->getScene()->getTopLevelStateItem()->getFullStatePath();
645 statechartHandler->begin_getStatechartInstanceByGlobalIdStr(globalStateName);
646 while (!asyncResult->isCompleted())
648 if (
getState() >= eManagedIceObjectExiting)
655 armarx::StateIceBasePtr stateptr =
656 statechartHandler->end_getStatechartInstanceByGlobalIdStr(asyncResult);
665 std::function<void(StateIceBasePtr iceState, StateItem * state)> subscriptionLamba;
666 subscriptionLamba = [&](StateIceBasePtr iceState, StateItem* state)
668 stateWatcher->subscribeToState(iceState, state);
670 for (
auto stateInstance : state->getSubstateItems())
672 if (stateInstance->getStateInstance()->getStateClass() &&
673 iceState->subStateList.size() > i)
676 StateIceBasePtr::dynamicCast(iceState->subStateList.at(i)),
682 subscriptionLamba(stateptr, view->getScene()->getTopLevelStateItem());
684 alreadyWatchingState =
true;
698 return qobject_cast<QWidget*>(editor);
702 StatechartEditorController::initWidget()
704 getWidget()->setFocusPolicy(Qt::WheelFocus);
716 eventuallyNamespacedPackage,
"",
true, variantInfo);
719 editor->setVariantInfo(variantInfo);
720 editor->setCurrentProfile(
config.selectedProfile);
721 editor->getUI()->toolBarViewControl->addWidget(
new QLabel(
722 QString::fromStdString(
"Selected Profile: " +
config.selectedProfile->getFullName())));
723 editor->getUI()->toolBarViewControl->insertWidget(
724 editor->getUI()->actionEdit_State_Properties,
new QLabel(
"Active State:"));
726 QList<QVariant> header;
727 header.push_back(QString(
"TEST"));
731 editor->getUI()->treeViewGroups,
732 editor->getUI()->lineEditStateSearch,
739 QStringList searchPaths;
740 if (
config.openAllStatesWasSelected)
742 for (std::string eventuallyNamespacedPackage :
config.selectedProfile->getAllPackages())
745 const auto elements = simox::alg::split(eventuallyNamespacedPackage,
"::");
748 const std::string cmakePackageName =
749 simox::alg::replace_all(eventuallyNamespacedPackage,
"::",
"_");
751 for (
const auto& includePath :
752 CMakePackageFinder(cmakePackageName).getIncludePathList())
756 if (elements.size() == 1)
758 std::filesystem::path packageStatechartPath(includePath.c_str());
759 packageStatechartPath /= cmakePackageName;
760 packageStatechartPath /=
"statecharts";
762 if (std::filesystem::exists(packageStatechartPath) &&
763 !std::filesystem::exists(
764 packageStatechartPath /
765 "cmake_install.cmake"))
768 << packageStatechartPath.string();
769 searchPaths.push_back(packageStatechartPath.c_str());
773 if (elements.size() == 2)
775 std::filesystem::path packageStatechartPathArmarXPackage(
776 includePath.c_str());
778 packageStatechartPathArmarXPackage /= elements.at(0);
779 packageStatechartPathArmarXPackage /= elements.at(1);
780 packageStatechartPathArmarXPackage /=
"statecharts";
784 if (std::filesystem::exists(packageStatechartPathArmarXPackage) &&
785 !std::filesystem::exists(
786 packageStatechartPathArmarXPackage /
787 "cmake_install.cmake"))
790 << packageStatechartPathArmarXPackage.string();
791 searchPaths.push_back(packageStatechartPathArmarXPackage.c_str());
797 config.searchPaths.removeDuplicates();
800 connect(editor->getUI()->actionNew_State_Definition,
802 treeController.get(),
803 SLOT(onNewStateDefinition()));
804 connect(editor->getUI()->actionDelete_State_Definition,
806 treeController.get(),
807 SLOT(onDeleteNode()));
808 connect(editor->getUI()->treeViewGroups,
809 SIGNAL(doubleClicked(QModelIndex)),
811 connect(editor->getUI()->actionSave_State, SIGNAL(triggered()), SLOT(
requestSave()));
812 connect(editor->getUI()->stateTabWidget,
813 SIGNAL(currentChanged(
int)),
815 connect(editor->getUI()->actionNew_Statechart_Group,
819 connect(editor->getUI()->actionOpenStatechartGroup,
821 treeController.get(),
822 SLOT(onOpenGroup()));
823 connect(editor->getUI()->actionSettings,
827 connect(editor->getUI()->toolButtonRunState,
828 SIGNAL(clicked(
bool)),
832 connect(treeController.get(), SIGNAL(closeAllTabsRequested()),
this, SLOT(
closeAllTabs()));
835 editor->getUI()->actionOpenStatechartGroup->setShortcutContext(
836 Qt::WidgetWithChildrenShortcut);
837 editor->getUI()->actionOpenStatechartGroup->setShortcut(tr(
"Ctrl+O"));
838 getWidget()->addAction(editor->getUI()->actionOpenStatechartGroup);
841 stateEditorController.reset(
new StateEditorController(editor,
847 stateEditorController->setLockRemoteStatesByDefault(
config.lockRemoteStates);
848 connect(editor->getUI()->stateTabWidget,
849 SIGNAL(currentChanged(
int)),
852 Qt::UniqueConnection);
853 connect(editor->getUI()->radioOnEnter,
857 Qt::UniqueConnection);
858 connect(editor->getUI()->radioOnBreak,
862 Qt::UniqueConnection);
863 connect(editor->getUI()->radioRun,
867 Qt::UniqueConnection);
868 connect(editor->getUI()->radioOnExit,
872 Qt::UniqueConnection);
876 editor->getUI()->btnOpenCppCode, SIGNAL(clicked()),
this, SLOT(
openSelectedState()));
878 watcher =
new QFileSystemWatcher(editor);
884 treeController->collapseAll();
885 executionStatusTask =
new PeriodicTask<StatechartEditorController>(
886 this, &StatechartEditorController::updateExecutionButtonStatus, 300);
902 config.selectedProfile = dialog->getSelectedProfile();
903 config.openAllStatesWasSelected = dialog->openAllStatesIsSelected();
918 return qobject_cast<StatechartEditorConfigDialog*>(dialog);
static ApplicationPtr getInstance()
Retrieve shared pointer to the application object.
QString getGroupName() const
QMap< QString, QString > getConfigurations() const
QString getGroupDescription() const
QList< QString > getProxies() const
bool contextGenerationEnabled() const
QString getPackageName() const
QString getGroupPath() const
IceManagerPtr getIceManager() const
Returns the IceManager.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
Ice::CommunicatorPtr getCommunicator() const
int getState() const
Retrieve current state of the ManagedIceObject.
ArmarXManagerPtr getArmarXManager() const
Returns the ArmarX manager used to add and remove components.
static std::string ReadFileContents(const std::string &path)
QVector< StateItem * > getSubstateItems() const
statechartmodel::StateInstancePtr getStateInstance() const
StateItem * getTopLevelStateItem() const
void clearActiveSubstates()
void storeAutoSaveSettings()
void onInitComponent() override
Pure virtual hook for the subclass.
bool onClose() override
If you overwrite this method, make sure to call this implementation at the end of your implementation...
void executeOpenedState(bool)
void openStatechartGroups(QStringList groups)
void onDisconnectComponent() override
Hook for subclass.
void loadSettings(QSettings *settings) override
Implement to load the settings that are part of the GUI configuration.
void showStatechartEditorSettingsDialog()
~StatechartEditorController() override
void saveSettings(QSettings *settings) override
Implement to save the settings as part of the GUI configuration.
void showCodeFileContent(const QString &path)
void showStateCode(statechartmodel::StateInstancePtr stateInstance)
void showOnExitFunction()
void searchAndOpenPaths(QStringList paths)
QStringList findAllStatechartGroupDefinitions(const QString &basePath)
QPointer< QWidget > getWidget() override
getWidget returns a pointer to the a widget of this controller.
void onConnectComponent() override
Pure virtual hook for the subclass.
void showOnBreakFunction()
void configured() override
This function must be implemented by the user, if he supplies a config dialog.
void showOnEnterFunction()
void connectToView(int tabIndex)
void treeviewGroupsDoubleClicked(QModelIndex index)
void onExitComponent() override
Hook for subclass.
QPointer< QDialog > getConfigDialog(QWidget *parent) override
getConfigDialog returns a pointer to the a configuration widget of this controller.
void showNewStatechartGroupDialog()
StatechartEditorController()
void onStateTabChanged(int index)
struct armarx::StatechartEditorController::Config config
void setRemoteStatesLocked(bool locked)
QStringList getPaths() const
bool getRemoteStatesLocked() const
void setPaths(QStringList paths)
static StatechartProfilesPtr ReadProfileFiles(const std::vector< std::string > &packages)
void showSubSubstates(bool show=true)
statechartmodel::StateInstancePtr getStateInstance() const
StateScene * getScene() const
static VariantInfoPtr ReadInfoFilesRecursive(const std::string &rootPackageName, const std::string &rootPackagePath, bool showErrors, VariantInfoPtr variantInfo=VariantInfoPtr())
static VariantInfoPtr ReadInfoFiles(const std::vector< std::string > &packages, bool showErrors=true, bool throwOnError=true)
#define ARMARX_INFO
The normal logging level.
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
std::shared_ptr< State > StatePtr
std::shared_ptr< StateInstance > StateInstancePtr
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< StatechartGroup > StatechartGroupPtr
std::shared_ptr< StateTreeNode > StateTreeNodePtr
StatechartProfilePtr selectedProfile