42 #include <moveit/task_constructor/properties.h>
44 #include <moveit_task_constructor_msgs/GetSolution.h>
49 #include <QApplication>
87 void setProperties(
const std::vector<moveit_task_constructor_msgs::Property>& props,
90 const planning_scene::PlanningSceneConstPtr& scene_,
94 void RemoteTaskModel::Node::setProperties(
const std::vector<moveit_task_constructor_msgs::Property>& props,
95 const planning_scene::PlanningSceneConstPtr& scene_,
100 for (
const auto& prop : props) {
101 int num =
root->numChildren();
104 while (next < num && root->childAt(
next)->
getName().toStdString() < prop.name)
108 num =
root->numChildren();
112 if (old_child && old_child->
getName().toStdString() != prop.name)
115 rviz::Property* new_child = createProperty(prop, old_child, scene_, display_context_);
116 if (new_child != old_child)
124 rviz::Property* RemoteTaskModel::Node::createProperty(
const moveit_task_constructor_msgs::Property& prop,
126 const planning_scene::PlanningSceneConstPtr& scene_,
128 auto& factory = PropertyFactory::instance();
131 if (!
value.empty()) {
132 auto it = properties_.insert(std::make_pair(prop.name,
Property())).first;
133 it->second.setDescription(prop.description);
134 it->second.setValue(
value);
135 if (
rviz::Property* rviz_prop = factory.create(prop.name, it->second, scene_.get(), display_context_)) {
136 rviz_prop->setReadOnly(
true);
139 properties_.erase(it);
143 return factory.createDefault(prop.name, prop.type, prop.description, prop.value, old);
148 if (!
index.isValid())
151 if (
index.model() !=
this) {
164 auto it = id_to_stage_.find(stage_id);
165 return (it == id_to_stage_.end()) ? nullptr : it->second;
169 QModelIndex RemoteTaskModel::index(
const Node* n)
const {
171 return QModelIndex();
176 for (
int row = 0, end = parent->
children_.size(); row != end; ++row)
177 if (parent->
children_.at(row).get() == n)
178 return createIndex(row, 0, parent);
180 return QModelIndex();
183 RemoteTaskModel::RemoteTaskModel(
ros::NodeHandle& nh,
const std::string& service_name,
184 const planning_scene::PlanningSceneConstPtr& scene,
209 return QModelIndex();
212 if (!p || row < 0 ||
static_cast<size_t>(row) >= p->
children_.size())
213 return QModelIndex();
217 return createIndex(row, column, p);
221 if (!child.isValid())
222 return QModelIndex();
225 Node* p =
static_cast<Node*
>(child.internalPointer());
227 if (child.model() !=
this || p ==
root_)
228 return QModelIndex();
230 return this->
index(p);
240 case Qt::DisplayRole:
241 switch (
index.column()) {
249 return QLocale().toString(n->
solutions_->totalComputeTime(),
'f', 4);
252 case Qt::ForegroundRole:
253 if (
index.column() == 0 && !
index.parent().isValid())
254 return (
flags_ &
IS_DESTROYED) ? QColor(Qt::red) : QApplication::palette().text().color();
256 case Qt::DecorationRole:
257 if (
index.column() == 0 &&
index.parent().isValid())
267 if (!n ||
index.column() != 0 || role != Qt::EditRole)
277 return n ?
index(n) : QModelIndex();
282 for (
const auto&
s : msg) {
286 ROS_ERROR_NAMED(
"TaskListModel",
"No parent found for stage %d (%s)",
s.id,
s.name.c_str());
296 int row =
parent->children_.size();
299 beginInsertRows(parent_idx, row, row);
300 parent->children_.push_back(std::make_unique<Node>(
parent));
305 n =
parent->children_.back().get();
310 bool changed =
false;
312 changed |= n->
setName(QString::fromStdString(
s.name));
328 QModelIndex idx =
index(n);
329 dataChanged(idx, idx.sibling(idx.row(), 2));
341 for (
const auto&
s : msg) {
348 Node* n = it->second;
349 n->
solutions_->processSolutionIDs(
s.solved,
s.failed,
s.num_failed,
s.total_compute_time);
353 QModelIndex idx =
index(n);
354 dataChanged(idx.sibling(idx.row(), 1), idx.sibling(idx.row(), 3));
363 m->setSolutionData(info.id, info.cost, QString::fromStdString(info.comment));
368 s->setFromMessage(
scene_->diff(), msg);
371 for (
const auto& sub : msg.sub_solution)
373 for (
const auto& sub : msg.sub_trajectory)
378 if (!msg.sub_solution.empty() && msg.sub_solution.front().info.stage_id == 1 &&
379 msg.sub_solution.front().info.id != 0) {
385 for (
const auto&
t : msg.sub_trajectory) {
388 DisplaySolutionPtr& sub =
389 id_to_solution_.insert(std::make_pair(
t.info.id, DisplaySolutionPtr())).first->second;
412 Q_ASSERT(
index.isValid());
420 DisplaySolutionPtr result;
423 moveit_task_constructor_msgs::GetSolution srv;
424 srv.request.solution_id = id;
448 typename T::iterator
findById(T& c, decltype((*
c.cbegin())->id)
id) {
449 return std::find_if(
c.begin(),
c.end(), [
id](
const typename T::value_type& item) { return item->id == id; });
454 typename T::iterator
insert(T& c,
typename T::value_type&& item) {
455 auto p = std::equal_range(
c.begin(),
c.end(), item);
456 if (p.first == p.second)
457 return c.insert(p.second, std::move(item));
474 if (orientation == Qt::Horizontal) {
476 case Qt::DisplayRole:
483 return tr(
"comment");
486 case Qt::TextAlignmentRole:
487 return Qt::AlignLeft;
490 return QAbstractItemModel::headerData(section, orientation, role);
494 Q_ASSERT(
index.isValid());
495 Q_ASSERT(!
index.parent().isValid());
503 case Qt::ToolTipRole:
504 #if 0 // show internal solution id in first column
505 if (
index.column() == 0)
512 case Qt::DisplayRole:
513 switch (
index.column()) {
517 if (std::isinf(item.
cost))
519 if (std::isnan(item.
cost))
521 return QLocale().toString(item.
cost,
'f', 4);
527 case Qt::ForegroundRole:
528 if (std::isinf(item.
cost))
529 return QColor(Qt::red);
532 case Qt::TextAlignmentRole:
533 return index.column() == 2 ? Qt::AlignLeft : Qt::AlignRight;
546 if (item.
cost != cost) {
548 tl = br =
index(row, 1);
557 Q_EMIT dataChanged(tl, br);
574 Q_EMIT layoutAboutToBeChanged();
575 QModelIndexList old_indexes = persistentIndexList();
576 std::vector<DataList::iterator> old_sorted;
577 std::swap(
sorted_, old_sorted);
580 for (
auto it =
data_.begin(), end =
data_.end(); it != end; ++it)
586 [
this](
const DataList::iterator& left,
const DataList::iterator& right) {
588 switch (sort_column_) {
590 if (left->cost_rank < right->cost_rank)
592 else if (left->cost_rank > right->cost_rank)
596 comp = left->comment.compare(right->comment);
600 comp = (left->id < right->id ? -1 : 1);
601 return (
sort_order_ == Qt::AscendingOrder) ? (comp < 0) : (comp >= 0);
606 std::map<int, int> old_to_new_row;
607 QModelIndexList new_indexes;
608 for (
int i = 0, end = old_indexes.count(); i != end; ++i) {
609 int old_row = old_indexes[i].row();
610 auto it_inserted = old_to_new_row.insert(std::make_pair(old_row, -1));
611 if (it_inserted.second) {
613 if (it != sorted_.cend())
614 it_inserted.first->second = it - sorted_.begin();
616 new_indexes.append(
index(it_inserted.first->second, old_indexes[i].column()));
619 changePersistentIndexList(old_indexes, new_indexes);
620 Q_EMIT layoutChanged();
624 void RemoteSolutionModel::processSolutionIDs(
const std::vector<uint32_t>& successful,
625 const std::vector<uint32_t>& failed,
size_t num_failed,
626 double total_compute_time) {
628 processSolutionIDs(successful,
true);
629 processSolutionIDs(failed,
false);
633 for (
auto& item : data_)
634 item.creation_rank = ++rank;
638 num_failed_data_ = failed.size();
639 num_failed_ = std::max(num_failed, num_failed_data_);
640 total_compute_time_ = total_compute_time;
645 void RemoteSolutionModel::processSolutionIDs(
const std::vector<uint32_t>& ids,
bool successful) {
648 double default_cost =
649 successful ? std::numeric_limits<double>::quiet_NaN() : std::numeric_limits<double>::infinity();
652 uint32_t rank = successful ? ++cost_rank : std::numeric_limits<uint32_t>::max();
654 Q_ASSERT(it->id ==
id);
655 it->cost_rank = rank;
660 return std::isnan(item.
cost) || item.
cost <= max_cost_;