39 #include "../StatechartViewerPlugin/model/DynamicRemoteStateClass.h"
46 #include <QInputDialog>
47 #include <QMessageBox>
49 #include <QProgressDialog>
51 #include <QFileDialog>
53 #include <QDialogButtonBox>
60 using namespace statechartio;
61 using namespace statechartmodel;
64 : QAbstractItemModel(parent)
66 qRegisterMetaType<StateTreeNodePtr>(
"StateTreeNodePtr");
68 this->appForDrag.reset(
70 "XMLRemoteStateOffererRun",
74 this->variantInfo = variantInfo;
75 this->profiles = statechartProfiles;
76 this->currentProfile = currentProfile;
77 this->packageTool = packageTool;
78 this->headerInfo = headerInfo;
79 this->treeView = treeView;
81 this->rootNode = this->stateTreeModel->getRootNode();
82 this->groupCloner = std::make_shared<GroupCloner>(stateTreeModel, packageTool);
83 this->groupRenamer = std::make_shared<GroupRenamer>(groupCloner);
84 this->communicator =
ic;
88 proxyModel->setSourceModel(
this);
89 proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
90 treeView->setModel(proxyModel);
93 contextMenuGroup =
new QMenu(treeView);
94 contextMenuFolder =
new QMenu(treeView);
95 contextMenuState =
new QMenu(treeView);
96 treeView->setContextMenuPolicy(Qt::CustomContextMenu);
98 actionDeleteNode =
new QAction(QIcon(
":/icons/delete.ico"),
"Delete", treeView);
99 actionMakeStatePublic =
new QAction(
"Public State", treeView);
100 actionMakeStatePublic->setCheckable(
true);
101 actionNewFolder =
new QAction(QIcon(
":/icons/folder-new.svg"),
"Add new Folder", treeView);
102 actionNewStateDefinition =
new QAction(QIcon(
":/icons/images/add-state.png"),
"Add new State Definition", treeView);
103 actionNewDynamicRemoteStateDefinition =
new QAction(
"Add new Dynamic Remote State Definition", treeView);
104 actionFindStateUsages =
new QAction(QIcon(
":/icons/search.svg"),
"Find State Usages", treeView);
105 actionRenameState =
new QAction(QIcon(
":/icons/rename.svg"),
"Rename State", treeView);
106 actionOpenCMakeProject =
new QAction(QIcon(
":/icons/qt-small.png"),
"Open CMake Project", treeView);
107 actionShowFullPath =
new QAction(QIcon(
":/icons/search.svg"),
"Show Full Path", treeView);
108 actionOpenStateCPP =
new QAction(QIcon(
":/icons/cpp.svg"),
"Open C++ Code", treeView);
109 actionExecuteGroup =
new QAction(QIcon(
":/icons/run.svg"),
"Execute Statechart Group", treeView);
112 actionGenerateStateCPP =
new QAction(QIcon(
":/icons/document-properties.svg"),
"Generate State C++ Files", treeView);
113 actionRenameGroup =
new QAction(QIcon(
":/icons/rename.svg"),
"Rename Group", treeView);
114 actionCloneGroup =
new QAction(QIcon(
":/icons/clone.svg"),
"Clone Group", treeView);
115 actionGroupProperties =
new QAction(QIcon(
":/icons/document-properties.svg"),
"Group Properties", treeView);
117 QList<QAction*> groupActions, folderActions, stateActions;
119 groupActions.append(actionNewStateDefinition);
120 groupActions.append(actionNewDynamicRemoteStateDefinition);
121 groupActions.append(actionNewFolder);
122 groupActions.append(actionDeleteNode);
123 groupActions.append(actionOpenCMakeProject);
124 groupActions.append(actionShowFullPath);
125 groupActions.append(actionExecuteGroup);
127 groupActions.append(actionRenameGroup);
128 groupActions.append(actionCloneGroup);
129 groupActions.append(actionGroupProperties);
131 folderActions.append(actionNewStateDefinition);
132 folderActions.append(actionNewDynamicRemoteStateDefinition);
133 folderActions.append(actionNewFolder);
134 folderActions.append(actionDeleteNode);
136 stateActions.append(actionMakeStatePublic);
137 stateActions.append(actionFindStateUsages);
138 stateActions.append(actionRenameState);
139 stateActions.append(actionDeleteNode);
140 stateActions.append(actionOpenStateCPP);
142 stateActions.append(actionGenerateStateCPP);
144 for (QAction*
a : groupActions)
146 a->setIconVisibleInMenu(
true);
149 for (QAction*
a : folderActions)
151 a->setIconVisibleInMenu(
true);
154 for (QAction*
a : stateActions)
156 a->setIconVisibleInMenu(
true);
159 contextMenuGroup->addActions(groupActions);
160 contextMenuFolder->addActions(folderActions);
161 contextMenuState->addActions(stateActions);
164 connect(stateTreeModel.get(), SIGNAL(stateAddedOrRemoved()), SLOT(stateAddedOrRemoved()));
165 connect(treeView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(
onContextMenu(QPoint)));
169 connect(actionDeleteNode, SIGNAL(triggered()), SLOT(
onDeleteNode()));
170 connect(actionMakeStatePublic, SIGNAL(triggered(
bool)), SLOT(
onMakeStatePublic(
bool)));
171 connect(actionNewFolder, SIGNAL(triggered()), SLOT(
onNewFolder()));
173 connect(actionRenameState, SIGNAL(triggered()), SLOT(
onRenameState()));
174 connect(actionOpenCMakeProject, SIGNAL(triggered()),
this, SLOT(
onOpenCMakeProject()));
175 connect(actionShowFullPath, SIGNAL(triggered()),
this, SLOT(
onShowFullPath()));
176 connect(actionOpenStateCPP, SIGNAL(triggered()),
this, SLOT(
onOpenStateCPP()));
177 connect(actionExecuteGroup, SIGNAL(triggered()),
this, SLOT(
onExecuteGroup()));
181 connect(actionRenameGroup, SIGNAL(triggered()),
this, SLOT(
onRenameGroup()));
182 connect(actionCloneGroup, SIGNAL(triggered()),
this, SLOT(
onCloneGroup()));
183 connect(actionGroupProperties, SIGNAL(triggered()),
this, SLOT(
onGroupProperties()));
185 connect(filterLineEdit, SIGNAL(textChanged(QString)), proxyModel, SLOT(setFilterFixedString(QString)));
186 connect(filterLineEdit, SIGNAL(textChanged(QString)),
this, SLOT(expandFilterResults(QString)));
192 ARMARX_INFO <<
"Killing " << processes.size() <<
" statechart processes";
193 for (
auto& process : processes)
198 for (
auto& process : processes)
200 ARMARX_INFO <<
"Waiting for process " << process->pid();
201 process->waitForFinished(2000);
203 for (
auto& process : processes)
205 if (process->pid() > 0)
216 if (!
index.isValid())
225 case Qt::DisplayRole:
228 return node->getDisplay()
229 + (node->getState() ?
"" :
" [no .xml]")
230 + (node->getCppExists() ?
"" :
" [no .cpp]")
231 + (node->isPublic() ?
" (public)" :
"")
236 return node->getDisplay();
239 case Qt::DecorationRole:
244 return getIcon(
":/icons/folder-locked.svg");
246 if (treeView->isExpanded(
index))
248 return getIcon(
":/icons/folder-open.svg");
252 return getIcon(
":/icons/folder.svg");
257 if (node->getState())
259 if (node->getState()->getSubstates().count() > 0)
261 return getIcon(node->isPublic() ?
":/statechart-editor/states-public.svg" :
":/statechart-editor/states.svg");
265 return getIcon(node->isPublic() ?
":/statechart-editor/state-public.svg" :
":/statechart-editor/state.svg");
270 return getIcon(
":/statechart-editor/state-broken.svg");
276 case Qt::ToolTipRole:
278 return QString::fromStdString(node->getAbsoluteBoostPath().string());
288 if (!
index.isValid())
295 flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
299 if (node->getState() || node->isGroup())
301 flags |= Qt::ItemIsDragEnabled;
310 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
312 return headerInfo.value(section);
320 if (!hasIndex(row, column, parentIndex))
322 return QModelIndex();
327 if (!parentIndex.isValid())
329 parentNode = this->rootNode.get();
333 parentNode =
static_cast<StateTreeNode*
>(parentIndex.internalPointer());
340 return createIndex(row, column, childNode);
344 return QModelIndex();
350 if (!
index.isValid())
352 return QModelIndex();
358 if (parentNode == rootNode)
360 return QModelIndex();
363 return createIndex(parentNode->row(), 0, parentNode.get());
376 return rootNode->childCount();
395 return rootNode->columnCount();
401 bool load = !groupDefinitionFile.isEmpty();
404 QFileDialog selectGroupFile(treeView,
"Open Statechart Group");
406 selectGroupFile.setOption(QFileDialog::ReadOnly,
true);
407 selectGroupFile.setOption(QFileDialog::HideNameFilterDetails,
false);
408 selectGroupFile.setFileMode(QFileDialog::ExistingFile);
410 urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation))
411 << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation));
418 selectGroupFile.setSidebarUrls(urls);
420 filters <<
"Statechart Group (*.scgxml)";
421 filters <<
"All Files(*.*)";
422 selectGroupFile.setNameFilters(filters);
423 load = selectGroupFile.exec() == QDialog::Accepted;
424 if (
load && groupDefinitionFile.isEmpty())
426 groupDefinitionFile = selectGroupFile.selectedFiles().first();
444 stateTreeModel->loadGroupStates(group);
446 catch (std::exception& e)
448 QString reason(QString::fromStdString(e.what()));
449 reason.truncate(200);
451 QMessageBox::warning(0,
"Error while loading States", QString(
"An error while loading states - Reason:\n" + reason));
454 catch (std::exception& e)
456 QString reason = QString::fromStdString(e.what());
457 reason.truncate(200);
458 QMessageBox::warning(0,
"Error while loading Statechart Group", QString(
"An error while loading the statechart group file '") + groupDefinitionFile +
"' - Reason:\n" + reason);
470 this->layoutAboutToBeChanged();
478 rootNode->appendChild(group->getRootNode());
479 rootNode->sortChildren();
481 this->layoutChanged();
484 treeView->expand(getIndex(groupNode));
485 treeView->setCurrentIndex(getIndex(groupNode));
490 StatechartGroupPtr StateTreeController::addNewGroup(
const QString& groupName,
const QString& groupPath,
const QString& description,
const QString& packageName,
const QList<QString> proxies,
bool generateContext,
const QMap<QString, QString>& statechartGroupConfigurations)
493 std::filesystem::path defPath = groupPath.toUtf8().data();
494 defPath /= (groupName +
".scgxml").
toUtf8().data();
497 group->setRootNode(groupRootNode);
499 stateTreeModel->addGroup(group);
500 rootNode->appendChild(group->getRootNode());
502 rootNode->sortChildren();
506 QMetaObject::invokeMethod(
this,
"selectNode", Qt::QueuedConnection, Q_ARG(
StateTreeNodePtr, group->getRootNode()));
513 stateTreeModel->loadAllStates();
518 return stateTreeModel->getNodeByState(state);
523 QModelIndex selected = treeView->currentIndex();
525 if (!selected.isValid())
535 return node ? node->getClosestParentFolderOrGroupNode() :
StateTreeNodePtr();
599 QList<StateInstancePtr> instances = stateTreeModel->findStateUsages(node);
601 if (instances.count() > 0)
603 QString
message = QString(
"Cannot delete state, it is still being used by %1 state(s):\n%2")
604 .arg(instances.count()).arg(buildStateUsageString(instances));
605 QMessageBox::warning(NULL,
"Cannot delete State",
message);
609 if (node->getState())
611 QString question = QString(
"You are about to delete the State Definition '%1'.\nDo you also want to permanently remove the underlying file %2?")
612 .arg(node->getDisplay(), node->getBasename());
613 QMessageBox::StandardButton reply = QMessageBox::question(NULL,
"Delete State Definition File?", question,
QMessageBox::Yes |
QMessageBox::No | QMessageBox::Cancel);
615 if (reply == QMessageBox::Cancel)
621 std::filesystem::remove(node->getAbsoluteBoostPath());
622 if (node->getCppExists())
624 std::filesystem::remove(node->getBoostCppFilePath());
625 std::filesystem::remove(node->getBoostHFilePath());
626 std::filesystem::remove(node->getBoostGeneratedHFilePath());
632 QString question = QString(
"Remove State Definition '%1'?").arg(node->getDisplay());
633 QMessageBox::StandardButton reply = QMessageBox::question(NULL,
"Delete State Definition?", question, QMessageBox::Ok | QMessageBox::Cancel);
635 if (reply == QMessageBox::Cancel)
642 GroupXmlWriter::WriteXml(node->getGroup(), QString::fromUtf8((node->getGroup()->getBoostDefinitionFilePath()).c_str()));
647 this->layoutAboutToBeChanged();
651 if (!createDynamicRemoteState)
654 state->addEndSubstate(
"Success",
"Success");
655 state->addEndSubstate(
"Failure",
"Failure");
657 evt->name =
"Failure";
658 evt->description =
"Event for statechart-internal failures or optionally user-code failures";
659 state->setOutgoingEvents(
EventList {evt});
667 state->setStateName(name);
670 stateTreeModel->setNodeState(node, state);
671 parent->appendChild(node);
673 stateTreeModel->notifyNewStateTreeNode(node);
674 this->layoutChanged();
675 treeView->sortByColumn(0, Qt::AscendingOrder);
677 QMetaObject::invokeMethod(
this,
"selectNode", Qt::QueuedConnection, Q_ARG(
StateTreeNodePtr, node));
684 this->layoutAboutToBeChanged();
686 parent->appendChild(node);
689 this->layoutChanged();
691 treeView->expand(getIndex(
parent));
692 treeView->setCurrentIndex(getIndex(node));
699 if (!
index.isValid())
705 if (
index.model() == proxyModel)
719 treeView->setCurrentIndex(proxyModel->mapFromSource(getIndex(node)));
725 QModelIndex
index = treeView->indexAt(point);
735 actionMakeStatePublic->setEnabled(
true);
736 actionRenameState->setEnabled(
true);
737 actionRenameGroup->setEnabled(
true);
738 actionGenerateStateCPP->setEnabled(
true);
739 actionNewFolder->setEnabled(
true);
740 actionNewStateDefinition->setEnabled(
true);
741 actionNewDynamicRemoteStateDefinition->setEnabled(
true);
742 actionOpenCMakeProject->setEnabled(
true);
743 actionOpenStateCPP->setEnabled(
true);
744 actionGroupProperties->setEnabled(
true);
745 actionDeleteNode->setEnabled(
true);
747 auto applyReadOnlyStatusToMenu = [&,
this]()
754 actionMakeStatePublic->setEnabled(writable);
755 actionRenameState->setEnabled(writable);
756 actionRenameGroup->setEnabled(writable);
757 actionGenerateStateCPP->setEnabled(writable);
758 actionNewFolder->setEnabled(writable);
759 actionNewStateDefinition->setEnabled(writable);
760 actionNewDynamicRemoteStateDefinition->setEnabled(writable);
761 actionOpenCMakeProject->setEnabled(writable);
762 actionOpenStateCPP->setEnabled(writable);
763 actionGroupProperties->setEnabled(writable);
764 actionDeleteNode->setEnabled(writable);
771 actionMakeStatePublic->setEnabled(node->getState() != NULL);
772 actionMakeStatePublic->setChecked(node->isPublic());
773 actionFindStateUsages->setEnabled(node->getState() != NULL);
774 actionRenameState->setEnabled(node->isState());
775 actionGenerateStateCPP->setEnabled(!node->getCppExists() && node->getState()->getType() == eNormalState);
776 actionOpenStateCPP->setEnabled(node->getCppExists());
777 applyReadOnlyStatusToMenu();
778 contextMenuState->exec(treeView->mapToGlobal(point));
780 else if (node->isGroup())
783 QMap<QString, QProcess*>::const_iterator it;
786 && (it = processes.find(node->getGroup()->getGroupPath())) != processes.end()
787 && it.value()->state() != QProcess::NotRunning)
789 actionExecuteGroup->setText(
"Stop and Execute Statechart Group");
793 actionExecuteGroup->setText(
"Execute Statechart Group");
795 applyReadOnlyStatusToMenu();
796 contextMenuGroup->exec(treeView->mapToGlobal(point));
798 else if (node->isFolder() && node != rootNode)
800 applyReadOnlyStatusToMenu();
801 contextMenuFolder->exec(treeView->mapToGlobal(point));
815 label =
new QLabel(
"Enter the state name",
this);
816 editField =
new QLineEdit(
this);
817 QRegExp rx(
"^([a-zA-Z_]{1})([a-zA-Z_0-9]+)$");
818 QValidator* validator =
new QRegExpValidator(rx,
this);
819 editField->setValidator(validator);
820 setWindowTitle(
"New State Definition");
822 checkbox =
new QCheckBox(
"Create C++ Files",
this);
823 QBoxLayout* layout =
new QBoxLayout(QBoxLayout::TopToBottom,
this);
824 buttonBox =
new QDialogButtonBox(
this);
825 buttonBox->setObjectName(QString::fromUtf8(
"buttonBox"));
826 buttonBox->setOrientation(Qt::Horizontal);
827 buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
828 layout->addWidget(label);
829 layout->addWidget(editField);
830 layout->addWidget(checkbox);
831 layout->addWidget(buttonBox);
832 QObject::connect(buttonBox, SIGNAL(accepted()),
this, SLOT(accept()));
833 QObject::connect(buttonBox, SIGNAL(rejected()),
this, SLOT(reject()));
838 bool StateTreeController::retrieveNewStateName(QString& newStateName,
StateTreeNodePtr& node,
bool& createCPPFiles,
bool askForCPPFiles)
844 QMessageBox::warning(NULL,
"Nothing selected",
"Error: No state, group or folder selected.");
848 node = node->getClosestParentFolderOrGroupNode();
851 dialog.
checkbox->setEnabled(askForCPPFiles);
853 if (dialog.exec() == QDialog::Rejected)
859 createCPPFiles = dialog.
checkbox->isChecked();
863 QMessageBox::warning(NULL,
"Invalid name", QString(
"Error: Provided name '%1' does not meet requirements: Has to start with a letter, followed by letters and digits. Sorry.").arg(newStateName));
867 if (node->getGroup()->findNodeByStateName(newStateName))
869 QMessageBox::warning(NULL,
"Duplicate State Name", QString(
"Error: State with name '%1' exists already. Sorry.").arg(newStateName));
873 if (node->getGroup()->getName() == newStateName)
875 QMessageBox::warning(NULL,
"Name Conflict", QString(
"Error: State cannot have same name as Group. Sorry."));
882 QIcon StateTreeController::getIcon(
const QString& path)
const
884 if (!icons.contains(path))
886 icons[path] = QIcon(path);
895 QString newStateName;
897 if (!retrieveNewStateName(newStateName, node, createCPPFiles,
true))
909 if (!packageTool->addFullXmlStatechart(newState->getGroup()->getName().toUtf8().data(),
910 newState->getBoostPathRelativeToGroup().replace_extension().string(),
911 newState->getGroup()->getPackagePath().toUtf8().data()))
913 ARMARX_WARNING_S <<
"Creating source files for state " << newStateName <<
" failed";
918 if (!packageTool->addXmlOnlyXmlStatechart(newState->getGroup()->getName().toUtf8().data(),
919 newState->getBoostPathRelativeToGroup().replace_extension().string(),
920 newState->getGroup()->getPackagePath().toUtf8().data()))
922 ARMARX_WARNING_S <<
"Creating source files for state " << newStateName <<
" failed";
926 newState->checkCppExists();
935 QString newStateName;
937 if (!retrieveNewStateName(newStateName, node, createCPPFiles,
false))
953 QMessageBox::warning(NULL,
"Nothing selected",
"Error: No state, group or folder selected.");
959 QMessageBox::warning(NULL,
"Internal error",
"Internal error.");
964 QString name = QInputDialog::getText(NULL, QString(
"New Folder"), QString(
"Enter name"), QLineEdit::Normal, QString(), &
ok);
972 std::filesystem::create_directory(newFolderNode->getAbsoluteBoostPath());
997 msgBox.setText(
"Error: No state selected.");
1005 treeView->repaint();
1012 QList<StateInstancePtr> instances = stateTreeModel->findStateUsages(
getSelectedNode());
1014 QString
message(
"Usage count: ");
1015 message += QString::number(instances.count());
1016 message +=
"\n" + buildStateUsageString(instances);
1026 if (node && node->isState())
1033 if (d.exec() == QDialog::Accepted)
1045 auto groups = stateTreeModel->getGroups();
1046 stateTreeModel->clear();
1048 for (
const auto&
c : rootNode->getChildren())
1063 if (loadedGroup->getDefinitionFilePath() == group->getDefinitionFilePath())
1065 stateTreeModel->generateBaseClasses(loadedGroup);
1086 ARMARX_INFO_S << node->getBoostPathRelativeToGroup().string() <<
" group path: " << node->getGroup()->getGroupPath().toStdString();
1088 opener.
openFile(
"qtcreatorProject", node->getGroup()->getPackagePath().toStdString() +
"/CMakeLists.txt");
1100 QMessageBox::information(treeView,
"Path for Group " + node->getGroup()->getName(), node->getGroup()->getGroupPath());
1117 if (processes.find(group->getGroupPath()) != processes.end())
1119 processes[group->getGroupPath()]->terminate();
1120 processes[group->getGroupPath()]->waitForFinished(1000);
1121 processes[group->getGroupPath()]->kill();
1122 processes.remove(group->getGroupPath());
1130 if (processes.find(group->getGroupPath()) == processes.end())
1132 processes[group->getGroupPath()] =
new QProcess(
this);
1136 QProcess* p = processes[group->getGroupPath()];
1140 if (!startState.isEmpty())
1142 args <<
"--ArmarX.XMLStateComponent.StatesToEnter=" + startState;
1144 args <<
"--ArmarX.XMLStateComponent.XMLStatechartGroupDefinitionFile=" + group->getDefinitionFilePath();
1145 args <<
"--ArmarX.XMLStateComponent.XMLStatechartProfile=" + QString::fromStdString(currentProfile->getName());
1146 args <<
"--ArmarX.XMLStateComponent.ObjectName=" + group->getName() +
"StateComponent";
1147 args <<
"--ArmarX.ApplicationName=" + group->getName() +
"StateComponentApp";
1148 QString path = QString::fromStdString(core.
getBinaryDir()) +
"/XMLRemoteStateOffererRun";
1149 ARMARX_INFO_S << path <<
" " << args.join(
" ").toStdString();
1151 std::string username;
1154 username = getenv(
"USER");
1156 std::string tempLogDir = (std::filesystem::temp_directory_path() / (
"armarx-" + username) / group->getName().toStdString()).
string();
1157 if (!std::filesystem::exists(tempLogDir) && !std::filesystem::create_directories(tempLogDir))
1159 ARMARX_WARNING_S <<
"Could not create log dirs for executing group - aborting";
1162 p->setStandardOutputFile(QString::fromStdString(tempLogDir) +
"/out.log");
1163 p->setStandardErrorFile(QString::fromStdString(tempLogDir) +
"/err.log");
1164 p->setProcessChannelMode(QProcess::MergedChannels);
1165 p->start(path, args);
1166 connect(p, SIGNAL(readyReadStandardOutput()),
this, SLOT(processOutputReady()));
1167 connect(p, SIGNAL(readyReadStandardError()),
this, SLOT(processErrorsReady()));
1183 deps.push_back(group);
1187 if (processes.find(dep->getGroupPath()) != processes.end())
1189 processes[dep->getGroupPath()]->terminate();
1192 auto startTime = IceUtil::Time::now();
1195 if (processes.find(dep->getGroupPath()) != processes.end())
1197 auto timeLeftToWait = std::max<int>(0, 1000 - (IceUtil::Time::now() - startTime).toMilliSeconds());
1198 processes[dep->getGroupPath()]->waitForFinished(timeLeftToWait);
1199 processes[dep->getGroupPath()]->kill();
1200 processes.remove(dep->getGroupPath());
1215 QString noneState(
"---");
1216 states << noneState ;
1219 if (curnode->isPublic() && curnode->isState())
1221 states << curnode->getState()->getStateName();
1225 QString startState = QInputDialog::getItem(0,
"State",
"Select the state to start or none", states, 0,
false, &
ok);
1230 if (startState == noneState)
1249 auto process = qobject_cast<QProcess*>(sender());
1252 ARMARX_INFO_S << process->pid() <<
" exited with code " << exitCode;
1311 if (!node || !node->isState())
1313 QMessageBox::warning(NULL,
"No State selected",
"Error: No state selected.");
1317 if (!packageTool->addCppOnlyXmlStatechart(node->getGroup()->getName().toUtf8().data(),
1318 node->getBoostPathRelativeToGroup().replace_extension().string(),
1319 node->getGroup()->getPackagePath().toUtf8().data()))
1321 ARMARX_WARNING_S <<
"Creating source files for state " << node->getBasename() <<
" failed:\n" << packageTool->getLastOutput();
1324 node->checkCppExists();
1331 if (node && node->isGroup())
1337 if (d.exec() == QDialog::Accepted)
1341 if (!g.first->existsCMakeLists())
1343 QMessageBox::warning(0,
"Cloning failed",
1344 g.first->getName() +
" at " + g.first->getGroupPath() +
" contains no CMakeLists.txt - is it an installed package? Installed packages cannot be cloned.");
1354 const QString packageName = QFileInfo(d.
getPackagePath()).fileName();
1359 groupDir.cd(
"source");
1360 groupDir.cd(packageName);
1361 groupDir.cd(
"statecharts");
1362 groupDir.cd(g.second);
1363 QString newDefFile = groupDir.path() + QDir::separator() + g.second +
".scgxml";
1375 if (node && node->isGroup())
1380 if (d.exec() == QDialog::Accepted)
1390 QString newGroupDefinitionPath = *newGroupDirPath + QDir::separator() + d.
getNewName() +
".scgxml";
1396 stateTreeModel->clear();
1398 for (
const auto&
c : rootNode->getChildren())
1408 if (g->getGroupPath() == group->getGroupPath())
1427 if (node && node->isGroup())
1431 group->getProxies(), group->contextGenerationEnabled(), profiles, group->getConfigurations(), group->getDescription(), group);
1433 if (d.exec() == QDialog::Accepted)
1445 treeView->collapseAll();
1451 treeView->expand(proxyModel->mapFromSource(getIndex(node->getParent())));
1452 treeView->setCurrentIndex(proxyModel->mapFromSource(getIndex(node)));
1457 if (!node->getCppExists())
1459 QMessageBox::warning(NULL,
"File missing", QString(
"File '") + node->getBoostCppFilePath().c_str() +
"' not found.");
1467 void StateTreeController::processOutputReady()
1469 QProcess* p = qobject_cast<QProcess*>(sender());
1473 std::cout << QString(p->readAllStandardOutput());
1481 void StateTreeController::processErrorsReady()
1483 QProcess* p = qobject_cast<QProcess*>(sender());
1487 std::cerr << QString(p->readAllStandardError());
1496 void StateTreeController::stateAddedOrRemoved()
1498 std::cout <<
"StateTreeController::stateAddedOrRemoved()" << std::endl;
1499 treeView->repaint();
1502 void StateTreeController::expandFilterResults(
const QString& filterString)
1504 if (filterString.length() == 0)
1515 if (!node || node == rootNode || !node->getParent())
1517 return QModelIndex();
1520 return createIndex(node->row(), 0, node.get());
1523 QString StateTreeController::buildStateUsageString(QList<StateInstancePtr> instances)
1526 QListIterator<StateInstancePtr> i(instances);
1531 message += stateTreeModel->getNodeByState(stateInstance->getParent())->getGroup()->getName() +
"/" + stateInstance->getParent()->getStateName() +
": '" + stateInstance->getInstanceName() +
"'\n";
1540 stateTreeModel->notifyDeleteStateTreeNode(stateNode);
1552 if (node->getChildren().count() > 0)
1554 QMessageBox::warning(NULL,
"Folder cannot be deleted.",
"Folder cannot be deleted. It is not empty.");
1560 std::filesystem::remove(node->getAbsoluteBoostPath());
1562 GroupXmlWriter::WriteXml(node->getGroup(), QString::fromUtf8((node->getGroup()->getBoostDefinitionFilePath()).c_str()));
1564 catch (std::exception&)
1566 QMessageBox::warning(NULL,
"Folder cannot be deleted.",
"Folder cannot be deleted. It is not empty. ");
1586 auto statechartsCmakeListPath = QString::fromUtf8((node->getAbsoluteBoostPath().remove_filename().parent_path() /
"CMakeLists.txt").c_str());
1588 filecontents = filecontents.remove(
"add_subdirectory(" + node->getBasename() +
")");
1591 std::filesystem::remove_all(node->getAbsoluteBoostPath().remove_filename());
1598 int row = node->row();
1600 this->beginRemoveRows(getIndex(node->getParent()), row, row);
1602 node->getParent()->removeChild(node);
1604 this->endRemoveRows();
1613 d.setMinimumDuration(1000);
1614 stateTreeModel->saveAll(&d);
1618 stateTreeModel->generateAllBaseClasses(&d);
1632 result <<
"application/x-State";
1633 result <<
"application/pointer";
1639 if (indexes.size() == 0)
1641 return new QMimeData();
1646 if (node->isGroup())
1648 QMimeData*
mimeData =
new QMimeData();
1649 QByteArray encodedData;
1651 QDataStream stream(&encodedData, QIODevice::WriteOnly);
1654 foreach (
const QModelIndex&
index, indexes)
1656 if (
index.isValid())
1662 auto prop = appForDrag->getProperties();
1664 prop->getProperties()->setProperty(
"ArmarX.XMLStateComponent.XMLStatechartGroupDefinitionFile",
1665 relativeGroupFilePath);
1666 prop->getProperties()->setProperty(
"ArmarX.XMLStateComponent.XMLStatechartProfile",
1667 currentProfile->getName());
1668 prop->getProperties()->setProperty(
"ArmarX.XMLStateComponent.ObjectName",
1669 node->getGroup()->getName().toStdString() +
"XMLStateComponent");
1670 prop->getProperties()->setProperty(
"ArmarX.ApplicationName",
1671 node->getGroup()->getName().toStdString() +
"App");
1672 appForDrag->setProperties(prop);
1675 stream << reinterpret_cast<quint64>(appForDrag.get()) << node->getGroup()->getName() ;
1680 mimeData->setData(
"application/pointer", encodedData);
1684 if (!node || !node->getState())
1686 return new QMimeData();
1690 StateMimeData*
data =
new StateMimeData(node->getState(), stateTreeModel);
1698 stateTreeModel(stateTreeModel)
1704 return stateTreeModel->getNodeByState(this->state)->getGroup() == stateTreeModel->getNodeByState(state)->getGroup();
1707 bool StateTreeController::StateMimeData::isPublic()
const
1709 return stateTreeModel->getNodeByState(this->state)->
isPublic();