implemented TaskListModel::removeRows

This commit is contained in:
Robert Haschke 2017-11-02 21:37:36 +01:00
parent 18119a7985
commit 0f9c8cc8ea
7 changed files with 100 additions and 93 deletions

View File

@ -43,6 +43,7 @@
#include <ros/init.h> #include <ros/init.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <initializer_list> #include <initializer_list>
#include <qcoreapplication.h>
using namespace moveit::task_constructor; using namespace moveit::task_constructor;
@ -200,3 +201,18 @@ TEST_F(TaskListModelTest, visitedPopulate) {
EXPECT_EQ(num_inserts, 3); EXPECT_EQ(num_inserts, 3);
EXPECT_EQ(num_updates, 0); EXPECT_EQ(num_updates, 0);
} }
TEST_F(TaskListModelTest, deletion) {
children = 3;
model.processTaskMessage(genMsg("first"));
moveit_rviz_plugin::BaseTaskModel *m = model.getTask(0);
int num_deletes = 0;
QObject::connect(m, &QObject::destroyed, [&num_deletes](){++num_deletes;});
model.removeTask(m);
// process deleteLater() events
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
// as m is owned by model, m should be destroyed
// EXPECT_EQ(num_deletes, 1); // TODO: event is not processed, missing event loop?
EXPECT_EQ(model.rowCount(), 0);
}

View File

@ -143,6 +143,8 @@ public:
return q_ptr->createIndex(src.row(), src.column(), src_parent.internalPointer()); return q_ptr->createIndex(src.row(), src.column(), src_parent.internalPointer());
} }
void removeTask(BaseTaskModel *model);
private: private:
void _q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end); void _q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
void _q_sourceRowsInserted(const QModelIndex &parent, int start, int end); void _q_sourceRowsInserted(const QModelIndex &parent, int start, int end);
@ -248,12 +250,6 @@ bool TaskListModel::setData(const QModelIndex &index, const QVariant &value, int
return task->model_->setData(src_index, value, role); return task->model_->setData(src_index, value, role);
} }
bool TaskListModel::removeRows(int row, int count, const QModelIndex &parent)
{
// TODO
return false;
}
// process a task monitoring message: // process a task monitoring message:
// update existing RemoteTask, create a new one, // update existing RemoteTask, create a new one,
// or (if msg.stages is empty) delete an existing one // or (if msg.stages is empty) delete an existing one
@ -309,7 +305,8 @@ BaseTaskModel *TaskListModel::getTask(int row) const
return d->tasks_.at(row).model_; return d->tasks_.at(row).model_;
} }
void TaskListModel::insertTask(BaseTaskModel* model, int row) { void TaskListModel::insertTask(BaseTaskModel* model, int row)
{
Q_D(TaskListModel); Q_D(TaskListModel);
if (row < 0 || (size_t)row > d->tasks_.size()) if (row < 0 || (size_t)row > d->tasks_.size())
@ -323,11 +320,6 @@ void TaskListModel::insertTask(BaseTaskModel* model, int row) {
d->tasks_.insert(it, TaskListModelPrivate::BaseModelData(model)); d->tasks_.insert(it, TaskListModelPrivate::BaseModelData(model));
endInsertRows(); endInsertRows();
// notice destruction of task
if (model->parent() != this)
connect(model, &BaseTaskModel::destroyed,
[this](QObject* o) { removeTask(static_cast<BaseTaskModel*>(o), false); });
connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int))); this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
@ -344,40 +336,74 @@ void TaskListModel::insertTask(BaseTaskModel* model, int row) {
this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>))); this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
} }
bool TaskListModel::removeTask(BaseTaskModel* model, bool disconnect_signals) { bool TaskListModel::removeTask(BaseTaskModel* model)
{
Q_D(TaskListModel); Q_D(TaskListModel);
// find row corresponding to model // find row corresponding to model
auto it = std::find_if(d->tasks_.begin(), d->tasks_.end(), auto it = std::find_if(d->tasks_.begin(), d->tasks_.end(),
[model](const TaskListModelPrivate::BaseModelData& data) { return data.model_ == model; }); [model](const TaskListModelPrivate::BaseModelData& data) {
return data.model_ == model;
});
if (it == d->tasks_.end()) if (it == d->tasks_.end())
return false; // model not found return false; // model not found
ROS_DEBUG_NAMED("TaskListModel", "%p: removing task: %p", this, model); return removeTasks(it - d->tasks_.begin(), 1);
size_t row = it - d->tasks_.begin(); }
beginRemoveRows(QModelIndex(), row, row);
d->tasks_.insert(it, TaskListModelPrivate::BaseModelData(model));
endRemoveRows();
if (disconnect_signals) { // reacting on signal destroyed(), signals are already disconnected bool TaskListModel::removeTasks(int row, int count)
disconnect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), {
this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int))); Q_D(TaskListModel);
disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), if (row < 0 || row+count > rowCount())
this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int))); return false;
disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int))); auto first = d->tasks_.begin(); std::advance(first, row);
disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), auto last = first; std::advance(last, count);
this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int))); beginRemoveRows(QModelIndex(), row, row+count-1);
disconnect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), std::for_each(first, last, [d](TaskListModelPrivate::BaseModelData &data) {
this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); d->removeTask(data.model_);
disconnect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), });
this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))); d->tasks_.erase(first, last);
disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), endRemoveRows();
this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
}
return true; return true;
} }
bool TaskListModel::removeRows(int row, int count, const QModelIndex &parent)
{
Q_D(TaskListModel);
if (!parent.isValid()) { // top-level items = tasks
return removeTasks(row, count);
} else {
TaskListModelPrivate::BaseModelData *data = nullptr;
QModelIndex src_parent = d->mapToSource(parent, &data);
return data->model_->removeRows(row, count, src_parent);
}
}
void TaskListModelPrivate::removeTask(BaseTaskModel *model)
{
ROS_DEBUG_NAMED("TaskListModel", "%p: removing task: %p", q_ptr, model);
QObject::disconnect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
q_ptr, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
QObject::disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
q_ptr, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
QObject::disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
q_ptr, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
QObject::disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
q_ptr, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
QObject::disconnect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
q_ptr, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
QObject::disconnect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
q_ptr, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
QObject::disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
q_ptr, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
// delete model if we own it
if (model->parent() == q_ptr)
model->deleteLater();
}
void TaskListModelPrivate::_q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) void TaskListModelPrivate::_q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
{ {
q_ptr->beginInsertRows(mapFromSource(parent), start, end); q_ptr->beginInsertRows(mapFromSource(parent), start, end);

View File

@ -99,7 +99,8 @@ public:
/// insert a TaskModel into our list /// insert a TaskModel into our list
void insertTask(BaseTaskModel* model, int row = -1); void insertTask(BaseTaskModel* model, int row = -1);
bool removeTask(BaseTaskModel* model, bool disconnect_signals = true); bool removeTask(BaseTaskModel* model);
bool removeTasks(int row, int count);
private: private:
Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(QModelIndex,int,int)) Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(QModelIndex,int,int))

View File

@ -81,9 +81,8 @@ TaskPanel::TaskPanel(QWidget* parent)
{ {
Q_D(TaskPanel); Q_D(TaskPanel);
// connect signals // connect signals
connect(d->actionNewTask, &QAction::triggered, this, &TaskPanel::onAddTask); connect(d->actionRemoveTaskTreeRows, &QAction::triggered, this, &TaskPanel::removeTaskTreeRows);
connect(d->actionNewStage, &QAction::triggered, this, &TaskPanel::onAddStage); connect(d->button_show_stage_dock_widget, &QToolButton::clicked, this, &TaskPanel::showStageDockWidget);
connect(d->actionRemoveStages, &QAction::triggered, this, &TaskPanel::onRemoveStages);
} }
TaskPanel::~TaskPanel() TaskPanel::~TaskPanel()
@ -93,16 +92,16 @@ TaskPanel::~TaskPanel()
TaskPanelPrivate::TaskPanelPrivate(TaskPanel *q_ptr) TaskPanelPrivate::TaskPanelPrivate(TaskPanel *q_ptr)
: q_ptr(q_ptr) : q_ptr(q_ptr)
, tasks_model(TaskListModelCache::instance().getGlobalModel()) , task_list_model(TaskListModelCache::instance().getGlobalModel())
, settings(new rviz::PropertyTreeModel(new rviz::Property)) , settings(new rviz::PropertyTreeModel(new rviz::Property))
{ {
setupUi(q_ptr); setupUi(q_ptr);
initSettings(settings->getRoot()); initSettings(settings->getRoot());
settings_view->setModel(settings); settings_view->setModel(settings);
tasks_view->setModel(tasks_model.get()); tasks_view->setModel(task_list_model.get());
// init actions // init actions
tasks_view->addActions({actionNewTask, actionNewStage, actionRemoveStages}); tasks_view->addActions({actionRemoveTaskTreeRows});
} }
void TaskPanelPrivate::initSettings(rviz::Property* root) void TaskPanelPrivate::initSettings(rviz::Property* root)
@ -129,20 +128,20 @@ void TaskPanel::onAddTask()
{ {
Q_D(TaskPanel); Q_D(TaskPanel);
QModelIndex current = d->tasks_view->currentIndex(); QModelIndex current = d->tasks_view->currentIndex();
d_ptr->tasks_model->insertTask(new LocalTaskModel(this), current.row()); d_ptr->task_list_model->insertTask(new LocalTaskModel(this), current.row());
} }
void TaskPanel::onAddStage() void TaskPanel::showStageDockWidget()
{ {
rviz::PanelDockWidget *dock = getStageDockWidget(vis_manager_->getWindowManager()); rviz::PanelDockWidget *dock = getStageDockWidget(vis_manager_->getWindowManager());
dock->show(); dock->show();
} }
void TaskPanel::onRemoveStages() void TaskPanel::removeTaskTreeRows()
{ {
Q_D(TaskPanel); Q_D(TaskPanel);
for (const auto &range : d_ptr->tasks_view->selectionModel()->selection()) for (const auto &range : d_ptr->tasks_view->selectionModel()->selection())
d_ptr->tasks_model->removeRows(range.top(), range.bottom()-range.top()+1, range.parent()); d_ptr->task_list_model->removeRows(range.top(), range.bottom()-range.top()+1, range.parent());
} }
} }

View File

@ -70,8 +70,8 @@ public:
public Q_SLOTS: public Q_SLOTS:
void onAddTask(); void onAddTask();
void onAddStage(); void showStageDockWidget();
void onRemoveStages(); void removeTaskTreeRows();
}; };
} }

View File

@ -30,7 +30,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QToolButton" name="button_add_stage"> <widget class="QToolButton" name="button_show_stage_dock_widget">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>18</width> <width>18</width>
@ -66,36 +66,18 @@
<widget class="rviz::PropertyTreeWidget" name="settings_view"/> <widget class="rviz::PropertyTreeWidget" name="settings_view"/>
</item> </item>
</layout> </layout>
<action name="actionNewStage"> <action name="actionRemoveTaskTreeRows">
<property name="icon">
<iconset theme="add">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text"> <property name="text">
<string>New Stage</string> <string>Remove</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Add a new stage</string> <string>Remove selected rows</string>
</property> </property>
</action> <property name="shortcut">
<action name="actionNewTask"> <string>Del</string>
<property name="icon">
<iconset theme="add">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="shortcutContext">
<string>New Task</string> <enum>Qt::WidgetShortcut</enum>
</property>
<property name="toolTip">
<string>Add a new task</string>
</property>
</action>
<action name="actionRemoveStages">
<property name="text">
<string>Remove Stages</string>
</property>
<property name="toolTip">
<string>Remove selected stages</string>
</property> </property>
</action> </action>
</widget> </widget>
@ -107,22 +89,5 @@
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections> <connections/>
<connection>
<sender>button_add_stage</sender>
<signal>clicked()</signal>
<receiver>actionNewStage</receiver>
<slot>trigger()</slot>
<hints>
<hint type="sourcelabel">
<x>378</x>
<y>21</y>
</hint>
<hint type="destinationlabel">
<x>-1</x>
<y>-1</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

View File

@ -53,7 +53,7 @@ public:
void initSettings(rviz::Property *root); void initSettings(rviz::Property *root);
TaskPanel* q_ptr; TaskPanel* q_ptr;
TaskListModelPtr tasks_model; TaskListModelPtr task_list_model;
rviz::PropertyTreeModel* settings; rviz::PropertyTreeModel* settings;
}; };