RenameStateDialog.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package ArmarX::
17* @author Valerij Wittenbeck (valerij.wittenbeck at student dot kit dot edu
18* @date 2015
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#include "RenameStateDialog.h"
24
25#include <numeric>
26
27#include <QFileDialog>
28#include <QTimer>
29#include <QtGui>
30
33
35#include <ArmarXGui/gui-plugins/StatechartEditorPlugin/view/dialogs/ui_RenameStateDialog.h>
36
37namespace armarx
38{
39
41 const StatechartGroupPtr& sourceGroup,
42 const statechartmodel::StatePtr& sourceState,
43 QWidget* parent) :
44 QDialog(parent),
45 ui(new Ui::RenameStateDialog),
46 sourceGroup(sourceGroup),
47 sourceState(sourceState),
48 validStateNameRegExp("[a-zA-Z][a-zA-Z0-9]*"),
49 validInstanceNameRegExp("[a-zA-Z][a-zA-Z0-9_]*"),
50 validNewName(false),
51 validInstanceNames(true),
52 colorGreen(QColor::fromRgb(120, 255, 120)),
53 colorRed(QColor::fromRgb(255, 120, 120)),
54 colorYellow(QColor::fromRgb(255, 200, 0)),
55 saveAll(false),
56 alreadyChecking(false)
57 {
58 ui->setupUi(this);
59 setOkButtonsEnabled(false);
60 ui->editOldName->setText(sourceState->getStateName());
61 ui->editOldName->setReadOnly(true);
62 // ui->editOldName->setEnabled(false);
63
64 ui->editNewName->setValidator(new QRegExpValidator(validStateNameRegExp, this));
65
66 connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
67 connect(
68 ui->btnSaveAndProceed, SIGNAL(clicked()), this, SLOT(saveAllProceedButtonClicked()));
69 connect(ui->btnDontSaveAndProceed, SIGNAL(clicked()), this, SLOT(accept()));
70 connect(ui->editNewName, SIGNAL(textChanged(QString)), this, SLOT(verifyNewName(QString)));
71 connect(ui->statesWidget,
72 SIGNAL(itemChanged(QTableWidgetItem*)),
73 this,
74 SLOT(verifyInstanceName(QTableWidgetItem*)));
75
76 localStates = sourceGroup->getAllStates(true);
77
78 for (const StatechartGroupPtr& group : treeModel->getGroups())
79 {
80 if (group->getWriteAccess() == StatechartGroup::eReadOnly)
81 {
82 continue;
83 }
84 for (const StateTreeNodePtr& node : group->getAllNodes())
85 {
86 if (!node->isState() || !node->getState())
87 {
88 continue;
89 }
90
91 auto state = node->getState();
92
93 for (const statechartmodel::StateInstancePtr& instance : state->getSubstates())
94 {
95 if (!instance->getStateClass())
96 {
97 continue;
98 }
99
100 if (instance->getStateClass()->getUUID() == sourceState->getUUID())
101 {
102 instanceRenameInfos.push_back({group,
103 node,
104 instance->getInstanceName(),
105 instance->getInstanceName()});
106 }
107 }
108 }
109 }
110
111 std::sort(instanceRenameInfos.begin(),
112 instanceRenameInfos.end(),
113 [](const StateRenamer::InstanceRenameInfo& info1,
115 {
116 if (info1.group->getName() == info2.group->getName())
117 {
118 if (info1.parentState->getState()->getStateName() ==
119 info2.parentState->getState()->getStateName())
120 {
121 return info1.fromName.compare(info2.toName);
122 }
123
124 return info1.parentState->getState()->getStateName().compare(
125 info2.parentState->getState()->getStateName());
126 }
127
128 return info1.group->getName().compare(info2.group->getName());
129 });
130
131 ui->statesWidget->clear();
132 ui->statesWidget->setRowCount(instanceRenameInfos.size());
133 ui->statesWidget->setColumnCount(3);
134 ui->statesWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
135 ui->statesWidget->setHorizontalHeaderLabels(
136 {"Statechart Group", "Parent State", "Instance Name"});
137
138 int i = 0;
139
140 for (const auto& info : instanceRenameInfos)
141 {
142 QTableWidgetItem* groupItem = new QTableWidgetItem(info.group->getName());
143 groupItem->setFlags(groupItem->flags() ^ Qt::ItemIsEditable);
144 ui->statesWidget->setItem(i, 0, groupItem);
145
146 QTableWidgetItem* stateItem =
147 new QTableWidgetItem(info.parentState->getState()->getStateName());
148 stateItem->setFlags(stateItem->flags() ^ Qt::ItemIsEditable);
149 ui->statesWidget->setItem(i, 1, stateItem);
150
151 QTableWidgetItem* newInstanceItem = new QTableWidgetItem(info.toName);
152 newInstanceItem->setBackgroundColor(colorGreen);
153 ui->statesWidget->setItem(i, 2, newInstanceItem);
154
155 ++i;
156 }
157 }
158
160 {
161 delete ui;
162 }
163
164 void
165 RenameStateDialog::setOkButtonsEnabled(bool enabled)
166 {
167 ui->btnDontSaveAndProceed->setEnabled(enabled);
168 ui->btnSaveAndProceed->setEnabled(enabled);
169 }
170
171 StatechartGroupPtr
173 {
174 return sourceGroup;
175 }
176
179 {
180 return sourceState;
181 }
182
183 QVector<StateRenamer::InstanceRenameInfo>
185 {
186 return instanceRenameInfos;
187 }
188
189 bool
191 {
192 return saveAll;
193 }
194
195 QString
197 {
198 return ui->editNewName->text();
199 }
200
201 void
203 {
204 saveAll = true;
205 accept();
206 }
207
208 void
210 {
211 const int r = item->row();
212 const int c = item->column();
213
214 //setting the background color triggers the "itemchanged" signal, which is what called this method in the first place
215 //this elegant solution ensures that no recursive calling is taking place
216 if (c != 2 || ui->statesWidget->columnCount() < 3 || ui->statesWidget->rowCount() == 0 ||
217 alreadyChecking)
218 {
219 return;
220 }
221
222 alreadyChecking = true;
223
224 StateRenamer::InstanceRenameInfo& info = instanceRenameInfos[r];
225
226 bool hasNameCollisions = false;
227
228 for (int i = 0; i < ui->statesWidget->rowCount(); ++i)
229 {
230 const auto& itemCheck = ui->statesWidget->item(i, 2);
231
232 if (!itemCheck)
233 {
234 continue;
235 }
236
237 const StateRenamer::InstanceRenameInfo& infoCheck = instanceRenameInfos[i];
238
239 bool collision = false;
240
241 for (int j = 0; j < ui->statesWidget->rowCount() && !collision; ++j)
242 {
243 const auto& itemOther = ui->statesWidget->item(j, 2);
244
245 if (i == j || !itemOther)
246 {
247 continue;
248 }
249
250 const StateRenamer::InstanceRenameInfo& infoR = instanceRenameInfos[j];
251
252 if (infoCheck.parentState->getState()->getUUID() ==
253 infoR.parentState->getState()->getUUID())
254 {
255 ARMARX_INFO_S << " checking: " << itemCheck->text() << " " << itemOther->text();
256 collision = itemCheck->text() == itemOther->text();
257 }
258 }
259
260 hasNameCollisions |= collision;
261 itemCheck->setBackgroundColor(collision ? colorRed : colorGreen);
262 }
263
264 bool validName = validInstanceNameRegExp.exactMatch(item->text());
265
266 if (validName)
267 {
268 info.toName = item->text();
269 }
270
271 item->setBackgroundColor(!validName ? colorRed : item->backgroundColor());
272 validInstanceNames = validName && !hasNameCollisions;
273 setOkButtonsEnabled(validInstanceNames && validNewName);
274 alreadyChecking = false;
275 }
276
277 void
279 {
280 bool inUse = false;
281
282 for (const auto& s : localStates)
283 {
284 if (newName == s->getStateName())
285 {
286 inUse = true;
287 break;
288 }
289 }
290
291 QColor colorToUse;
292
293 if (inUse)
294 {
295 ui->labelNewNameError->setText("Name already in use");
296 colorToUse = colorRed;
297 }
298 else
299 {
300 ui->labelNewNameError->setText("Valid name");
301 colorToUse = colorGreen;
302 }
303
304 validNewName = (!inUse && newName.size() != 0);
305 setOkButtonsEnabled(validNewName && validInstanceNames);
306
307 QPalette p(ui->labelNewNameError->palette());
308 p.setColor(ui->labelNewNameError->backgroundRole(), colorToUse);
309 ui->labelNewNameError->setPalette(p);
310 }
311
312} // namespace armarx
constexpr T c
void verifyNewName(QString newName)
void verifyInstanceName(QTableWidgetItem *item)
statechartmodel::StatePtr getState() const
QVector< StateRenamer::InstanceRenameInfo > getInstanceRenameInfos() const
StatechartGroupPtr getGroup() const
RenameStateDialog(const StateTreeModelPtr &treeModel, const StatechartGroupPtr &sourceGroup, const statechartmodel::StatePtr &sourceState, QWidget *parent=0)
#define ARMARX_INFO_S
Definition Logging.h:202
ArmarX Headers.
std::shared_ptr< State > StatePtr
Definition State.h:48
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< StateTreeModel > StateTreeModelPtr
std::shared_ptr< StateTreeNode > StateTreeNodePtr