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

notify other GUI plugins of added/removed entities via GUI events #1138

Merged
merged 5 commits into from
Oct 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 36 additions & 0 deletions include/ignition/gazebo/gui/GuiEvents.hh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define IGNITION_GAZEBO_GUI_GUIEVENTS_HH_

#include <QEvent>
#include <set>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -99,6 +100,41 @@ namespace events
private: bool fromUser{false};
};

/// \brief Event that contains newly created and removed entities
class AddedRemovedEntities : public QEvent
{
/// \brief Constructor
/// \param[in] _newEntities Set of newly created entities
/// \param[in] _removedEntities Set of recently removed entities
public: AddedRemovedEntities(const std::set<Entity> &_newEntities,
const std::set<Entity> &_removedEntities)
: QEvent(kType), newEntities(_newEntities),
removedEntities(_removedEntities)
{
}

/// \brief Get the set of newly created entities
public: const std::set<Entity> &NewEntities() const
{
return this->newEntities;
}

/// \brief Get the set of recently removed entities
public: const std::set<Entity> &RemovedEntities() const
{
return this->removedEntities;
}

/// \brief Unique type for this event.
static const QEvent::Type kType = QEvent::Type(QEvent::User + 3);

/// \brief Set of newly created entities
private: std::set<Entity> newEntities;

/// \brief Set of recently removed entities
private: std::set<Entity> removedEntities;
};

/// \brief True if a transform control is currently active (translate /
/// rotate / scale). False if we're in selection mode.
class TransformControlModeActive : public QEvent
Expand Down
99 changes: 88 additions & 11 deletions src/gui/plugins/entity_tree/EntityTree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "EntityTree.hh"

#include <iostream>
#include <mutex>
#include <set>
#include <vector>

#include <ignition/common/Console.hh>
Expand Down Expand Up @@ -54,6 +56,16 @@ namespace ignition::gazebo

/// \brief World entity
public: Entity worldEntity{kNullEntity};

/// \brief List of new entities from a gui event
public: std::set<Entity> newEntities;

/// \brief List of removed entities from a gui event
public: std::set<Entity> removedEntities;

/// \brief Mutex to protect gui event and system upate call race conditions
/// for newEntities and removedEntities
public: std::mutex newRemovedEntityMutex;
};
}

Expand Down Expand Up @@ -100,11 +112,12 @@ QString entityType(Entity _entity,
/////////////////////////////////////////////////
TreeModel::TreeModel() : QStandardItemModel()
{
qRegisterMetaType<Entity>("Entity");
}

/////////////////////////////////////////////////
void TreeModel::AddEntity(unsigned int _entity, const QString &_entityName,
unsigned int _parentEntity, const QString &_type)
void TreeModel::AddEntity(Entity _entity, const QString &_entityName,
Entity _parentEntity, const QString &_type)
{
IGN_PROFILE_THREAD_NAME("Qt thread");
IGN_PROFILE("TreeModel::AddEntity");
Expand Down Expand Up @@ -165,7 +178,7 @@ void TreeModel::AddEntity(unsigned int _entity, const QString &_entityName,
}

/////////////////////////////////////////////////
void TreeModel::RemoveEntity(unsigned int _entity)
void TreeModel::RemoveEntity(Entity _entity)
{
IGN_PROFILE("TreeModel::RemoveEntity");
QStandardItem *item{nullptr};
Expand Down Expand Up @@ -247,7 +260,7 @@ QString TreeModel::ScopedName(const QModelIndex &_index) const
}

/////////////////////////////////////////////////
unsigned int TreeModel::EntityId(const QModelIndex &_index) const
Entity TreeModel::EntityId(const QModelIndex &_index) const
{
Entity entity{kNullEntity};
QStandardItem *item = this->itemFromIndex(_index);
Expand Down Expand Up @@ -329,9 +342,9 @@ void EntityTree::Update(const UpdateInfo &, EntityComponentManager &_ecm)

QMetaObject::invokeMethod(&this->dataPtr->treeModel, "AddEntity",
Qt::QueuedConnection,
Q_ARG(unsigned int, _entity),
Q_ARG(Entity, _entity),
Q_ARG(QString, QString::fromStdString(_name->Data())),
Q_ARG(unsigned int, parentEntity),
Q_ARG(Entity, parentEntity),
Q_ARG(QString, entityType(_entity, _ecm)));
return true;
});
Expand Down Expand Up @@ -359,9 +372,9 @@ void EntityTree::Update(const UpdateInfo &, EntityComponentManager &_ecm)

QMetaObject::invokeMethod(&this->dataPtr->treeModel, "AddEntity",
Qt::QueuedConnection,
Q_ARG(unsigned int, _entity),
Q_ARG(Entity, _entity),
Q_ARG(QString, QString::fromStdString(_name->Data())),
Q_ARG(unsigned int, parentEntity),
Q_ARG(Entity, parentEntity),
Q_ARG(QString, entityType(_entity, _ecm)));
return true;
});
Expand All @@ -373,13 +386,62 @@ void EntityTree::Update(const UpdateInfo &, EntityComponentManager &_ecm)
{
QMetaObject::invokeMethod(&this->dataPtr->treeModel, "RemoveEntity",
Qt::QueuedConnection,
Q_ARG(unsigned int, _entity));
Q_ARG(Entity, _entity));
return true;
});

{
// update the entity tree with new/removed entities from gui events
std::lock_guard<std::mutex> lock(this->dataPtr->newRemovedEntityMutex);

for (auto entity : this->dataPtr->newEntities)
{
// make sure the entity to be added has a name and parent
auto nameComp = _ecm.Component<components::Name>(entity);
if (!nameComp)
{
ignerr << "Could not add entity [" << entity << "] to the entity tree "
<< "because it does not have a name component.\n";
continue;
}
auto parentComp = _ecm.Component<components::ParentEntity>(entity);
if (!parentComp)
{
ignerr << "Could not add entity [" << entity << "] to the entity tree "
<< "because it does not have a parent entity component.\n";
continue;
}

// World children are top-level
auto parentEntity = parentComp->Data();
if (this->dataPtr->worldEntity != kNullEntity &&
parentEntity == this->dataPtr->worldEntity)
{
parentEntity = kNullEntity;
}

QMetaObject::invokeMethod(&this->dataPtr->treeModel, "AddEntity",
Qt::QueuedConnection,
Q_ARG(Entity, entity),
Q_ARG(QString, QString::fromStdString(nameComp->Data())),
Q_ARG(Entity, parentEntity),
Q_ARG(QString, entityType(entity, _ecm)));
}

for (auto entity : this->dataPtr->removedEntities)
{
QMetaObject::invokeMethod(&this->dataPtr->treeModel, "RemoveEntity",
Qt::QueuedConnection,
Q_ARG(Entity, entity));
}

this->dataPtr->newEntities.clear();
this->dataPtr->removedEntities.clear();
}
}

/////////////////////////////////////////////////
void EntityTree::OnEntitySelectedFromQml(unsigned int _entity)
void EntityTree::OnEntitySelectedFromQml(Entity _entity)
{
std::vector<Entity> entitySet {_entity};
gui::events::EntitiesSelected event(entitySet, true);
Expand Down Expand Up @@ -413,7 +475,7 @@ bool EntityTree::eventFilter(QObject *_obj, QEvent *_event)

QMetaObject::invokeMethod(this->PluginItem(), "onEntitySelectedFromCpp",
Qt::QueuedConnection, Q_ARG(QVariant,
QVariant(static_cast<unsigned int>(entity))));
QVariant(static_cast<qulonglong>(entity))));
}
}
}
Expand All @@ -428,6 +490,21 @@ bool EntityTree::eventFilter(QObject *_obj, QEvent *_event)
Qt::QueuedConnection);
}
}
else if (_event->type() ==
ignition::gazebo::gui::events::AddedRemovedEntities::kType)
{
std::lock_guard<std::mutex> lock(this->dataPtr->newRemovedEntityMutex);
auto addedRemovedEvent =
reinterpret_cast<gui::events::AddedRemovedEntities *>(_event);
if (addedRemovedEvent)
{
for (auto entity : addedRemovedEvent->NewEntities())
this->dataPtr->newEntities.insert(entity);

for (auto entity : addedRemovedEvent->RemovedEntities())
this->dataPtr->removedEntities.insert(entity);
}
}

// Standard event processing
return QObject::eventFilter(_obj, _event);
Expand Down
15 changes: 8 additions & 7 deletions src/gui/plugins/entity_tree/EntityTree.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <memory>
#include <vector>

#include <ignition/gazebo/Entity.hh>
#include <ignition/gazebo/gui/GuiSystem.hh>

namespace ignition
Expand Down Expand Up @@ -50,14 +51,14 @@ namespace gazebo
/// \param[in] _parentEntity Parent entity. By default, kNullEntity, which
/// means it's a root entity.
/// \param[in] _type Entity type
public slots: void AddEntity(unsigned int _entity,
public slots: void AddEntity(Entity _entity,
const QString &_entityName,
unsigned int _parentEntity = kNullEntity,
Entity _parentEntity = kNullEntity,
const QString &_type = QString());

/// \brief Remove an entity from the tree.
/// \param[in] _entity Entity to be removed
public slots: void RemoveEntity(unsigned int _entity);
public slots: void RemoveEntity(Entity _entity);

/// \brief Get the entity type of a tree item at specified index
/// \param[in] _index Model index
Expand All @@ -72,7 +73,7 @@ namespace gazebo
/// \brief Get the entity ID of a tree item at specified index
/// \param[in] _index Model index
/// \return Entity ID
public: Q_INVOKABLE unsigned int EntityId(const QModelIndex &_index) const;
public: Q_INVOKABLE Entity EntityId(const QModelIndex &_index) const;

/// \brief Keep track of which item corresponds to which entity.
private: std::map<Entity, QStandardItem *> entityItems;
Expand All @@ -82,14 +83,14 @@ namespace gazebo
{
/// \brief Entity ID
// cppcheck-suppress unusedStructMember
unsigned int entity;
Entity entity;

/// \brief Entity name
QString name;

/// \brief Parent ID
// cppcheck-suppress unusedStructMember
unsigned int parentEntity;
Entity parentEntity;

/// \brief Entity type
QString type;
Expand Down Expand Up @@ -123,7 +124,7 @@ namespace gazebo
/// \brief Callback when an entity has been selected. This should be
/// called from QML.
/// \param[in] _entity Entity being selected.
public: Q_INVOKABLE void OnEntitySelectedFromQml(unsigned int _entity);
public: Q_INVOKABLE void OnEntitySelectedFromQml(Entity _entity);

/// \brief Callback when all entities have been deselected.
/// This should be called from QML.
Expand Down