EditStatechartGroupDialog.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 Mirko Waechter ( mirko.waechter at kit dot edu)
18* @date 2014
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
24
25#include <filesystem>
26
27#include <QFileDialog>
28#include <QTimer>
29#include <QToolTip>
30#include <QtGui>
31
35
37#include <ArmarXGui/gui-plugins/StatechartEditorPlugin/view/dialogs/ui_EditStatechartGroupDialog.h>
39
40namespace armarx
41{
42
44 EditMode editMode,
45 QString groupName,
47 VariantInfoPtr variantInfo,
48 QList<QString> selectedProxies,
49 bool generateContext,
50 const StatechartProfilesPtr& statechartProfiles,
51 const QMap<QString, QString>& statechartGroupConfigurations,
52 const QString& description,
54 QWidget* parent) :
55 QDialog(parent),
57 packageTool(packageTool),
58 editMode(editMode),
59 statechartProfiles(statechartProfiles),
60 configurations(statechartGroupConfigurations),
61 variantInfo(variantInfo),
62 group(group)
63 {
64 ui->setupUi(this);
65 ui->btnShowPackageError->setVisible(false);
66
67 ui->checkBoxGenerateContext->setChecked(generateContext);
68 updateProxyListEnabled(ui->checkBoxGenerateContext->checkState());
69 connect(ui->checkBoxGenerateContext,
70 SIGNAL(stateChanged(int)),
71 this,
72 SLOT(updateProxyListEnabled(int)));
73
74 if (editMode == NewGroup)
75 {
76 setWindowTitle("Create new Statechart Group");
77 QRegExp rx("([a-zA-Z][a-zA-Z0-9]*)");
78 ui->editStatechartGroup->setValidator(new QRegExpValidator(rx, this));
79
80 connect(ui->btnSelectPackageFolder, SIGNAL(clicked()), this, SLOT(selectPackagePath()));
81 connect(ui->editPackagePath,
82 SIGNAL(textChanged(QString)),
83 this,
84 SLOT(requestCheckPackagePath(QString)));
85 connect(ui->editStatechartGroup,
86 SIGNAL(textChanged(QString)),
87 this,
88 SLOT(requestCheckPackagePath(QString)));
89
90 timer = new QTimer(this);
91 connect(timer, SIGNAL(timeout()), this, SLOT(checkPackagePath()));
92 timer->setSingleShot(true);
93
94 // disable ok button until everything is valid
95 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
96 ui->tabWidget->setCurrentIndex(0);
97 }
98 else if (editMode == EditGroup)
99 {
100 setWindowTitle(groupName + " - Properties");
101 ui->editStatechartGroup->setText(groupName);
102 ui->textEditGroupDescription->setPlainText(description);
103 ui->editPackagePath->setEnabled(false);
104 ui->editStatechartGroup->setEnabled(false);
105 ui->btnSelectPackageFolder->setEnabled(false);
106
107 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
108 }
109 else
110 {
111 throw LocalException("Not supported enum value.");
112 }
113
114 QStringList properties;
115 QStandardItemModel* model = new QStandardItemModel(ui->listProxies);
116 // Populate proxy/topic list
117 for (VariantInfo::LibEntryPtr lib : variantInfo->getLibs())
118 {
119 QString libName = QString::fromUtf8(lib->getName().c_str());
120
121 for (VariantInfo::ProxyEntryPtr proxy : lib->getProxies())
122 {
123 //QString proxyType = QString::fromUtf8(proxy->getProxyTypeAsString().c_str());
124 QString proxyHumanName = QString::fromUtf8(proxy->getHumanName().c_str());
125 QString proxyMemberName = QString::fromUtf8(proxy->getMemberName().c_str());
126 QString display = QString("[%1] %3").arg(libName, proxyHumanName);
127 QStandardItem* listItem = new QStandardItem(display);
128 QString proxyId = QString("%1.%2").arg(libName, proxyMemberName);
129 listItem->setData(proxyId, Qt::UserRole);
130 listItem->setCheckable(true);
131 listItem->setEditable(false);
132 listItem->setCheckState(selectedProxies.contains(proxyId) ? Qt::Checked
133 : Qt::Unchecked);
134 model->appendRow(listItem);
135 }
136 }
137 InfixFilterModel* filterModel = new InfixFilterModel(ui->listProxies);
138 filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
139 filterModel->setSourceModel(model);
140 ui->listProxies->setModel(filterModel);
141 connect(ui->lineEditProxyFilter,
142 SIGNAL(textChanged(QString)),
143 filterModel,
144 SLOT(setFilterFixedString(QString)));
145
146
147 std::list<StatechartProfilePtr> profileQueue;
148 profileQueue.push_back(statechartProfiles->getRootProfile());
149 connect(ui->comboBoxStatechartProfiles,
150 SIGNAL(currentIndexChanged(QString)),
151 this,
152 SLOT(updateConfigurationTextField(QString)));
153 connect(ui->tabWidget,
154 SIGNAL(currentChanged(int)),
155 this,
156 SLOT(updateConfigurationContent(int)));
157 while (!profileQueue.empty())
158 {
159 StatechartProfilePtr currentProfile = profileQueue.front();
160 profileQueue.pop_front();
161 ui->comboBoxStatechartProfiles->addItem(
162 QString(currentProfile->getNesting(), '-') + " " +
163 QString::fromStdString(currentProfile->getName()),
164 QString::fromStdString(currentProfile->getName()));
165 for (auto it = currentProfile->getChildren().rbegin();
166 it != currentProfile->getChildren().rend();
167 it++)
168 {
169 profileQueue.push_front(*it);
170 }
171 if (profileQueue.size() == 0)
172 {
173 break;
174 }
175 if (configurations[QString::fromStdString(currentProfile->getName())].isEmpty())
176 {
177 configurations[QString::fromStdString(currentProfile->getName())] =
178 properties.join("\n");
179 }
180 }
181 connect(
182 ui->textEditParameters, SIGNAL(textChanged()), this, SLOT(storeConfigurationText()));
183 connect(ui->listProxies->model(),
184 SIGNAL(dataChanged(QModelIndex, QModelIndex)),
185 this,
186 SLOT(updateDependencies(QModelIndex, QModelIndex)));
187
189 }
190
195
198 {
199 return packageTool;
200 }
201
202 QString
204 {
205 return ui->editStatechartGroup->text();
206 }
207
208 QString
210 {
211 // new behavior
212 {
213 CMakePackageFinder finder(getPackageName().toStdString());
214
215 std::filesystem::path path = finder.getStatechartsDir();
216
217 if (not path.empty())
218 {
219 path /= getGroupName().toUtf8().data();
220 return QString::fromStdString(path.string());
221 }
222 }
223
224 // legacy behavior
225
226 ARMARX_WARNING << "The package `" << getPackageName()
227 << "` does not provide the STATECHARTS_DIR cmake variable!"
228 << "Using legacy path for now.";
229
230 std::filesystem::path path = ui->editPackagePath->text().toUtf8().data();
231 path /= "source";
232 path /= getPackageName().toUtf8().data();
233 path /= "statecharts";
234 path /= getGroupName().toUtf8().data();
235
236 return QString::fromUtf8(path.c_str());
237 }
238
239 QString
241 {
242 return ui->textEditGroupDescription->toPlainText();
243 }
244
245 QString
247 {
248 const std::filesystem::path packagePath = getPackagePath().toStdString();
249
250 std::vector<std::string> packages = CMakePackageFinder::FindAllArmarXSourcePackages();
251 ARMARX_IMPORTANT << VAROUT(packages);
252 for (const std::string& package : packages)
253 {
254 CMakePackageFinder finder(package);
255 if (finder.getPackageDir() == packagePath)
256 {
257 return QString::fromStdString(package);
258 }
259 }
260 std::stringstream ss;
261 ss << "No CMake package found for path " << packagePath << ".";
262 throw LocalException(ss.str());
263
264 // std::filesystem::path path = getPackagePath().toUtf8().data();
265 // return QString::fromUtf8(path.filename().c_str());
266 }
267
268 QString
270 {
271 std::filesystem::path path = ui->editPackagePath->text().toUtf8().data();
272 std::filesystem::path cleanPath = path;
273
274 try
275 {
276 cleanPath = std::filesystem::canonical(path);
277 }
278 catch (...)
279 {
280 cleanPath = ArmarXDataPath::cleanPath(path.string());
281
282 if (*cleanPath.string().rbegin() == '/' || *cleanPath.string().rbegin() == '\\')
283 {
284 cleanPath = cleanPath.remove_filename();
285 }
286 }
287
288 return QString::fromUtf8(cleanPath.c_str());
289 }
290
291 QList<QString>
293 {
294 QList<QString> proxies;
295 QSortFilterProxyModel* proxy =
296 qobject_cast<QSortFilterProxyModel*>(ui->listProxies->model());
297 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(proxy->sourceModel());
298 for (int row = 0; row < model->rowCount(); row++)
299 {
300 auto item = model->item(row);
301 if (item && item->checkState() == Qt::Checked)
302 {
303 proxies.append(item->data(Qt::UserRole).toString());
304 }
305 }
306
307 return proxies;
308 }
309
310 bool
312 {
313 return ui->checkBoxGenerateContext->isChecked();
314 }
315
316 QMap<QString, QString>
318 {
319 return configurations;
320 }
321
322 void
324 {
325 timer->start(250);
326 }
327
328 void
330 {
331 QFileDialog selectFolder(this, "Select ArmarX Package Root Folder");
332 QList<QUrl> urls;
333 urls << QUrl::fromLocalFile(
334 QDesktopServices::storageLocation(QDesktopServices::HomeLocation))
335 << QUrl::fromLocalFile(
336 QDesktopServices::storageLocation(QDesktopServices::DesktopLocation));
337
338 if (!ArmarXDataPath::getHomePath().empty())
339 {
340 urls << QUrl::fromLocalFile(QString::fromStdString(ArmarXDataPath::getHomePath()));
341 }
342
343 selectFolder.setSidebarUrls(urls);
344 // selectFolder.setOption(QFileDialog::ShowDirsOnly, true);
345 selectFolder.setOption(QFileDialog::ReadOnly, true);
346 selectFolder.setOption(QFileDialog::HideNameFilterDetails, false);
347 selectFolder.setFileMode(QFileDialog::Directory);
348
349 if (selectFolder.exec() == QDialog::Accepted)
350 {
351 ui->editPackagePath->setText(*selectFolder.selectedFiles().begin());
352 }
353 }
354
355 void
357 {
358 std::string cmdOutput;
359 if (packageTool->checkPackagePath(ui->editPackagePath->text().toStdString(), cmdOutput))
360 {
361 ui->labelPackageError->setText("Package path is valid.");
362 QPalette p(ui->labelPackageError->palette());
363 p.setColor(ui->labelPackageError->backgroundRole(), QColor::fromRgb(120, 255, 120));
364 // p.setBrush(ui->labelPackageError->backgroundRole(), p.light());
365 ui->labelPackageError->setPalette(p);
366
367 if (!ui->editStatechartGroup->text().isEmpty())
368 {
369 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
370 }
371 else
372 {
373 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
374 }
375 ui->labelPackageError->setToolTip("");
376 ui->btnShowPackageError->setVisible(false);
377 }
378 else
379 {
380 ui->labelPackageError->setText("Package path is not valid!");
381 ui->labelPackageError->setToolTip(QString::fromStdString(cmdOutput));
382 QPalette p(ui->labelPackageError->palette());
383 p.setColor(ui->labelPackageError->backgroundRole(), QColor::fromRgb(255, 120, 120));
384 ui->labelPackageError->setPalette(p);
385 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
386 ui->btnShowPackageError->setVisible(true);
387 }
388 }
389
390 void
392 {
393 ui->listProxies->setEnabled(ui->checkBoxGenerateContext->isChecked());
394 }
395
396 void
398 {
399 int i = ui->comboBoxStatechartProfiles->findText(profileText);
400 if (i < 0)
401 {
402 return;
403 }
404 auto profile = ui->comboBoxStatechartProfiles->itemData(i).toString();
405 ui->textEditParameters->setPlainText(configurations[profile]);
406 }
407
408 void
410 {
411 int i = ui->comboBoxStatechartProfiles->currentIndex();
412 auto profile = ui->comboBoxStatechartProfiles->itemData(i).toString();
413 configurations[profile] = ui->textEditParameters->toPlainText();
414 }
415
416 void
420
421 void
422 EditStatechartGroupDialog::updateDependencies(QModelIndex index1, QModelIndex index2)
423 {
424 auto selectedProxies = getProxies();
425 QStringList libs;
426 for (VariantInfo::LibEntryPtr lib : variantInfo->getLibs())
427 {
428 QString libName = QString::fromUtf8(lib->getName().c_str());
429 for (VariantInfo::ProxyEntryPtr proxy : lib->getProxies())
430 {
431 QString proxyMemberName = QString::fromUtf8(proxy->getMemberName().c_str());
432 QString proxyId = QString("%1.%2").arg(libName, proxyMemberName);
433 if (selectedProxies.contains(proxyId))
434 {
435 if (!libs.contains(libName))
436 {
437 libs << (libName);
438 }
439 }
440 }
441 }
442 if (group)
443 {
444 QSet<QString> vars;
445 Ice::StringSeq types;
446 for (statechartmodel::StatePtr state : group->getAllStates(true))
447 {
448 for (auto& param : state->getInputParameters())
449 {
450 vars.insert(param->type);
451 }
452 for (auto& param : state->getLocalParameters())
453 {
454 vars.insert(param->type);
455 }
456 for (auto& param : state->getOutputParameters())
457 {
458 vars.insert(param->type);
459 }
460 }
461 for (auto& var : vars)
462 {
463 auto type = VariantContainerType::GetInnerType(var.toStdString());
464 if (!type.empty())
465 {
466 types.push_back(type);
467 }
468 }
469 for (std::string& lib : variantInfo->findLibNames(types))
470 {
471 auto libName = QString::fromStdString(lib);
472 if (!libs.contains(libName))
473 {
474 libs << libName;
475 }
476 }
477 }
478 ui->editDependencies->setText(libs.join(" "));
479 }
480} // namespace armarx
481
482void
483armarx::EditStatechartGroupDialog::on_pushButton_clicked()
484{
485 auto selectedProxies = getProxies();
486 auto groupName = getGroupName();
487 int i = ui->comboBoxStatechartProfiles->currentIndex();
488 if (i < 0)
489 {
490 return;
491 }
492 auto profileName = ui->comboBoxStatechartProfiles->itemData(i).toString();
493 for (VariantInfo::LibEntryPtr lib : variantInfo->getLibs())
494 {
495 QString libName = QString::fromUtf8(lib->getName().c_str());
496
497 for (VariantInfo::ProxyEntryPtr proxy : lib->getProxies())
498 {
499 QString proxyMemberName = QString::fromUtf8(proxy->getMemberName().c_str());
500 QString proxyId = QString("%1.%2").arg(libName, proxyMemberName);
501 if (selectedProxies.contains(proxyId))
502 {
503 QString propName = QString("ArmarX.") + groupName + "RemoteStateOfferer." +
504 QString::fromUtf8(proxy->getPropertyName().c_str());
505
506 if (!configurations[profileName].contains(propName))
507 {
508 QString newProp;
509 if (!proxy->getPropertyIsOptional())
510 {
511 newProp += "# Required Property\n";
512 newProp += "#" + propName + " = <set value and uncomment!>\n";
513 }
514 else
515 {
516 newProp += "#" + propName + " = " +
517 QString::fromUtf8(proxy->getPropertyDefaultValue().c_str()) +
518 "\n";
519 }
520
521 configurations[profileName] += "\n" + newProp;
522 }
523 }
524 }
525 }
526 updateConfigurationTextField(ui->comboBoxStatechartProfiles->currentText());
527}
528
529void
530armarx::EditStatechartGroupDialog::on_btnShowPackageError_clicked()
531{
532 QToolTip::showText(ui->btnShowPackageError->mapToGlobal(QPoint(10, 10)),
533 ui->labelPackageError->toolTip());
534}
uint8_t index
#define VAROUT(x)
static std::string cleanPath(const std::string &filepathStr)
static std::string getHomePath()
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
std::string getStatechartsDir() const
std::string getPackageDir() const
Returns the top level path of a source package.
static std::vector< std::string > FindAllArmarXSourcePackages()
QMap< QString, QString > getConfigurations() const
ArmarXPackageToolInterfacePtr getPackageTool() const
EditStatechartGroupDialog(EditMode editMode, QString groupName, ArmarXPackageToolInterfacePtr packageTool, VariantInfoPtr variantInfo, QList< QString > selectedProxies, bool generateContext, const StatechartProfilesPtr &statechartProfiles, const QMap< QString, QString > &statechartGroupConfigurations=QMap< QString, QString >(), const QString &description="", StatechartGroupPtr group=StatechartGroupPtr(), QWidget *parent=0)
void updateDependencies(QModelIndex index1=QModelIndex(), QModelIndex index2=QModelIndex())
void updateConfigurationTextField(QString profileText)
This proxy model reimplements the filterAcceptsRow function with a new behavior: All elements that fi...
static std::string GetInnerType(const std::string &typeStr)
std::shared_ptr< LibEntry > LibEntryPtr
std::shared_ptr< ProxyEntry > ProxyEntryPtr
Definition VariantInfo.h:76
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
ArmarX Headers.
bool contains(const MemoryID &general, const MemoryID &specific)
Indicates whether general is "less specific" than, or equal to, specific, i.e.
Definition MemoryID.cpp:563
std::shared_ptr< State > StatePtr
Definition State.h:48
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< StatechartProfiles > StatechartProfilesPtr
std::shared_ptr< StatechartGroup > StatechartGroupPtr
std::shared_ptr< VariantInfo > VariantInfoPtr
Definition VariantInfo.h:39
std::shared_ptr< class StatechartProfile > StatechartProfilePtr
std::shared_ptr< ArmarXPackageToolInterface > ArmarXPackageToolInterfacePtr