StateRenamer.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "StateRenamer.h"
25
26#include <filesystem>
27
28#include <QDir>
29#include <QDirIterator>
30#include <QFileInfo>
31
32#include <IceUtil/UUID.h>
33
38
39using namespace armarx;
40using namespace armarx::statechartmodel;
41
42bool
43StateRenamer::RenameState(const QVector<InstanceRenameInfo>& instanceRenameInfos,
44 const StateTreeNodePtr& state,
45 const QString& newStateName,
46 const StatechartGroupPtr& group)
47{
48 RenameStateInstances(instanceRenameInfos);
49
50 if (!RenameStateClass(state, newStateName))
51 {
52 return false;
53 }
54
55 if (!AdjustStatechartGroupFile(group, state, newStateName))
56 {
57 return false;
58 }
59
60 auto cmakeListPath = QString::fromUtf8(
61 (group->getBoostDefinitionFilePath().remove_filename() / "CMakeLists.txt").c_str());
62 auto fileContents = GuiStatechartGroupXmlReader::ReadFileContents(cmakeListPath);
63 fileContents =
64 fileContents.replace(state->getState()->getStateName() + ".xml", newStateName + ".xml");
65 fileContents =
66 fileContents.replace(state->getState()->getStateName() + ".cpp", newStateName + ".cpp");
67 fileContents =
68 fileContents.replace(state->getState()->getStateName() + ".h", newStateName + ".h");
69 fileContents = fileContents.replace(state->getState()->getStateName() + ".generated.h",
70 newStateName + ".generated.h");
71 GroupXmlWriter::WriteFileContents(cmakeListPath, fileContents);
72
73 return true;
74}
75
76void
77StateRenamer::RenameStateInstances(const QVector<InstanceRenameInfo>& instanceRename)
78{
79 for (const auto& entry : instanceRename)
80 {
81 if (entry.fromName == entry.toName)
82 {
83 continue;
84 }
85
86 auto xmlProcessor = [&](const std::string& nodeName,
87 const std::string& attribName,
88 const std::string& attribValue) -> std::string
89 {
90 QString value = QString::fromUtf8(attribValue.c_str());
91 const bool nameRef = attribName == "name" && value == entry.fromName;
92 const bool transitionRef = nodeName == "Transition" &&
93 (attribName == "from" || attribName == "to") &&
94 value == entry.fromName;
95 const bool startRef =
96 nodeName == "StartState" && attribName == "substateName" && value == entry.fromName;
97
98 if (nameRef || transitionRef || startRef)
99 {
100 return entry.toName.toUtf8().data();
101 }
102
103 return attribValue;
104 };
105
106 auto statePath =
107 entry.parentState->getBoostXmlFilePath(StateTreeNode::Path::Absolute).string();
108
109 ARMARX_VERBOSE_S << "processing xml file: " << statePath;
110 auto readerPtr = RapidXmlReader::FromFile(statePath);
111 RapidXmlReaderNode rootNode = readerPtr->getRoot();
112 RapidXmlWriter writer;
113 auto writerNode = writer.createRootNode(rootNode.name());
114
115 GroupCloner::ProcessXMLFile(rootNode, writerNode, xmlProcessor);
116
117 writer.saveToFile(statePath, true);
118 }
119}
120
121bool
122StateRenamer::RenameStateClass(const StateTreeNodePtr& state, const QString& newStateName)
123{
124 const std::string newStateNameStd = newStateName.toUtf8().data();
125 auto oldStateName = state->getState()->getStateName();
126 auto oldStatePath = state->getBoostXmlFilePath(StateTreeNode::Path::Absolute);
127 auto newStatePath =
128 state->getBoostXmlFilePath(StateTreeNode::Path::Absolute).remove_filename() /
129 (newStateNameStd + ".xml");
130 auto readerPtr = RapidXmlReader::FromFile(oldStatePath.string());
131 RapidXmlReaderNode rootNode = readerPtr->getRoot();
132 RapidXmlWriter writer;
133 auto writerNode = writer.createRootNode(rootNode.name());
134
135 auto xmlProcessor = [&](const std::string& nodeName,
136 const std::string& attribName,
137 const std::string& attribValue) -> std::string
138 {
139 QString value = QString::fromUtf8(attribValue.c_str());
140
141 if (nodeName == "State" && attribName == "name" &&
142 value == state->getState()->getStateName())
143 {
144 ARMARX_CHECK_EXPRESSION(state->getState()->getStateName() == value)
145 << "expected state file of '" << state->getState()->getStateName() << "', but got '"
146 << value << "'";
147 return newStateName.toUtf8().data();
148 }
149
150 return attribValue;
151 };
152
153 GroupCloner::ProcessXMLFile(rootNode, writerNode, xmlProcessor);
154 writer.saveToFile(newStatePath.string(), true);
155
156 QVector<QPair<QRegExp, QString>> codeFileReplaceList;
157 codeFileReplaceList.push_back({QRegExp{"\\b(" + oldStateName + ")\\b"}, newStateName});
158 codeFileReplaceList.push_back({QRegExp{"_" + oldStateName + "_"}, "_" + newStateName + "_"});
159 codeFileReplaceList.push_back(
160 {QRegExp{oldStateName + "GeneratedBase"}, newStateName + "GeneratedBase"});
161
162 bool success = true;
163
164 if (state->checkCppExists())
165 {
166 auto oldCppPath = state->getBoostCppFilePath();
167 auto newCppPath = state->getBoostCppFilePath().parent_path() / (newStateNameStd + ".cpp");
168 auto oldHPath = state->getBoostHFilePath();
169 auto newHPath = state->getBoostHFilePath().parent_path() / (newStateNameStd + ".h");
170 auto genPath = state->getBoostGeneratedHFilePath();
171
172 GroupCloner::RegexReplaceFile(QString::fromUtf8(oldCppPath.c_str()),
173 QString::fromUtf8(newCppPath.c_str()),
174 codeFileReplaceList);
175 GroupCloner::RegexReplaceFile(QString::fromUtf8(oldHPath.c_str()),
176 QString::fromUtf8(newHPath.c_str()),
177 codeFileReplaceList);
178 success = !std::filesystem::exists(oldCppPath) || std::filesystem::remove(oldCppPath);
179 success &= !std::filesystem::exists(oldHPath) || std::filesystem::remove(oldHPath);
180 success &= !std::filesystem::exists(genPath) || std::filesystem::remove(genPath);
181 }
182
183
184 return success;
185}
186
187bool
188StateRenamer::AdjustStatechartGroupFile(const StatechartGroupPtr& group,
189 const StateTreeNodePtr& state,
190 const QString& newName)
191{
192 std::string path = group->getDefinitionFilePath().toUtf8().data();
193 auto readerPtr = RapidXmlReader::FromFile(path);
194 RapidXmlReaderNode rootNode = readerPtr->getRoot();
195 RapidXmlWriter writer;
196 auto writerNode = writer.createRootNode(rootNode.name());
197
198 auto scgxmlProcessor = [&](const std::string& nodeName,
199 const std::string& attribName,
200 const std::string& attribValue) -> std::string
201 {
202 QString value = QString::fromUtf8(attribValue.c_str());
203
204 if (nodeName == "State" && attribName == "filename" && value == state->getBasename())
205 {
206 const QString newStateFile = newName + ".xml";
207 return newStateFile.toUtf8().data();
208 }
209
210 return attribValue;
211 };
212
213 GroupCloner::ProcessXMLFile(rootNode, writerNode, scgxmlProcessor);
214 writer.saveToFile(path, true);
215 return true;
216}
217
218bool
219StateRenamer::AttemptMoveTo(const QString& source, const QString& target)
220{
221 if (!QFile(source).rename(target))
222 {
223 ARMARX_ERROR_S << "Could not move '" << source << "' to '" << target << "'";
224 return false;
225 }
226
227 return true;
228}
static void ProcessXMLFile(RapidXmlReaderNode source, RapidXmlWriterNode target, const Function &processorFunction)
Definition GroupCloner.h:66
static void RegexReplaceFile(const QString &srcFilePath, const QString &tgtFilePath, const QVector< QPair< QRegExp, QString > > &replaceList)
static void WriteFileContents(QString path, QString contents)
static QString ReadFileContents(QString path)
std::string name() const
static RapidXmlReaderPtr FromFile(const std::string &path)
void saveToFile(const std::string &path, bool indent)
RapidXmlWriterNode createRootNode(const std::string &name)
static bool RenameState(const QVector< InstanceRenameInfo > &instanceRenameInfos, const StateTreeNodePtr &state, const QString &newStateName, const StatechartGroupPtr &group)
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_VERBOSE_S
Definition Logging.h:207
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< StatechartGroup > StatechartGroupPtr
std::shared_ptr< StateTreeNode > StateTreeNodePtr
Vertex source(const detail::edge_base< Directed, Vertex > &e, const PCG &)
Vertex target(const detail::edge_base< Directed, Vertex > &e, const PCG &)
std::shared_ptr< Value > value()
Definition cxxopts.hpp:855