diff --git a/mapviz/include/mapviz/config_item.h b/mapviz/include/mapviz/config_item.h index e40aedb80..880beff43 100644 --- a/mapviz/include/mapviz/config_item.h +++ b/mapviz/include/mapviz/config_item.h @@ -66,11 +66,13 @@ namespace mapviz Q_SIGNALS: void UpdateSizeHint(); void ToggledDraw(QListWidgetItem* plugin, bool visible); + void DuplicateRequest(QListWidgetItem* plugin); void RemoveRequest(QListWidgetItem* plugin); public Q_SLOTS: void Hide(); void EditName(); + void Duplicate(); void Remove(); void ToggleDraw(bool toggled); @@ -82,6 +84,7 @@ namespace mapviz QString name_; QString type_; QAction* edit_name_action_; + QAction* duplicate_item_action_; QAction* remove_item_action_; bool visible_; }; diff --git a/mapviz/include/mapviz/mapviz.h b/mapviz/include/mapviz/mapviz.h index d2e680724..fffa93143 100644 --- a/mapviz/include/mapviz/mapviz.h +++ b/mapviz/include/mapviz/mapviz.h @@ -92,6 +92,8 @@ namespace mapviz void SelectNewDisplay(); void RemoveDisplay(); void RemoveDisplay(QListWidgetItem* item); + void DuplicateDisplay(); + void DuplicateDisplay(QListWidgetItem *item); void ReorderDisplays(); void FixedFrameSelected(const QString& text); void TargetFrameSelected(const QString& text); diff --git a/mapviz/src/config_item.cpp b/mapviz/src/config_item.cpp index 416af3111..41b9925c8 100644 --- a/mapviz/src/config_item.cpp +++ b/mapviz/src/config_item.cpp @@ -42,10 +42,12 @@ namespace mapviz ui_.setupUi(this); edit_name_action_ = new QAction("Edit Name", this); + duplicate_item_action_ = new QAction("Duplicate", this); remove_item_action_ = new QAction("Remove", this); remove_item_action_->setIcon(QIcon(":/images/remove-icon-th.png")); connect(edit_name_action_, SIGNAL(triggered()), this, SLOT(EditName())); + connect(duplicate_item_action_, SIGNAL(triggered()), this, SLOT(Duplicate())); connect(remove_item_action_, SIGNAL(triggered()), this, SLOT(Remove())); } @@ -71,6 +73,7 @@ namespace mapviz { QMenu menu(this); menu.addAction(edit_name_action_); + menu.addAction(duplicate_item_action_); menu.addAction(remove_item_action_); menu.exec(event->globalPos()); } @@ -109,6 +112,11 @@ namespace mapviz } } + void ConfigItem::Duplicate() + { + Q_EMIT DuplicateRequest(item_); + } + void ConfigItem::Remove() { Q_EMIT RemoveRequest(item_); diff --git a/mapviz/src/mapviz.cpp b/mapviz/src/mapviz.cpp index 6adf8094a..595fdfca5 100644 --- a/mapviz/src/mapviz.cpp +++ b/mapviz/src/mapviz.cpp @@ -1188,6 +1188,7 @@ MapvizPluginPtr Mapviz::CreateNewDisplay( item->setSizeHint(config_item->sizeHint()); connect(config_item, SIGNAL(UpdateSizeHint()), this, SLOT(UpdateSizeHints())); connect(config_item, SIGNAL(ToggledDraw(QListWidgetItem*, bool)), this, SLOT(ToggleShowPlugin(QListWidgetItem*, bool))); + connect(config_item, SIGNAL(DuplicateRequest(QListWidgetItem*)), this, SLOT(DuplicateDisplay(QListWidgetItem*))); connect(config_item, SIGNAL(RemoveRequest(QListWidgetItem*)), this, SLOT(RemoveDisplay(QListWidgetItem*))); connect(plugin.get(), SIGNAL(VisibleChanged(bool)), config_item, SLOT(ToggleDraw(bool))); connect(plugin.get(), SIGNAL(SizeChanged()), this, SLOT(UpdateSizeHints())); @@ -1499,6 +1500,66 @@ void Mapviz::RemoveDisplay(QListWidgetItem* item) } } +void Mapviz::DuplicateDisplay() +{ + QListWidgetItem* item = ui_.configs->item(ui_.configs->currentRow()); + if (item != nullptr) + { + DuplicateDisplay(item); + } +} + +void Mapviz::DuplicateDisplay(QListWidgetItem* item) +{ + ROS_INFO("Duplicating active display... "); + // - Get plugin associated with QListWidgetItem + if (plugins_.count(item) != 1) + { + ROS_ERROR("Item attempted to duplicate is not a plugin."); + return; + } + MapvizPluginPtr target_plugin = plugins_[item]; + ConfigItem* target_config_item = static_cast(ui_.configs->itemWidget(item)); + + // - Save plugin config to a temporary string via an emitter + YAML::Emitter out; + out << YAML::BeginMap; + out << YAML::Key << "type" << YAML::Value << target_plugin->Type(); + out << YAML::Key << "name" << YAML::Value << target_config_item->Name().toStdString(); + out << YAML::Key << "config" << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "visible" << YAML::Value << target_plugin->Visible(); + out << YAML::Key << "collapsed" << YAML::Value << target_config_item->Collapsed(); + target_plugin->SaveConfig(out, ""); + out << YAML::EndMap; + out << YAML::EndMap; + + // - Create the new display via existing MapvizPlugin::LoadConfig interface + YAML::Node temp_node; + swri_yaml_util::LoadString(out.c_str(), temp_node); + YAML::Node temp_config_node = temp_node["config"]; + if (!temp_config_node) + { + ROS_ERROR("Cannot duplicate plugin of type %s. Invalid config.", + target_plugin->Type().c_str()); + return; + } + try + { + MapvizPluginPtr duplicate_plugin = CreateNewDisplay( + target_config_item->Name().toStdString(), + target_plugin->Type(), + target_plugin->Visible(), + target_config_item->Collapsed()); + duplicate_plugin->LoadConfig(temp_config_node, ""); + duplicate_plugin->DrawIcon(); + } + catch (const pluginlib::LibraryLoadException& e) + { + ROS_ERROR("%s", e.what()); + } +} + void Mapviz::ClearDisplays() { while (ui_.configs->count() > 0)