39 #include <QApplication>
42 #include <QListWidget>
43 #include <QMessageBox>
44 #include <QProgressBar>
45 #include <QPushButton>
46 #include <QPushButton>
49 #include <QVBoxLayout>
54 #include <boost/algorithm/string.hpp>
68 has_generated_pkg_ =
false;
71 QVBoxLayout* layout =
new QVBoxLayout();
77 "Create or update the configuration files package needed to run your robot with MoveIt. Uncheck "
78 "files to disable them from being generated - this is useful if you have made custom changes to "
79 "them. Files in orange have been automatically detected as changed.",
81 layout->addWidget(header);
87 "Specify the desired directory for the MoveIt configuration package to be "
88 "generated. Overwriting an existing configuration package directory is acceptable. "
89 "Example: <i>/u/robot/ros/panda_moveit_config</i>",
92 connect(
stack_path_, SIGNAL(pathChanged(QString)),
this, SLOT(onPackagePathChanged(QString)));
95 QLabel* generated_list =
new QLabel(
"Check files you want to be generated:",
this);
96 layout->addWidget(generated_list);
98 QSplitter* splitter =
new QSplitter(Qt::Horizontal,
this);
99 splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
103 action_list_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
104 action_list_->setSelectionMode(QAbstractItemView::ExtendedSelection);
105 connect(
action_list_, SIGNAL(currentRowChanged(
int)),
this, SLOT(changeActionDesc(
int)));
107 action_list_->setContextMenuPolicy(Qt::ActionsContextMenu);
108 QAction*
action =
new QAction(
"Check all selected files",
this);
109 connect(
action, &QAction::triggered, [
this]() { setCheckSelected(
true); });
111 action =
new QAction(
"Uncheck all selected files",
this);
112 connect(
action, &QAction::triggered, [
this]() { setCheckSelected(
false); });
122 action_label_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
132 layout->addWidget(splitter);
135 QHBoxLayout* hlayout1 =
new QHBoxLayout();
145 btn_save_ =
new QPushButton(
"&Generate Package",
this);
148 connect(
btn_save_, SIGNAL(clicked()),
this, SLOT(savePackage()));
152 layout->addLayout(hlayout1);
156 QHBoxLayout* hlayout3 =
new QHBoxLayout();
160 QFont success_label_font(QFont().defaultFamily(), 12, QFont::Bold);
163 success_label_->setText(
"Configuration package generated successfully!");
168 QPushButton* btn_exit =
new QPushButton(
"E&xit Setup Assistant",
this);
169 btn_exit->setMinimumWidth(180);
170 connect(btn_exit, SIGNAL(clicked()),
this, SLOT(exitSetupAssistant()));
171 hlayout3->addWidget(btn_exit);
172 hlayout3->setAlignment(btn_exit, Qt::AlignRight);
174 layout->addLayout(hlayout3);
180 void ConfigurationFilesWidget::setCheckSelected(
bool checked)
182 for (
const QModelIndex& row :
action_list_->selectionModel()->selectedRows())
183 action_list_->model()->setData(row, checked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
186 void ConfigurationFilesWidget::onPackagePathChanged(
const QString& path)
188 std::filesystem::path package_path = path.toStdString();
203 bool ConfigurationFilesWidget::checkDependencies()
206 bool required_actions =
false;
212 if (!dependencies.empty())
216 if (!required_actions)
218 dep_message =
"Some setup steps have not been completed. None of the steps are required, but here is a reminder "
219 "of what was not filled in, just in case something was forgotten:<br /><ul>";
223 dep_message =
"Some setup steps have not been completed. Please fix the required steps (printed in bold), "
224 "otherwise the setup cannot be completed:<br /><ul>";
227 for (
const auto& dependency : dependencies)
229 dep_message.append(
"<li>").append(QString::fromStdString(dependency)).append(
"</li>");
232 if (!required_actions)
234 dep_message.append(
"</ul><br/>Press Ok to continue generating files.");
235 if (QMessageBox::question(
this,
"Incomplete MoveIt Setup Assistant Steps", dep_message,
236 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
243 QMessageBox::warning(
this,
"Incomplete MoveIt Setup Assistant Steps", dep_message);
254 void ConfigurationFilesWidget::updateProgress()
262 QApplication::processEvents();
268 void ConfigurationFilesWidget::changeActionDesc(
int id)
281 void ConfigurationFilesWidget::changeCheckedState(QListWidgetItem* item)
283 std::size_t index = item->data(Qt::UserRole).toUInt();
287 bool generate = (item->checkState() == Qt::Checked);
289 if (!generate && gen_file->hasChanges())
291 QMessageBox::warning(
this,
"Package Generation",
292 "You should generate this file to ensure your changes will take "
311 disconnect(
action_list_, SIGNAL(itemChanged(QListWidgetItem*)),
this, SLOT(changeCheckedState(QListWidgetItem*)));
317 connect(
action_list_, SIGNAL(itemChanged(QListWidgetItem*)),
this, SLOT(changeCheckedState(QListWidgetItem*)));
320 QApplication::processEvents();
326 QString msg(
"Some files have been modified outside of the Setup Assistant (according to timestamp). "
327 "The Setup Assistant will not overwrite these changes by default because often changing configuration "
328 "files manually is necessary, "
329 "but we recommend you check the list and enable the checkbox next to files you would like to "
333 msg +=
"<br/><font color='red'>Attention:</font> Some files (<font color='red'>marked red</font>) are changed "
334 "both, externally and in Setup Assistant.";
336 QMessageBox::information(
this,
"Files Modified", msg);
343 void ConfigurationFilesWidget::showGenFiles()
350 for (std::size_t i = 0; i < gen_files.size(); ++i)
352 auto gen_file = gen_files[i];
355 QListWidgetItem* item =
new QListWidgetItem(QString(gen_file->getRelativePath().c_str()),
action_list_, 0);
358 item->setCheckState(setup_step_.
shouldGenerate(gen_file) ? Qt::Checked : Qt::Unchecked);
360 auto status = gen_file->getStatus();
363 item->setForeground(QBrush(QColor(255, 0, 0)));
367 item->setForeground(QBrush(QColor(255, 135, 0)));
371 item->setData(Qt::UserRole, QVariant(
static_cast<qulonglong
>(i)));
375 action_desc_.append(QString(gen_file->getDescription().c_str()));
385 void ConfigurationFilesWidget::savePackage()
394 if (!generatePackage())
396 RCLCPP_ERROR_STREAM(setup_step_.
getLogger(),
"Failed to generate entire configuration package");
403 has_generated_pkg_ =
true;
409 bool ConfigurationFilesWidget::generatePackage()
414 boost::trim(package_path_s);
417 if (package_path_s.empty())
419 QMessageBox::warning(
this,
"Error Generating",
420 "No package path provided. Please choose a directory location to "
421 "generate the MoveIt configuration files.");
426 if (!checkDependencies())
430 if (!noGroupsEmpty())
439 QMessageBox::warning(
440 this,
"Incorrect Folder/Package",
441 QString(
"The chosen package location already exists but was not previously created using this MoveIt Setup "
443 "If this is a mistake, add the missing file: ")
444 .
append(SETUP_ASSISTANT_FILE.c_str()));
449 if (QMessageBox::question(
this,
"Confirm Package Update",
450 QString(
"Are you sure you want to overwrite this existing package with updated "
451 "configurations?<br /><i>")
452 .
append(package_path_s.c_str())
454 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
463 std::filesystem::path absolute_path;
472 absolute_path = gen_file->getPath();
475 RCLCPP_DEBUG_STREAM(setup_step_.
getLogger(),
"Creating file " << absolute_path.string());
478 if (!gen_file->write())
481 QMessageBox::critical(
this,
"Error Generating File",
482 QString(
"Failed to generate folder or file: '")
483 .
append(gen_file->getRelativePath().c_str())
484 .append(
"' at location:\n")
485 .append(absolute_path.c_str()));
497 void ConfigurationFilesWidget::exitSetupAssistant()
499 if (has_generated_pkg_ || QMessageBox::question(
this,
"Exit Setup Assistant",
500 QString(
"Are you sure you want to exit the MoveIt Setup Assistant?"),
501 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
510 bool ConfigurationFilesWidget::noGroupsEmpty()
514 if (!invalid_group.empty())
517 QMessageBox::warning(
519 QString(
"The planning group '")
520 .
append(invalid_group.c_str())
521 .append(
"' is empty and has no subcomponents associated with it (joints/links/chains/subgroups). You must "
522 "edit or remove this planning group before this configuration package can be saved."));
531 #include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
const rclcpp::Logger & getLogger() const
Makes a namespaced logger for this step available to the widget.
void loadFiles()
Populate the 'Files to be generated' list.
void setShouldGenerate(const std::string &rel_path, bool should_generate)
const std::filesystem::path & getPackagePath()
std::vector< std::string > getIncompleteWarnings() const
bool hasModifiedFiles() const
void setPackagePath(const std::filesystem::path &package_path)
std::string getInvalidGroupName() const
bool shouldGenerate(const GeneratedFilePtr &file) const
void setPackageName(const std::string &package_name)
unsigned int getNumFiles() const
const std::vector< GeneratedFilePtr > getGeneratedFiles() const
bool hasConflictingFiles() const
bool hasSetupAssistantFile()
std::string append(const std::string &left, const std::string &right)