Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insert Local Models #173

Merged
merged 50 commits into from
Aug 6, 2020
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e610b80
insert model init
Jun 1, 2020
f8ad140
Update cmakelists
Jun 1, 2020
356b0b1
Add config/sdf search
Jun 2, 2020
38fbd52
init attempt at qml listview
Jun 3, 2020
b24acec
Add grid view component
Jun 3, 2020
9f388f6
Add prototype local model ui
Jun 3, 2020
4de9ee5
Add docs and lint
Jun 3, 2020
d707e8c
Merge branch 'ign-gazebo2' into jshep1/local_models
Jun 3, 2020
4e03306
Remove unnecessary files
Jun 3, 2020
84bd069
Change some path logic
Jun 3, 2020
2fee326
add more image types
Jun 3, 2020
e98ba78
Add generalizable path logic, no thumbnail image
Jun 4, 2020
73ec648
Move test Relay to its own file
chapulina Jun 4, 2020
d09cca3
Resource env var, with transport interface
chapulina Jun 2, 2020
53f38e4
backport resources.md without changes
chapulina Jun 3, 2020
840b173
Update resources tutorial
chapulina Jun 3, 2020
f07d872
Requested changes
Jun 9, 2020
da5ff9e
style fix
Jun 9, 2020
b8e0b5e
Add logic fixes
Jun 9, 2020
47f214c
Add some qml updates
Jun 9, 2020
5770c67
Merge branch 'ign-gazebo2' into jshep1/local_models
Jun 9, 2020
d3efb89
Merge branch 'chapulina/resource_path' into jshep1/local_models
Jun 9, 2020
0719ee1
Add env var path
Jun 9, 2020
d1869fe
merged from ign-gazebo2
chapulina Jun 12, 2020
45e76f4
Also add paths for client, needs tests
chapulina Jun 14, 2020
ad8b3b5
Add path tests for the GUI
chapulina Jun 15, 2020
899d538
Merge branch 'ign-gazebo2' into chapulina/resource_path
chapulina Jun 15, 2020
f023b26
fix OSX
chapulina Jun 16, 2020
0630001
Merge branch 'ign-gazebo2' into chapulina/resource_path
chapulina Jul 1, 2020
e2979ef
subscribe to path updates
chapulina Jul 1, 2020
0fe84c4
PR feedback
chapulina Jul 8, 2020
d66efe2
Merge branch 'ign-gazebo2' into chapulina/resource_path
chapulina Jul 8, 2020
00d9235
Merge branch 'chapulina/resource_path' into jshep1/local_models
Jul 8, 2020
a086574
remove global node for now
chapulina Jul 9, 2020
40f4bfc
Merge branch 'chapulina/resource_path' into jshep1/local_models
Jul 9, 2020
7e679e9
Fix running ign gazebo, more PR feedback, more tests
chapulina Jul 11, 2020
7bdc38a
Merge branch 'chapulina/resource_path' into jshep1/local_models
Jul 11, 2020
cc84c74
Merge branch 'ign-gazebo2' into chapulina/resource_path
chapulina Jul 13, 2020
88859ab
Merge branch 'chapulina/resource_path' into jshep1/local_models
Jul 13, 2020
47a1e64
Add split view selection
Jul 14, 2020
e827c61
Add splitview window
Jul 15, 2020
f5add64
Fix dark mode text
Jul 15, 2020
956354f
Fix spelling
Jul 15, 2020
44e8f4b
Merge branch 'chapulina/resource_path' into jshep1/local_models
Jul 15, 2020
c7a3535
Fixes, I think (#245)
nkoenig Jul 15, 2020
ae84fae
Some UI tweaks to Resource Spawner (#253)
chapulina Jul 27, 2020
c6fff7f
merged from ign-gazebo2
chapulina Aug 4, 2020
7638910
fix merge
chapulina Aug 4, 2020
96e39b1
Update naming and address feedback
Aug 6, 2020
b155ec0
Merge branch 'ign-gazebo2' into jshep1/local_models
Aug 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ Server::Server(const ServerConfig &_config)

addResourcePaths();

addResourcePaths();

sdf::Errors errors;

// Load a world if specified. Check SDF string first, then SDF file
Expand Down
7 changes: 7 additions & 0 deletions src/ServerPrivate.hh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ namespace ignition
/// \return Path to the downloaded resource, empty on error.
public: std::string FetchResourceUri(const common::URI &_uri);

/// \brief Add resource paths based on latest environment variables.
/// This will update the SDF and Ignition environment variables based
/// on kResourcesPathEnv, and optionally add more paths to the list.
/// \param[in] _paths Optional paths to add.
public: void AddResourcePaths(
const std::vector<std::string> &_paths = {});

/// \brief Signal handler callback
/// \param[in] _sig The signal number
private: void OnSignal(int _sig);
Expand Down
1 change: 1 addition & 0 deletions src/gui/plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ add_subdirectory(modules)
add_subdirectory(component_inspector)
add_subdirectory(entity_tree)
add_subdirectory(grid_config)
add_subdirectory(resource_spawner)
add_subdirectory(scene3d)
add_subdirectory(shapes)
add_subdirectory(transform_control)
Expand Down
4 changes: 4 additions & 0 deletions src/gui/plugins/resource_spawner/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gz_add_gui_plugin(ResourceSpawner
SOURCES ResourceSpawner.cc
QT_HEADERS ResourceSpawner.hh
)
Binary file added src/gui/plugins/resource_spawner/NoThumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
289 changes: 289 additions & 0 deletions src/gui/plugins/resource_spawner/ResourceSpawner.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
/*
* Copyright (C) 2020 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <ignition/msgs/boolean.pb.h>
#include <ignition/msgs/stringmsg.pb.h>

#include <sdf/Root.hh>
#include <sdf/parser.hh>

#include <ignition/common/Console.hh>
#include <ignition/common/Profiler.hh>
#include <ignition/common/Filesystem.hh>
#include <ignition/gui/Application.hh>
#include <ignition/gui/MainWindow.hh>
#include <ignition/plugin/Register.hh>
#include <ignition/transport/Node.hh>
#include <ignition/transport/Publisher.hh>

#include "ignition/gazebo/EntityComponentManager.hh"
#include "ignition/gazebo/gui/GuiEvents.hh"

#include "ResourceSpawner.hh"

namespace ignition::gazebo
{
class ResourceSpawnerPrivate
{
/// \brief Ignition communication node.
public: transport::Node node;

/// \brief The grid model that the qml gridview reflects
public: GridModel gridModel;

/// \brief The path list model that the qml treeview reflects
public: PathModel pathModel;
};
}

using namespace ignition;
using namespace gazebo;

/////////////////////////////////////////////////
PathModel::PathModel() : QStandardItemModel()
{
}

/////////////////////////////////////////////////
void PathModel::AddPath(const std::string &_path)
{
IGN_PROFILE_THREAD_NAME("Qt thread");
IGN_PROFILE("PathModel::AddPath");
QStandardItem *parentItem{nullptr};

parentItem = this->invisibleRootItem();

auto localModel = new QStandardItem(QString::fromStdString(_path));
localModel->setData(QString::fromStdString(_path),
this->roleNames().key("path"));

parentItem->appendRow(localModel);
}

/////////////////////////////////////////////////
QHash<int, QByteArray> PathModel::roleNames() const
{
return
{
std::pair(100, "path"),
};
}

/////////////////////////////////////////////////
GridModel::GridModel() : QStandardItemModel()
{
}

/////////////////////////////////////////////////
void GridModel::Clear()
{
QStandardItem *parentItem{nullptr};
parentItem = this->invisibleRootItem();

while (parentItem->rowCount() > 0)
{
parentItem->removeRow(0);
}
}

/////////////////////////////////////////////////
void GridModel::AddLocalModel(LocalModel &_model)
{
IGN_PROFILE_THREAD_NAME("Qt thread");
IGN_PROFILE("GridModel::AddLocalModel");
QStandardItem *parentItem{nullptr};

parentItem = this->invisibleRootItem();

auto localModel = new QStandardItem(QString::fromStdString(_model.name));
localModel->setData(QString::fromStdString(_model.thumbnailPath),
this->roleNames().key("thumbnail"));
localModel->setData(QString::fromStdString(_model.name),
this->roleNames().key("name"));
localModel->setData(QString::fromStdString(_model.sdfPath),
this->roleNames().key("sdf"));

parentItem->appendRow(localModel);
}

/////////////////////////////////////////////////
QHash<int, QByteArray> GridModel::roleNames() const
{
return
{
std::pair(100, "thumbnail"),
std::pair(101, "name"),
std::pair(102, "sdf"),
};
}

/////////////////////////////////////////////////
ResourceSpawner::ResourceSpawner()
: ignition::gui::Plugin(),
dataPtr(std::make_unique<ResourceSpawnerPrivate>())
{
ignition::gui::App()->Engine()->rootContext()->setContextProperty(
"LocalModelList", &this->dataPtr->gridModel);
ignition::gui::App()->Engine()->rootContext()->setContextProperty(
"PathList", &this->dataPtr->pathModel);
}

/////////////////////////////////////////////////
ResourceSpawner::~ResourceSpawner() = default;

/////////////////////////////////////////////////
void ResourceSpawner::LoadLocalModel(const std::string &_path)
{
std::string fileName = common::basename(_path);
if (!common::isFile(_path) || fileName != "model.config")
return;

// If we have found model.config, extract thumbnail and sdf
LocalModel model;
std::string modelPath = common::parentPath(_path);
std::string thumbnailPath = common::joinPaths(modelPath, "thumbnails");
std::string configFileName = common::joinPaths(modelPath, "model.config");
tinyxml2::XMLDocument doc;
doc.LoadFile(configFileName.c_str());
auto modelXml = doc.FirstChildElement("model");

if (modelXml)
{
auto modelName = modelXml->FirstChildElement("name");
if (modelName)
model.name = modelName->GetText();
}
std::string sdfPath = sdf::getModelFilePath(modelPath);
model.sdfPath = sdfPath;

// Get first thumbnail image found
if (common::exists(thumbnailPath))
{
for (common::DirIter file(thumbnailPath);
file != common::DirIter(); ++file)
{
std::string current(*file);
if (common::isFile(current))
{
std::string thumbnailFileName = common::basename(current);
std::string::size_type thumbnailExtensionIndex =
thumbnailFileName.rfind(".");
std::string thumbnailFileExtension =
thumbnailFileName.substr(thumbnailExtensionIndex + 1);
// The standard image types QML supports
if (thumbnailFileExtension == "png" ||
thumbnailFileExtension == "jpg" ||
thumbnailFileExtension == "jpeg" ||
thumbnailFileExtension == "svg")
{
model.thumbnailPath = current;
break;
}
}
}
}
this->dataPtr->gridModel.AddLocalModel(model);
}

/////////////////////////////////////////////////
void ResourceSpawner::FindLocalModels(const std::string &_path)
{
std::string path = _path;
if (common::isDirectory(path))
{
for (common::DirIter file(path); file != common::DirIter(); ++file)
{
std::string currentPath(*file);
if (common::isDirectory(currentPath))
{
std::string modelConfigPath =
common::joinPaths(currentPath, "model.config");
this->LoadLocalModel(modelConfigPath);
}
else
{
this->LoadLocalModel(currentPath);
}
}
}
else
{
this->LoadLocalModel(path);
}
}

/////////////////////////////////////////////////
void ResourceSpawner::AddPath(const std::string &_path)
{
this->dataPtr->pathModel.AddPath(_path);
}

/////////////////////////////////////////////////
void ResourceSpawner::OnPathClicked(const QString &_path)
{
this->dataPtr->gridModel.Clear();
this->FindLocalModels(_path.toStdString());
}

/////////////////////////////////////////////////
void ResourceSpawner::LoadConfig(const tinyxml2::XMLElement *)
{
if (this->title.empty())
this->title = "Resource Spawner";

// For resource spawn requests
ignition::gui::App()->findChild
<ignition::gui::MainWindow *>()->installEventFilter(this);
JShep1 marked this conversation as resolved.
Show resolved Hide resolved

msgs::StringMsg_V res;
bool result;
bool executed = this->dataPtr->node.Request(
"/gazebo/resource_paths/get", 5000, res, result);
if (!executed || !result || res.data_size() < 1)
{
ignwarn << "No paths found in IGN_GAZEBO_RESOURCE_PATH.\n";
return;
}

for (int i = 0; i < res.data_size(); i++)
{
const std::string path = res.data(i);
this->AddPath(path);
}
}

/////////////////////////////////////////////////
void ResourceSpawner::OnResourceSpawn(const QString &_sdfPath)
{
std::string modelSdfPath = _sdfPath.toStdString();

// Parse the sdf from the path
std::ifstream nameFileout;
nameFileout.open(modelSdfPath);
std::string line;
std::string modelSdfString = "";
while (std::getline(nameFileout, line))
modelSdfString += line + "\n";

auto event = new gui::events::SpawnPreviewModel(modelSdfString);
ignition::gui::App()->sendEvent(
ignition::gui::App()->findChild<ignition::gui::MainWindow *>(),
event);
}

// Register this plugin
IGNITION_ADD_PLUGIN(ignition::gazebo::ResourceSpawner,
ignition::gui::Plugin)
Loading