28 #include <QDialogButtonBox>
29 #include <QFileDialog>
31 #include <QInputDialog>
34 #include <QMessageBox>
35 #include <QProgressDialog>
55 #include "../StatechartViewerPlugin/model/DynamicRemoteStateClass.h"
61 using namespace statechartio;
62 using namespace statechartmodel;
66 QList<QVariant> headerInfo,
68 QLineEdit* filterLineEdit,
73 QAbstractItemModel(parent)
75 qRegisterMetaType<StateTreeNodePtr>(
"StateTreeNodePtr");
78 "XMLRemoteStateOffererRun", finder.
getBinaryDir(),
"ArmarXCore"));
79 this->variantInfo = variantInfo;
80 this->profiles = statechartProfiles;
81 this->currentProfile = currentProfile;
82 this->packageTool = packageTool;
83 this->headerInfo = headerInfo;
84 this->treeView = treeView;
86 this->rootNode = this->stateTreeModel->getRootNode();
87 this->groupCloner = std::make_shared<GroupCloner>(stateTreeModel, packageTool);
88 this->groupRenamer = std::make_shared<GroupRenamer>(groupCloner);
89 this->communicator =
ic;
93 proxyModel->setSourceModel(
this);
94 proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
95 treeView->setModel(proxyModel);
98 contextMenuGroup =
new QMenu(treeView);
99 contextMenuFolder =
new QMenu(treeView);
100 contextMenuState =
new QMenu(treeView);
101 treeView->setContextMenuPolicy(Qt::CustomContextMenu);
103 actionDeleteNode =
new QAction(QIcon(
":/icons/delete.ico"),
"Delete", treeView);
104 actionMakeStatePublic =
new QAction(
"Public State", treeView);
105 actionMakeStatePublic->setCheckable(
true);
106 actionNewFolder =
new QAction(QIcon(
":/icons/folder-new.svg"),
"Add new Folder", treeView);
107 actionNewStateDefinition =
108 new QAction(QIcon(
":/icons/images/add-state.png"),
"Add new State Definition", treeView);
109 actionNewDynamicRemoteStateDefinition =
110 new QAction(
"Add new Dynamic Remote State Definition", treeView);
111 actionFindStateUsages =
new QAction(QIcon(
":/icons/search.svg"),
"Find State Usages", treeView);
112 actionRenameState =
new QAction(QIcon(
":/icons/rename.svg"),
"Rename State", treeView);
113 actionOpenCMakeProject =
114 new QAction(QIcon(
":/icons/qt-small.png"),
"Open CMake Project", treeView);
115 actionShowFullPath =
new QAction(QIcon(
":/icons/search.svg"),
"Show Full Path", treeView);
116 actionOpenStateCPP =
new QAction(QIcon(
":/icons/cpp.svg"),
"Open C++ Code", treeView);
118 new QAction(QIcon(
":/icons/run.svg"),
"Execute Statechart Group", treeView);
121 actionGenerateStateCPP =
122 new QAction(QIcon(
":/icons/document-properties.svg"),
"Generate State C++ Files", treeView);
123 actionRenameGroup =
new QAction(QIcon(
":/icons/rename.svg"),
"Rename Group", treeView);
124 actionCloneGroup =
new QAction(QIcon(
":/icons/clone.svg"),
"Clone Group", treeView);
125 actionGroupProperties =
126 new QAction(QIcon(
":/icons/document-properties.svg"),
"Group Properties", treeView);
128 QList<QAction*> groupActions, folderActions, stateActions;
130 groupActions.append(actionNewStateDefinition);
131 groupActions.append(actionNewDynamicRemoteStateDefinition);
132 groupActions.append(actionNewFolder);
133 groupActions.append(actionDeleteNode);
134 groupActions.append(actionOpenCMakeProject);
135 groupActions.append(actionShowFullPath);
136 groupActions.append(actionExecuteGroup);
138 groupActions.append(actionRenameGroup);
139 groupActions.append(actionCloneGroup);
140 groupActions.append(actionGroupProperties);
142 folderActions.append(actionNewStateDefinition);
143 folderActions.append(actionNewDynamicRemoteStateDefinition);
144 folderActions.append(actionNewFolder);
145 folderActions.append(actionDeleteNode);
147 stateActions.append(actionMakeStatePublic);
148 stateActions.append(actionFindStateUsages);
149 stateActions.append(actionRenameState);
150 stateActions.append(actionDeleteNode);
151 stateActions.append(actionOpenStateCPP);
153 stateActions.append(actionGenerateStateCPP);
155 for (QAction*
a : groupActions)
157 a->setIconVisibleInMenu(
true);
160 for (QAction*
a : folderActions)
162 a->setIconVisibleInMenu(
true);
165 for (QAction*
a : stateActions)
167 a->setIconVisibleInMenu(
true);
170 contextMenuGroup->addActions(groupActions);
171 contextMenuFolder->addActions(folderActions);
172 contextMenuState->addActions(stateActions);
175 connect(stateTreeModel.get(), SIGNAL(stateAddedOrRemoved()), SLOT(stateAddedOrRemoved()));
176 connect(treeView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(
onContextMenu(QPoint)));
179 connect(actionNewDynamicRemoteStateDefinition,
182 connect(actionDeleteNode, SIGNAL(triggered()), SLOT(
onDeleteNode()));
183 connect(actionMakeStatePublic, SIGNAL(triggered(
bool)), SLOT(
onMakeStatePublic(
bool)));
184 connect(actionNewFolder, SIGNAL(triggered()), SLOT(
onNewFolder()));
186 connect(actionRenameState, SIGNAL(triggered()), SLOT(
onRenameState()));
187 connect(actionOpenCMakeProject, SIGNAL(triggered()),
this, SLOT(
onOpenCMakeProject()));
188 connect(actionShowFullPath, SIGNAL(triggered()),
this, SLOT(
onShowFullPath()));
189 connect(actionOpenStateCPP, SIGNAL(triggered()),
this, SLOT(
onOpenStateCPP()));
190 connect(actionExecuteGroup, SIGNAL(triggered()),
this, SLOT(
onExecuteGroup()));
194 connect(actionRenameGroup, SIGNAL(triggered()),
this, SLOT(
onRenameGroup()));
195 connect(actionCloneGroup, SIGNAL(triggered()),
this, SLOT(
onCloneGroup()));
196 connect(actionGroupProperties, SIGNAL(triggered()),
this, SLOT(
onGroupProperties()));
198 connect(filterLineEdit,
199 SIGNAL(textChanged(QString)),
201 SLOT(setFilterFixedString(QString)));
202 connect(filterLineEdit, SIGNAL(textChanged(QString)),
this, SLOT(expandFilterResults(QString)));
208 ARMARX_INFO <<
"Killing " << processes.size() <<
" statechart processes";
209 for (
auto& process : processes)
212 process->terminate();
214 for (
auto& process : processes)
216 ARMARX_INFO <<
"Waiting for process " << process->pid();
217 process->waitForFinished(2000);
219 for (
auto& process : processes)
221 if (process->pid() > 0)
232 if (!
index.isValid())
241 case Qt::DisplayRole:
244 return node->getDisplay() + (node->getState() ?
"" :
" [no .xml]") +
245 (node->getCppExists() ?
"" :
" [no .cpp]") +
246 (node->isPublic() ?
" (public)" :
"") +
253 return node->getDisplay();
256 case Qt::DecorationRole:
262 return getIcon(
":/icons/folder-locked.svg");
264 if (treeView->isExpanded(
index))
266 return getIcon(
":/icons/folder-open.svg");
270 return getIcon(
":/icons/folder.svg");
275 if (node->getState())
277 if (node->getState()->getSubstates().count() > 0)
279 return getIcon(node->isPublic() ?
":/statechart-editor/states-public.svg"
280 :
":/statechart-editor/states.svg");
284 return getIcon(node->isPublic() ?
":/statechart-editor/state-public.svg"
285 :
":/statechart-editor/state.svg");
290 return getIcon(
":/statechart-editor/state-broken.svg");
296 case Qt::ToolTipRole:
298 return QString::fromStdString(node->getAbsoluteBoostPath().string());
308 if (!
index.isValid())
315 flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
319 if (node->getState() || node->isGroup())
321 flags |= Qt::ItemIsDragEnabled;
331 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
333 return headerInfo.value(section);
342 if (!hasIndex(row, column, parentIndex))
344 return QModelIndex();
349 if (!parentIndex.isValid())
351 parentNode = this->rootNode.get();
355 parentNode =
static_cast<StateTreeNode*
>(parentIndex.internalPointer());
362 return createIndex(row, column, childNode);
366 return QModelIndex();
373 if (!
index.isValid())
375 return QModelIndex();
381 if (parentNode == rootNode)
383 return QModelIndex();
386 return createIndex(parentNode->row(), 0, parentNode.get());
400 return rootNode->childCount();
405 <<
"The internal pointer of a tree node is zero";
421 return rootNode->columnCount();
428 bool load = !groupDefinitionFile.isEmpty();
431 QFileDialog selectGroupFile(treeView,
"Open Statechart Group");
433 selectGroupFile.setOption(QFileDialog::ReadOnly,
true);
434 selectGroupFile.setOption(QFileDialog::HideNameFilterDetails,
false);
435 selectGroupFile.setFileMode(QFileDialog::ExistingFile);
437 urls << QUrl::fromLocalFile(
438 QDesktopServices::storageLocation(QDesktopServices::HomeLocation))
439 << QUrl::fromLocalFile(
440 QDesktopServices::storageLocation(QDesktopServices::DesktopLocation));
447 selectGroupFile.setSidebarUrls(urls);
449 filters <<
"Statechart Group (*.scgxml)";
450 filters <<
"All Files(*.*)";
451 selectGroupFile.setNameFilters(filters);
452 load = selectGroupFile.exec() == QDialog::Accepted;
453 if (
load && groupDefinitionFile.isEmpty())
455 groupDefinitionFile = selectGroupFile.selectedFiles().first();
473 stateTreeModel->loadGroupStates(group);
475 catch (std::exception& e)
477 QString reason(QString::fromStdString(e.what()));
478 reason.truncate(200);
480 QMessageBox::warning(0,
481 "Error while loading States",
482 QString(
"An error while loading states - Reason:\n" + reason));
485 catch (std::exception& e)
487 QString reason = QString::fromStdString(e.what());
488 reason.truncate(200);
489 QMessageBox::warning(0,
490 "Error while loading Statechart Group",
491 QString(
"An error while loading the statechart group file '") +
492 groupDefinitionFile +
"' - Reason:\n" + reason);
505 this->layoutAboutToBeChanged();
513 rootNode->appendChild(group->getRootNode());
514 rootNode->sortChildren();
516 this->layoutChanged();
519 treeView->expand(getIndex(groupNode));
520 treeView->setCurrentIndex(getIndex(groupNode));
527 const QString& groupPath,
528 const QString& description,
529 const QString& packageName,
530 const QList<QString> proxies,
531 bool generateContext,
532 const QMap<QString, QString>& statechartGroupConfigurations)
535 std::filesystem::path defPath = groupPath.toUtf8().data();
536 defPath /= (groupName +
".scgxml").
toUtf8().data();
544 statechartGroupConfigurations,
548 group->setRootNode(groupRootNode);
550 stateTreeModel->addGroup(group);
551 rootNode->appendChild(group->getRootNode());
553 rootNode->sortChildren();
557 QMetaObject::invokeMethod(
558 this,
"selectNode", Qt::QueuedConnection, Q_ARG(
StateTreeNodePtr, group->getRootNode()));
566 stateTreeModel->loadAllStates();
572 return stateTreeModel->getNodeByState(state);
578 QModelIndex selected = treeView->currentIndex();
580 if (!selected.isValid())
591 return node ? node->getClosestParentFolderOrGroupNode() :
StateTreeNodePtr();
667 QList<StateInstancePtr> instances = stateTreeModel->findStateUsages(node);
669 if (instances.count() > 0)
671 QString
message = QString(
"Cannot delete state, it is still being used by %1 state(s):\n%2")
672 .arg(instances.count())
673 .arg(buildStateUsageString(instances));
674 QMessageBox::warning(NULL,
"Cannot delete State",
message);
678 if (node->getState())
680 QString question = QString(
"You are about to delete the State Definition '%1'.\nDo you "
681 "also want to permanently remove the underlying file %2?")
682 .arg(node->getDisplay(), node->getBasename());
683 QMessageBox::StandardButton reply =
684 QMessageBox::question(NULL,
685 "Delete State Definition File?",
689 if (reply == QMessageBox::Cancel)
695 std::filesystem::remove(node->getAbsoluteBoostPath());
696 if (node->getCppExists())
698 std::filesystem::remove(node->getBoostCppFilePath());
699 std::filesystem::remove(node->getBoostHFilePath());
700 std::filesystem::remove(node->getBoostGeneratedHFilePath());
706 QString question = QString(
"Remove State Definition '%1'?").arg(node->getDisplay());
707 QMessageBox::StandardButton reply = QMessageBox::question(
708 NULL,
"Delete State Definition?", question, QMessageBox::Ok | QMessageBox::Cancel);
710 if (reply == QMessageBox::Cancel)
719 QString::fromUtf8((node->getGroup()->getBoostDefinitionFilePath()).c_str()));
725 bool createDynamicRemoteState)
727 this->layoutAboutToBeChanged();
731 if (!createDynamicRemoteState)
734 state->addEndSubstate(
"Success",
"Success");
735 state->addEndSubstate(
"Failure",
"Failure");
737 evt->name =
"Failure";
739 "Event for statechart-internal failures or optionally user-code failures";
740 state->setOutgoingEvents(
EventList{evt});
748 state->setStateName(name);
752 stateTreeModel->setNodeState(node, state);
753 parent->appendChild(node);
755 stateTreeModel->notifyNewStateTreeNode(node);
756 this->layoutChanged();
757 treeView->sortByColumn(0, Qt::AscendingOrder);
759 QMetaObject::invokeMethod(
768 this->layoutAboutToBeChanged();
771 parent->appendChild(node);
774 this->layoutChanged();
776 treeView->expand(getIndex(
parent));
777 treeView->setCurrentIndex(getIndex(node));
785 if (!
index.isValid())
791 if (
index.model() == proxyModel)
806 treeView->setCurrentIndex(proxyModel->mapFromSource(getIndex(node)));
813 QModelIndex
index = treeView->indexAt(point);
823 actionMakeStatePublic->setEnabled(
true);
824 actionRenameState->setEnabled(
true);
825 actionRenameGroup->setEnabled(
true);
826 actionGenerateStateCPP->setEnabled(
true);
827 actionNewFolder->setEnabled(
true);
828 actionNewStateDefinition->setEnabled(
true);
829 actionNewDynamicRemoteStateDefinition->setEnabled(
true);
830 actionOpenCMakeProject->setEnabled(
true);
831 actionOpenStateCPP->setEnabled(
true);
832 actionGroupProperties->setEnabled(
true);
833 actionDeleteNode->setEnabled(
true);
835 auto applyReadOnlyStatusToMenu = [&,
this]()
842 actionMakeStatePublic->setEnabled(writable);
843 actionRenameState->setEnabled(writable);
844 actionRenameGroup->setEnabled(writable);
845 actionGenerateStateCPP->setEnabled(writable);
846 actionNewFolder->setEnabled(writable);
847 actionNewStateDefinition->setEnabled(writable);
848 actionNewDynamicRemoteStateDefinition->setEnabled(writable);
849 actionOpenCMakeProject->setEnabled(writable);
850 actionOpenStateCPP->setEnabled(writable);
851 actionGroupProperties->setEnabled(writable);
852 actionDeleteNode->setEnabled(writable);
859 actionMakeStatePublic->setEnabled(node->getState() != NULL);
860 actionMakeStatePublic->setChecked(node->isPublic());
861 actionFindStateUsages->setEnabled(node->getState() != NULL);
862 actionRenameState->setEnabled(node->isState());
863 actionGenerateStateCPP->setEnabled(!node->getCppExists() &&
864 node->getState()->getType() == eNormalState);
865 actionOpenStateCPP->setEnabled(node->getCppExists());
866 applyReadOnlyStatusToMenu();
867 contextMenuState->exec(treeView->mapToGlobal(point));
869 else if (node->isGroup())
872 QMap<QString, QProcess*>::const_iterator it;
875 && (it = processes.find(node->getGroup()->getGroupPath())) != processes.end() &&
876 it.value()->state() != QProcess::NotRunning)
878 actionExecuteGroup->setText(
"Stop and Execute Statechart Group");
882 actionExecuteGroup->setText(
"Execute Statechart Group");
884 applyReadOnlyStatusToMenu();
885 contextMenuGroup->exec(treeView->mapToGlobal(point));
887 else if (node->isFolder() && node != rootNode)
889 applyReadOnlyStatusToMenu();
890 contextMenuFolder->exec(treeView->mapToGlobal(point));
903 label =
new QLabel(
"Enter the state name",
this);
904 editField =
new QLineEdit(
this);
905 QRegExp rx(
"^([a-zA-Z_]{1})([a-zA-Z_0-9]+)$");
906 QValidator* validator =
new QRegExpValidator(rx,
this);
907 editField->setValidator(validator);
908 setWindowTitle(
"New State Definition");
910 checkbox =
new QCheckBox(
"Create C++ Files",
this);
911 QBoxLayout* layout =
new QBoxLayout(QBoxLayout::TopToBottom,
this);
912 buttonBox =
new QDialogButtonBox(
this);
913 buttonBox->setObjectName(QString::fromUtf8(
"buttonBox"));
914 buttonBox->setOrientation(Qt::Horizontal);
915 buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
916 layout->addWidget(label);
917 layout->addWidget(editField);
918 layout->addWidget(checkbox);
919 layout->addWidget(buttonBox);
920 QObject::connect(buttonBox, SIGNAL(accepted()),
this, SLOT(accept()));
921 QObject::connect(buttonBox, SIGNAL(rejected()),
this, SLOT(reject()));
926 StateTreeController::retrieveNewStateName(QString& newStateName,
928 bool& createCPPFiles,
935 QMessageBox::warning(
936 NULL,
"Nothing selected",
"Error: No state, group or folder selected.");
940 node = node->getClosestParentFolderOrGroupNode();
943 dialog.
checkbox->setEnabled(askForCPPFiles);
945 if (dialog.exec() == QDialog::Rejected)
951 createCPPFiles = dialog.
checkbox->isChecked();
955 QMessageBox::warning(NULL,
957 QString(
"Error: Provided name '%1' does not meet requirements: Has to "
958 "start with a letter, followed by letters and digits. Sorry.")
963 if (node->getGroup()->findNodeByStateName(newStateName))
965 QMessageBox::warning(
967 "Duplicate State Name",
968 QString(
"Error: State with name '%1' exists already. Sorry.").arg(newStateName));
972 if (node->getGroup()->getName() == newStateName)
974 QMessageBox::warning(
975 NULL,
"Name Conflict", QString(
"Error: State cannot have same name as Group. Sorry."));
983 StateTreeController::getIcon(
const QString& path)
const
985 if (!icons.contains(path))
987 icons[path] = QIcon(path);
997 QString newStateName;
999 if (!retrieveNewStateName(newStateName, node, createCPPFiles,
true))
1011 if (!packageTool->addFullXmlStatechart(
1012 newState->getGroup()->getName().toUtf8().data(),
1013 newState->getBoostPathRelativeToGroup().replace_extension().string(),
1014 newState->getGroup()->getPackagePath().toUtf8().data()))
1016 ARMARX_WARNING_S <<
"Creating source files for state " << newStateName <<
" failed";
1021 if (!packageTool->addXmlOnlyXmlStatechart(
1022 newState->getGroup()->getName().toUtf8().data(),
1023 newState->getBoostPathRelativeToGroup().replace_extension().string(),
1024 newState->getGroup()->getPackagePath().toUtf8().data()))
1026 ARMARX_WARNING_S <<
"Creating source files for state " << newStateName <<
" failed";
1030 newState->checkCppExists();
1037 bool createCPPFiles;
1039 QString newStateName;
1041 if (!retrieveNewStateName(newStateName, node, createCPPFiles,
false))
1058 QMessageBox::warning(
1059 NULL,
"Nothing selected",
"Error: No state, group or folder selected.");
1065 QMessageBox::warning(NULL,
"Internal error",
"Internal error.");
1070 QString name = QInputDialog::getText(
1071 NULL, QString(
"New Folder"), QString(
"Enter name"), QLineEdit::Normal, QString(), &
ok);
1079 std::filesystem::create_directory(newFolderNode->getAbsoluteBoostPath());
1104 msgBox.setText(
"Error: No state selected.");
1113 treeView->repaint();
1119 QList<StateInstancePtr> instances = stateTreeModel->findStateUsages(
getSelectedNode());
1121 QString
message(
"Usage count: ");
1122 message += QString::number(instances.count());
1123 message +=
"\n" + buildStateUsageString(instances);
1134 if (node && node->isState())
1141 if (d.exec() == QDialog::Accepted)
1153 auto groups = stateTreeModel->getGroups();
1154 stateTreeModel->clear();
1156 for (
const auto&
c : rootNode->getChildren())
1172 if (loadedGroup->getDefinitionFilePath() == group->getDefinitionFilePath())
1174 stateTreeModel->generateBaseClasses(loadedGroup);
1180 ARMARX_WARNING_S <<
"Renaming state '" << state->getStateName() <<
"' to '"
1197 ARMARX_INFO_S << node->getBoostPathRelativeToGroup().string()
1198 <<
" group path: " << node->getGroup()->getGroupPath().toStdString();
1200 opener.
openFile(
"qtcreatorProject",
1201 node->getGroup()->getPackagePath().toStdString() +
"/CMakeLists.txt");
1214 QMessageBox::information(treeView,
1215 "Path for Group " + node->getGroup()->getName(),
1216 node->getGroup()->getGroupPath());
1234 if (processes.find(group->getGroupPath()) != processes.end())
1236 processes[group->getGroupPath()]->terminate();
1237 processes[group->getGroupPath()]->waitForFinished(1000);
1238 processes[group->getGroupPath()]->kill();
1239 processes.remove(group->getGroupPath());
1248 if (processes.find(group->getGroupPath()) == processes.end())
1250 processes[group->getGroupPath()] =
new QProcess(
this);
1254 QProcess* p = processes[group->getGroupPath()];
1258 if (!startState.isEmpty())
1260 args <<
"--ArmarX.XMLStateComponent.StatesToEnter=" + startState;
1262 args <<
"--ArmarX.XMLStateComponent.XMLStatechartGroupDefinitionFile=" +
1263 group->getDefinitionFilePath();
1264 args <<
"--ArmarX.XMLStateComponent.XMLStatechartProfile=" +
1265 QString::fromStdString(currentProfile->getName());
1266 args <<
"--ArmarX.XMLStateComponent.ObjectName=" + group->getName() +
"StateComponent";
1267 args <<
"--ArmarX.ApplicationName=" + group->getName() +
"StateComponentApp";
1268 QString path = QString::fromStdString(core.
getBinaryDir()) +
"/XMLRemoteStateOffererRun";
1269 ARMARX_INFO_S << path <<
" " << args.join(
" ").toStdString();
1271 std::string username;
1274 username = getenv(
"USER");
1276 std::string tempLogDir = (std::filesystem::temp_directory_path() / (
"armarx-" + username) /
1277 group->getName().toStdString())
1279 if (!std::filesystem::exists(tempLogDir) && !std::filesystem::create_directories(tempLogDir))
1281 ARMARX_WARNING_S <<
"Could not create log dirs for executing group - aborting";
1284 p->setStandardOutputFile(QString::fromStdString(tempLogDir) +
"/out.log");
1285 p->setStandardErrorFile(QString::fromStdString(tempLogDir) +
"/err.log");
1286 p->setProcessChannelMode(QProcess::MergedChannels);
1287 p->start(path, args);
1288 connect(p, SIGNAL(readyReadStandardOutput()),
this, SLOT(processOutputReady()));
1289 connect(p, SIGNAL(readyReadStandardError()),
this, SLOT(processErrorsReady()));
1307 deps.push_back(group);
1311 if (processes.find(dep->getGroupPath()) != processes.end())
1313 processes[dep->getGroupPath()]->terminate();
1316 auto startTime = IceUtil::Time::now();
1319 if (processes.find(dep->getGroupPath()) != processes.end())
1321 auto timeLeftToWait =
1322 std::max<int>(0, 1000 - (IceUtil::Time::now() - startTime).toMilliSeconds());
1323 processes[dep->getGroupPath()]->waitForFinished(timeLeftToWait);
1324 processes[dep->getGroupPath()]->kill();
1325 processes.remove(dep->getGroupPath());
1341 QString noneState(
"---");
1342 states << noneState;
1345 if (curnode->isPublic() && curnode->isState())
1347 states << curnode->getState()->getStateName();
1351 QString startState = QInputDialog::getItem(
1352 0,
"State",
"Select the state to start or none", states, 0,
false, &
ok);
1357 if (startState == noneState)
1376 auto process = qobject_cast<QProcess*>(sender());
1379 ARMARX_INFO_S << process->pid() <<
" exited with code " << exitCode;
1440 if (!node || !node->isState())
1442 QMessageBox::warning(NULL,
"No State selected",
"Error: No state selected.");
1446 if (!packageTool->addCppOnlyXmlStatechart(
1447 node->getGroup()->getName().toUtf8().data(),
1448 node->getBoostPathRelativeToGroup().replace_extension().string(),
1449 node->getGroup()->getPackagePath().toUtf8().data()))
1451 ARMARX_WARNING_S <<
"Creating source files for state " << node->getBasename()
1453 << packageTool->getLastOutput();
1456 node->checkCppExists();
1464 if (node && node->isGroup())
1470 if (d.exec() == QDialog::Accepted)
1474 if (!g.first->existsCMakeLists())
1476 QMessageBox::warning(0,
1478 g.first->getName() +
" at " + g.first->getGroupPath() +
1479 " contains no CMakeLists.txt - is it an installed "
1480 "package? Installed packages cannot be cloned.");
1485 if (
auto newMapping = groupCloner->cloneGroupsTo(
1489 <<
"Cloning successful, creating/overwriting mapping file in package: "
1493 const QString packageName = QFileInfo(d.
getPackagePath()).fileName();
1498 groupDir.cd(
"source");
1499 groupDir.cd(packageName);
1500 groupDir.cd(
"statecharts");
1501 groupDir.cd(g.second);
1502 QString newDefFile = groupDir.path() + QDir::separator() + g.second +
".scgxml";
1515 if (node && node->isGroup())
1520 if (d.exec() == QDialog::Accepted)
1528 if (
auto newGroupDirPath =
1531 QString newGroupDefinitionPath =
1532 *newGroupDirPath + QDir::separator() + d.
getNewName() +
".scgxml";
1538 stateTreeModel->clear();
1540 for (
const auto&
c : rootNode->getChildren())
1550 if (g->getGroupPath() == group->getGroupPath())
1570 if (node && node->isGroup())
1577 group->getProxies(),
1578 group->contextGenerationEnabled(),
1580 group->getConfigurations(),
1581 group->getDescription(),
1584 if (d.exec() == QDialog::Accepted)
1597 treeView->collapseAll();
1604 treeView->expand(proxyModel->mapFromSource(getIndex(node->getParent())));
1605 treeView->setCurrentIndex(proxyModel->mapFromSource(getIndex(node)));
1611 if (!node->getCppExists())
1613 QMessageBox::warning(NULL,
1615 QString(
"File '") + node->getBoostCppFilePath().c_str() +
1625 StateTreeController::processOutputReady()
1627 QProcess* p = qobject_cast<QProcess*>(sender());
1631 std::cout << QString(p->readAllStandardOutput());
1640 StateTreeController::processErrorsReady()
1642 QProcess* p = qobject_cast<QProcess*>(sender());
1646 std::cerr << QString(p->readAllStandardError());
1655 StateTreeController::stateAddedOrRemoved()
1657 std::cout <<
"StateTreeController::stateAddedOrRemoved()" << std::endl;
1658 treeView->repaint();
1662 StateTreeController::expandFilterResults(
const QString& filterString)
1664 if (filterString.length() == 0)
1675 if (!node || node == rootNode || !node->getParent())
1677 return QModelIndex();
1680 return createIndex(node->row(), 0, node.get());
1684 StateTreeController::buildStateUsageString(QList<StateInstancePtr> instances)
1687 QListIterator<StateInstancePtr> i(instances);
1693 stateTreeModel->getNodeByState(stateInstance->getParent())->getGroup()->getName() +
1694 "/" + stateInstance->getParent()->getStateName() +
": '" +
1695 stateInstance->getInstanceName() +
"'\n";
1705 stateTreeModel->notifyDeleteStateTreeNode(stateNode);
1718 if (node->getChildren().count() > 0)
1720 QMessageBox::warning(
1721 NULL,
"Folder cannot be deleted.",
"Folder cannot be deleted. It is not empty.");
1727 std::filesystem::remove(node->getAbsoluteBoostPath());
1731 QString::fromUtf8((node->getGroup()->getBoostDefinitionFilePath()).c_str()));
1733 catch (std::exception&)
1735 QMessageBox::warning(
1736 NULL,
"Folder cannot be deleted.",
"Folder cannot be deleted. It is not empty. ");
1756 auto statechartsCmakeListPath = QString::fromUtf8(
1757 (node->getAbsoluteBoostPath().remove_filename().parent_path() /
"CMakeLists.txt").c_str());
1759 filecontents = filecontents.remove(
"add_subdirectory(" + node->getBasename() +
")");
1762 std::filesystem::remove_all(node->getAbsoluteBoostPath().remove_filename());
1770 int row = node->row();
1772 this->beginRemoveRows(getIndex(node->getParent()), row, row);
1774 node->getParent()->removeChild(node);
1776 this->endRemoveRows();
1786 d.setMinimumDuration(1000);
1787 stateTreeModel->saveAll(&d);
1791 stateTreeModel->generateAllBaseClasses(&d);
1806 result <<
"application/x-State";
1807 result <<
"application/pointer";
1814 if (indexes.size() == 0)
1816 return new QMimeData();
1821 if (node->isGroup())
1823 QMimeData*
mimeData =
new QMimeData();
1824 QByteArray encodedData;
1826 QDataStream stream(&encodedData, QIODevice::WriteOnly);
1829 foreach (
const QModelIndex&
index, indexes)
1831 if (
index.isValid())
1836 << node->getGroup()->getPackageName().toStdString();
1838 auto prop = appForDrag->getProperties();
1841 node->getGroup()->getBoostDefinitionFilePath().string());
1842 prop->getProperties()->setProperty(
1843 "ArmarX.XMLStateComponent.XMLStatechartGroupDefinitionFile",
1844 relativeGroupFilePath);
1845 prop->getProperties()->setProperty(
"ArmarX.XMLStateComponent.XMLStatechartProfile",
1846 currentProfile->getName());
1847 prop->getProperties()->setProperty(
"ArmarX.XMLStateComponent.ObjectName",
1848 node->getGroup()->getName().toStdString() +
1849 "XMLStateComponent");
1850 prop->getProperties()->setProperty(
1851 "ArmarX.ApplicationName", node->getGroup()->getName().toStdString() +
"App");
1852 appForDrag->setProperties(prop);
1855 stream << reinterpret_cast<quint64>(appForDrag.get())
1856 << node->getGroup()->getName() ;
1861 mimeData->setData(
"application/pointer", encodedData);
1865 if (!node || !node->getState())
1867 return new QMimeData();
1871 StateMimeData*
data =
new StateMimeData(node->getState(), stateTreeModel);
1885 return stateTreeModel->getNodeByState(this->state)->getGroup() ==
1886 stateTreeModel->getNodeByState(state)->getGroup();
1890 StateTreeController::StateMimeData::isPublic()
const
1892 return stateTreeModel->getNodeByState(this->state)->
isPublic();