Fix (again) creation of TaskPanel

This commit is contained in:
Robert Haschke 2020-10-29 21:16:14 +01:00
parent f7ea72010b
commit ef9c7612a9
4 changed files with 41 additions and 10 deletions

View File

@ -59,7 +59,7 @@
namespace moveit_rviz_plugin {
TaskDisplay::TaskDisplay() : Display(), received_task_description_(false) {
TaskDisplay::TaskDisplay() : Display(), panel_requested_(false), received_task_description_(false) {
task_list_model_.reset(new TaskListModel);
MetaTaskListModel::instance().insertModel(task_list_model_.get(), this);
@ -88,17 +88,24 @@ TaskDisplay::TaskDisplay() : Display(), received_task_description_(false) {
}
TaskDisplay::~TaskDisplay() {
if (context_)
TaskPanel::decDisplayCount();
if (panel_requested_)
TaskPanel::release(); // Indicate that we don't need a TaskPanel anymore
}
void TaskDisplay::onInitialize() {
Display::onInitialize();
trajectory_visual_->onInitialize(scene_node_, context_);
task_list_model_->setDisplayContext(context_);
// create a new TaskPanel by default
// by post-poning this to Qt's GUI loop, we can ensure that rviz has loaded everything before
QTimer::singleShot(0, [this]() { TaskPanel::incDisplayCount(context_->getWindowManager()); });
}
inline void TaskDisplay::requestPanel() {
if (panel_requested_)
return; // already done
// Create a new TaskPanel if not yet done.
// This cannot be done in initialize(), because Panel loading follows Display loading in rviz.
panel_requested_ = true;
TaskPanel::request(context_->getWindowManager());
}
void TaskDisplay::loadRobotModel() {
@ -170,6 +177,7 @@ void TaskDisplay::calculateOffsetPosition() {
}
void TaskDisplay::update(float wall_dt, float ros_dt) {
requestPanel();
Display::update(wall_dt, ros_dt);
trajectory_visual_->update(wall_dt, ros_dt);
}
@ -188,6 +196,7 @@ void TaskDisplay::changedRobotDescription() {
void TaskDisplay::taskDescriptionCB(const moveit_task_constructor_msgs::TaskDescriptionConstPtr& msg) {
setStatus(rviz::StatusProperty::Ok, "Task Monitor", "OK");
requestPanel();
task_list_model_->processTaskDescriptionMessage(*msg, update_nh_,
base_ns_ + GET_SOLUTION_SERVICE "_" + msg->task_id);

View File

@ -100,6 +100,9 @@ protected:
void fixedFrameChanged() override;
void calculateOffsetPosition();
private:
inline void requestPanel();
private Q_SLOTS:
/**
* \brief Slot Event Functions
@ -123,6 +126,7 @@ protected:
std::unique_ptr<TaskSolutionVisualization> trajectory_visual_;
// The TaskListModel storing actual task and solution data
std::unique_ptr<TaskListModel> task_list_model_;
bool panel_requested_;
// Load robot model
rdf_loader::RDFLoaderPtr rdf_loader_;

View File

@ -130,7 +130,25 @@ void TaskPanel::addSubPanel(SubPanel* w, const QString& title, const QIcon& icon
connect(w, SIGNAL(configChanged()), this, SIGNAL(configChanged()));
}
void TaskPanel::incDisplayCount(rviz::WindowManagerInterface* window_manager) {
/* Realizing a singleton Panel is a nightmare with rviz...
* Formally, Panels (as a plugin class) cannot be singleton, because new instances are created on demand.
* Hence, we decided to use a true singleton for the underlying model only and a fake singleton for the panel.
* Thus, all panels (in case multiple were created) show the same content.
* The fake singleton shall ensure that only a single panel is created, even if several displays are created.
* To this end, the displays request() the need for a panel during their initialization and they release()
* this need during their destruction. This, in principle, allows to create a panel together with the first
* display and destroy it when the last display is gone.
* Obviously, the user can still decide to explicitly delete the panel (or create new ones).
* The nightmare arises from the order of loading of displays and panels: Displays are loaded first.
* However, directly creating a panel with the first loaded display doesn't work, because panel loading
* will create another panel instance later (because there is no singleton support).
* Hence, we need to postpone the actual panel creation from displays until panel loading is finished as well.
* This was initially done, by postponing panel creation to TaskDisplay::update(). However, update()
* will never be called if the display is disabled...
*/
void TaskPanel::request(rviz::WindowManagerInterface* window_manager) {
++DISPLAY_COUNT;
rviz::VisualizationFrame* vis_frame = dynamic_cast<rviz::VisualizationFrame*>(window_manager);
@ -143,7 +161,7 @@ void TaskPanel::incDisplayCount(rviz::WindowManagerInterface* window_manager) {
assert(dock->widget() == SINGLETON);
}
void TaskPanel::decDisplayCount() {
void TaskPanel::release() {
Q_ASSERT(DISPLAY_COUNT > 0);
if (--DISPLAY_COUNT == 0 && SINGLETON)
SINGLETON->deleteLater();

View File

@ -91,8 +91,8 @@ public:
* If not yet done, an instance is created. If use count drops to zero,
* the global instance is destroyed.
*/
static void incDisplayCount(rviz::WindowManagerInterface* window_manager);
static void decDisplayCount();
static void request(rviz::WindowManagerInterface* window_manager);
static void release();
void onInitialize() override;
void load(const rviz::Config& config) override;