Merge pull request #146 from v4hn/pr-master-rework-panel

rework RViz panel
This commit is contained in:
Michael Görner 2020-06-30 11:40:39 +02:00 committed by GitHub
commit a86bb4248a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 171 additions and 158 deletions

View File

@ -134,6 +134,8 @@ Qt::ItemFlags LocalTaskModel::flags(const QModelIndex& index) const {
// dropping into containers is enabled
if (c && stage_factory_)
flags |= Qt::ItemIsDropEnabled;
if (index.column() == 0)
flags |= Qt::ItemIsEditable; // name is editable
return flags;
}

View File

@ -232,13 +232,6 @@ QModelIndex RemoteTaskModel::parent(const QModelIndex& child) const {
return this->index(p);
}
Qt::ItemFlags RemoteTaskModel::flags(const QModelIndex& index) const {
Qt::ItemFlags flags = BaseTaskModel::flags(index);
if (index.column() == 0)
flags |= Qt::ItemIsEditable; // name is editable
return flags;
}
QVariant RemoteTaskModel::data(const QModelIndex& index, int role) const {
Node* n = node(index);
if (!n)
@ -495,7 +488,7 @@ QVariant RemoteSolutionModel::headerData(int section, Qt::Orientation orientatio
return tr("comment");
}
case Qt::TextAlignmentRole:
return section == 2 ? Qt::AlignLeft : Qt::AlignRight;
return Qt::AlignLeft;
}
}
return QAbstractItemModel::headerData(section, orientation, role);
@ -509,9 +502,11 @@ QVariant RemoteSolutionModel::data(const QModelIndex& index, int role) const {
switch (role) {
case Qt::UserRole:
case Qt::ToolTipRole:
return item.id;
case Qt::ToolTipRole:
return item.comment;
case Qt::DisplayRole:
switch (index.column()) {
case 0:

View File

@ -81,7 +81,6 @@ public:
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex& index) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;

View File

@ -2,6 +2,7 @@
* Software License Agreement (BSD License)
*
* Copyright (c) 2017, Bielefeld University
* Copyright (c) 2020, Hamburg University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -60,7 +61,7 @@ QVariant TaskListModel::horizontalHeader(int column, int role) {
case Qt::DisplayRole:
switch (column) {
case 0:
return tr("Name");
return tr("name");
case 1:
return tr(u8"");
case 2:
@ -80,7 +81,7 @@ QVariant TaskListModel::horizontalHeader(int column, int role) {
break;
case Qt::TextAlignmentRole:
return column == 0 ? Qt::AlignLeft : Qt::AlignRight;
return Qt::AlignLeft;
case Qt::ToolTipRole:
switch (column) {
@ -113,13 +114,6 @@ QVariant BaseTaskModel::data(const QModelIndex& index, int role) const {
return QVariant();
}
Qt::ItemFlags BaseTaskModel::flags(const QModelIndex& index) const {
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if (index.column() == 0)
flags |= Qt::ItemIsEditable; // name is editable
return flags;
}
QVariant BaseTaskModel::flowIcon(moveit::task_constructor::InterfaceFlags f) {
static const QIcon CONNECT_ICON = icons::CONNECT.icon();
static const QIcon FORWARD_ICON = icons::FORWARD.icon();
@ -359,99 +353,7 @@ Qt::DropActions TaskListModel::supportedDropActions() const {
return Qt::CopyAction | Qt::MoveAction;
}
AutoAdjustingTreeView::AutoAdjustingTreeView(QWidget* parent) : QTreeView(parent) {
// consider viewportSizeHint()
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
#endif
}
void AutoAdjustingTreeView::setStretchSection(int section) {
stretch_section_ = section;
updateGeometry();
}
void AutoAdjustingTreeView::setAutoHideSections(const QList<int>& sections) {
auto_hide_cols_ = sections;
updateGeometry();
}
void AutoAdjustingTreeView::setModel(QAbstractItemModel* model) {
size_hints_.clear();
QTreeView::setModel(model);
updateGeometry();
}
QSize AutoAdjustingTreeView::viewportSizeHint() const {
bool preferred = sizePolicy().horizontalPolicy() & QSizePolicy::ShrinkFlag;
auto m = model();
auto* h = header();
size_hints_.clear();
int width = 0;
for (int i = 0, end = m ? m->columnCount() : 0; i < end; ++i) {
size_hints_.push_back(h->sectionSizeHint(i));
if (preferred || !auto_hide_cols_.contains(i))
width += size_hints_.back();
}
QSize main_size(width, sizeHintForRow(0) * ((!preferred || !m) ? 2 : m->rowCount()));
// add size for header
QSize header_size(0, header()->isVisible() ? header()->height() : 0);
// add size for scrollbars
QSize scrollbars(verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0,
horizontalScrollBar()->isVisible() ? horizontalScrollBar()->height() : 0);
return main_size + header_size + scrollbars;
}
void AutoAdjustingTreeView::resizeEvent(QResizeEvent* event) {
auto* m = model();
int columns = m ? m->columnCount() : 0;
if ((int)size_hints_.size() != columns)
viewportSizeHint();
// auto hide/show columns > 0, stretch last column to width
int available_width = event->size().width();
int required_width = std::accumulate(size_hints_.begin(), size_hints_.end(), 0);
std::vector<int> width = size_hints_;
// if required is larger than available width, try to hide some columns
QListIterator<int> it(auto_hide_cols_);
for (it.toBack(); it.hasPrevious() && required_width > available_width;) {
int section = it.previous();
required_width -= size_hints_[section];
width[section] = 0;
}
// extend width to current column width if possible
for (int i = 0; i < columns; ++i) {
if (i == stretch_section_)
continue; // ignore auto-stretch section for now
int delta = columnWidth(i) > 0 ? columnWidth(i) - width[i] : 0;
if (delta < 0 || required_width + delta <= available_width) {
width[i] += delta;
required_width += delta;
}
}
// stretch section if there is still space available
if (stretch_section_ >= 0 && stretch_section_ < (int)width.size() && width[stretch_section_] > 0 &&
available_width > required_width)
width[stretch_section_] += available_width - required_width;
// apply stuff
for (int i = 0; i < columns; ++i)
setColumnWidth(i, width[i]);
}
TaskListView::TaskListView(QWidget* parent) : AutoAdjustingTreeView(parent) {
setStretchSection(0);
}
TaskListView::TaskListView(QWidget* parent) : QTreeView(parent) {}
// dropping onto an item, should expand this item
void TaskListView::dropEvent(QDropEvent* event) {
@ -460,6 +362,64 @@ void TaskListView::dropEvent(QDropEvent* event) {
if (event->isAccepted())
expand(index);
}
void TaskListView::setModel(QAbstractItemModel* model) {
QTreeView::setModel(model);
if (header()->count() >= 4) {
header()->setSectionResizeMode(0, QHeaderView::Stretch);
updateColumnWidth();
}
}
void TaskListView::dataChanged(const QModelIndex& /*topLeft*/, const QModelIndex& bottomRight,
const QVector<int>& /*roles*/) {
if (bottomRight.column() > 0) {
updateColumnWidth();
}
}
void TaskListView::updateColumnWidth() {
for (int i = 3; i > 0; --i) {
header()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
}
}
SolutionListView::SolutionListView(QWidget* parent) : QTreeView(parent) {}
void SolutionListView::setModel(QAbstractItemModel* model) {
QTreeView::setModel(model);
updateColumnWidth();
}
void SolutionListView::dataChanged(const QModelIndex& /*topLeft*/, const QModelIndex& bottomRight,
const QVector<int>& /*roles*/) {
if (bottomRight.column() > 0) {
updateColumnWidth();
}
}
void SolutionListView::resizeEvent(QResizeEvent* e) {
QTreeView::resizeEvent(e);
updateColumnWidth();
}
void SolutionListView::updateColumnWidth() {
// do nothing if current model is not what we expect
if (header()->count() < 3) {
return;
}
for (int i = 0; i < 2; ++i) {
header()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
}
const int stretch_size = viewport()->size().width() - header()->sectionPosition(2);
const int content_size = sizeHintForColumn(2);
header()->resizeSection(2, std::max(stretch_size, content_size));
}
} // namespace moveit_rviz_plugin
#include "moc_task_list_model.cpp"

View File

@ -2,6 +2,7 @@
* Software License Agreement (BSD License)
*
* Copyright (c) 2017, Bielefeld University
* Copyright (c) 2020, Hamburg University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -47,6 +48,7 @@
#include <QAbstractItemModel>
#include <QTreeView>
#include <QTableView>
#include <memory>
#include <QPointer>
@ -94,7 +96,6 @@ public:
QVariant data(const QModelIndex& index, int role) const override;
virtual void setStageFactory(const StageFactoryPtr& factory) {}
Qt::ItemFlags flags(const QModelIndex& index) const override;
unsigned int taskFlags() const { return flags_; }
static QVariant flowIcon(moveit::task_constructor::InterfaceFlags f);
@ -178,34 +179,34 @@ protected Q_SLOTS:
void highlightStage(size_t id);
};
class AutoAdjustingTreeView : public QTreeView
{
Q_OBJECT
Q_PROPERTY(int stretchSection READ stretchSection WRITE setStretchSection)
mutable std::vector<int> size_hints_; // size hints for sections
QList<int> auto_hide_cols_; // auto-hiding sections
int stretch_section_ = -1;
public:
AutoAdjustingTreeView(QWidget* parent = nullptr);
int stretchSection() const { return stretch_section_; }
void setStretchSection(int section);
void setAutoHideSections(const QList<int>& sections);
void setModel(QAbstractItemModel* model) override;
QSize viewportSizeHint() const override;
void resizeEvent(QResizeEvent* event) override;
};
class TaskListView : public AutoAdjustingTreeView
class TaskListView : public QTreeView
{
Q_OBJECT
public:
TaskListView(QWidget* parent = nullptr);
void dropEvent(QDropEvent* event) override;
void setModel(QAbstractItemModel* model) override;
void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight,
const QVector<int>& roles = QVector<int>()) override;
protected:
void updateColumnWidth();
};
class SolutionListView : public QTreeView
{
Q_OBJECT
public:
SolutionListView(QWidget* parent = nullptr);
void setModel(QAbstractItemModel* model) override;
void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight,
const QVector<int>& roles = QVector<int>()) override;
void resizeEvent(QResizeEvent* event) override;
protected:
void updateColumnWidth();
};
} // namespace moveit_rviz_plugin

View File

@ -234,11 +234,11 @@ TaskViewPrivate::TaskViewPrivate(TaskView* q_ptr) : q_ptr(q_ptr), exec_action_cl
tasks_view->setDropIndicatorShown(true);
tasks_view->setDragEnabled(true);
solutions_view->setAutoHideSections({ 1, 2 });
solutions_view->setStretchSection(2);
actionShowTimeColumn->setChecked(true);
// init actions
tasks_view->addActions({ actionAddLocalTask, actionRemoveTaskTreeRows });
// TODO(v4hn): add actionAddLocalTask once there is something meaningful to add
tasks_view->addActions({ /*actionAddLocalTask,*/ actionRemoveTaskTreeRows, actionShowTimeColumn });
}
std::pair<TaskListModel*, TaskDisplay*> TaskViewPrivate::getTaskListModel(const QModelIndex& index) const {
@ -263,9 +263,13 @@ TaskView::TaskView(moveit_rviz_plugin::TaskPanel* parent, rviz::Property* root)
: SubPanel(parent), d_ptr(new TaskViewPrivate(this)) {
Q_D(TaskView);
d_ptr->tasks_property_splitter->setStretchFactor(0, 3);
d_ptr->tasks_property_splitter->setStretchFactor(1, 1);
// connect signals
connect(d->actionRemoveTaskTreeRows, SIGNAL(triggered()), this, SLOT(removeSelectedStages()));
connect(d->actionAddLocalTask, SIGNAL(triggered()), this, SLOT(addTask()));
connect(d->actionShowTimeColumn, &QAction::triggered, [this](bool checked) { show_time_column->setValue(checked); });
connect(d->tasks_view->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this,
SLOT(onCurrentStageChanged(QModelIndex, QModelIndex)));
@ -287,6 +291,9 @@ TaskView::TaskView(moveit_rviz_plugin::TaskPanel* parent, rviz::Property* root)
initial_task_expand->addOption("Top-level Expanded", EXPAND_TOP);
initial_task_expand->addOption("All Expanded", EXPAND_ALL);
initial_task_expand->addOption("All Closed", EXPAND_NONE);
show_time_column = new rviz::BoolProperty("Show Computation Times", true, "Show the 'time' column", configs);
connect(show_time_column, SIGNAL(changed()), this, SLOT(onShowTimeChanged()));
}
TaskView::~TaskView() {
@ -304,15 +311,15 @@ void TaskView::save(rviz::Config config) {
write_splitter_sizes(d_ptr->tasks_property_splitter, "property_splitter");
write_splitter_sizes(d_ptr->tasks_solutions_splitter, "solutions_splitter");
auto write_column_sizes = [&config](QTreeView* view, const QString& key) {
auto write_column_sizes = [&config](QHeaderView* view, const QString& key) {
rviz::Config group = config.mapMakeChild(key);
for (int c = 0, end = view->header()->count(); c != end; ++c) {
for (int c = 0, end = view->count(); c != end; ++c) {
rviz::Config item = group.listAppendNew();
item.setValue(view->columnWidth(c));
item.setValue(view->sectionSize(c));
}
};
write_column_sizes(d_ptr->tasks_view, "tasks_view_columns");
write_column_sizes(d_ptr->solutions_view, "solutions_view_columns");
write_column_sizes(d_ptr->tasks_view->header(), "tasks_view_columns");
write_column_sizes(d_ptr->solutions_view->header(), "solutions_view_columns");
const QHeaderView* view = d_ptr->solutions_view->header();
rviz::Config group = config.mapMakeChild("solution_sorting");
@ -413,10 +420,10 @@ void TaskView::onCurrentStageChanged(const QModelIndex& current, const QModelInd
}
// update the PropertyModel
view = d_ptr->property_view;
sm = view->selectionModel();
QTreeView* pview = d_ptr->property_view;
sm = pview->selectionModel();
m = task ? task->getPropertyModel(task_index) : nullptr;
view->setModel(m);
pview->setModel(m);
delete sm; // we don't store the selection model
}
@ -474,6 +481,14 @@ void TaskView::onExecCurrentSolution() const {
d_ptr->exec_action_client_.sendGoal(goal);
}
void TaskView::onShowTimeChanged() {
auto* header = d_ptr->tasks_view->header();
bool show = show_time_column->getBool();
if (header->count() > 3)
d_ptr->tasks_view->header()->setSectionHidden(3, !show);
d_ptr->actionShowTimeColumn->setChecked(show);
}
GlobalSettingsWidgetPrivate::GlobalSettingsWidgetPrivate(GlobalSettingsWidget* q_ptr, rviz::Property* root)
: q_ptr(q_ptr) {
setupUi(q_ptr);
@ -484,6 +499,8 @@ GlobalSettingsWidgetPrivate::GlobalSettingsWidgetPrivate(GlobalSettingsWidget* q
GlobalSettingsWidget::GlobalSettingsWidget(moveit_rviz_plugin::TaskPanel* parent, rviz::Property* root)
: SubPanel(parent), d_ptr(new GlobalSettingsWidgetPrivate(this, root)) {
Q_D(GlobalSettingsWidget);
d->view->expandAll();
connect(d->properties, &rviz::PropertyTreeModel::configChanged, this, &GlobalSettingsWidget::configChanged);
}

View File

@ -47,6 +47,7 @@ class QIcon;
namespace rviz {
class WindowManagerInterface;
class Property;
class BoolProperty;
class EnumProperty;
}
@ -125,6 +126,8 @@ protected:
};
rviz::EnumProperty* initial_task_expand;
rviz::BoolProperty* show_time_column;
public:
TaskView(TaskPanel* parent, rviz::Property* root);
~TaskView() override;
@ -141,6 +144,7 @@ protected Q_SLOTS:
void onCurrentSolutionChanged(const QModelIndex& current, const QModelIndex& previous);
void onSolutionSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
void onExecCurrentSolution() const;
void onShowTimeChanged();
};
class GlobalSettingsWidgetPrivate;

View File

@ -28,6 +28,9 @@
</property>
<item>
<layout class="QHBoxLayout" name="tool_buttons_layout">
<property name="topMargin">
<number>2</number>
</property>
<item>
<spacer name="spacer">
<property name="orientation">

View File

@ -31,7 +31,7 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout1">
<property name="spacing">
<number>0</number>
@ -64,11 +64,23 @@
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="indentation">
<number>15</number>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
<widget class="moveit_rviz_plugin::AutoAdjustingTreeView" name="solutions_view">
<widget class="moveit_rviz_plugin::SolutionListView" name="solutions_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>1</horstretch>
@ -78,6 +90,15 @@
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="textElideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
@ -87,15 +108,15 @@
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout2">
<property name="spacing">
<number>0</number>
@ -134,6 +155,17 @@
<string>Add task</string>
</property>
</action>
<action name="actionShowTimeColumn">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>ShowTimeColumn</string>
</property>
<property name="toolTip">
<string>show time column</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
@ -141,16 +173,16 @@
<extends>QTreeView</extends>
<header>task_list_model.h</header>
</customwidget>
<customwidget>
<class>moveit_rviz_plugin::AutoAdjustingTreeView</class>
<extends>QTreeView</extends>
<header>task_list_model.h</header>
</customwidget>
<customwidget>
<class>rviz::PropertyTreeWidget</class>
<extends>QTreeView</extends>
<header location="global">rviz/properties/property_tree_widget.h</header>
</customwidget>
<customwidget>
<class>moveit_rviz_plugin::SolutionListView</class>
<extends>QTreeView</extends>
<header>task_list_model.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>