/* * Copyright (C) 2012 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 #include #include "gazebo/math/Helpers.hh" #include "gazebo/msgs/msgs.hh" #include "gazebo/transport/TransportIface.hh" #include "gazebo/gui/GuiEvents.hh" #include "gazebo/gui/GuiIface.hh" #include "gazebo/gui/qtpropertybrowser/qttreepropertybrowser.h" #include "gazebo/gui/qtpropertybrowser/qtvariantproperty.h" #include "gazebo/gui/ModelListWidget.hh" #include "gazebo/gui/ModelListWidget_TEST.hh" #include "test_config.h" ///////////////////////////////////////////////// void ModelListWidget_TEST::TreeWidget() { QBENCHMARK { this->Load("worlds/empty.world"); gazebo::gui::ModelListWidget *modelListWidget = new gazebo::gui::ModelListWidget; QCoreApplication::processEvents(); // Get tree widget QTreeWidget *modelTreeWidget = modelListWidget->findChild( "modelTreeWidget"); QVERIFY(modelTreeWidget != NULL); QList treeSceneItems = modelTreeWidget->findItems(tr("Scene"), Qt::MatchExactly); QCOMPARE(treeSceneItems.size(), 1); QList treePhysicsItems = modelTreeWidget->findItems(tr("Physics"), Qt::MatchExactly); QCOMPARE(treePhysicsItems.size(), 1); QList treeLightItems = modelTreeWidget->findItems(tr("Lights"), Qt::MatchExactly); QCOMPARE(treeLightItems.size(), 1); QList treeModelItems = modelTreeWidget->findItems(tr("Models"), Qt::MatchExactly); QCOMPARE(treeModelItems.size(), 1); QTreeWidgetItem *modelsItem = treeModelItems.front(); QVERIFY(modelsItem != NULL); delete modelListWidget; } } ///////////////////////////////////////////////// void ModelListWidget_TEST::OnResponse(ConstResponsePtr &_msg) { gazebo::msgs::Model_V modelVMsg; if (_msg->has_type() && _msg->type() == modelVMsg.GetTypeName()) { modelVMsg.ParseFromString(_msg->serialized_data()); for (int i = 0; i < modelVMsg.models_size(); i++) { gazebo::gui::Events::modelUpdate(modelVMsg.models(i)); } } } ///////////////////////////////////////////////// void ModelListWidget_TEST::CheckVector3Property(QList _properties, const ignition::math::Vector3d &_xyz) { QVERIFY(_properties.size() >= 3); for (unsigned char c = 0; c < 3; ++c) { QtVariantProperty *property = static_cast(_properties[c]); Q_ASSERT(property); std::string name(1, 'x' + c); QCOMPARE(property->propertyName(), tr(name.c_str())); QCOMPARE(property->value().toDouble(), _xyz[c]); } } ///////////////////////////////////////////////// void ModelListWidget_TEST::CheckPoseProperty(QList _properties, const gazebo::math::Pose &_pose) { QCOMPARE(_properties.size(), 6); this->CheckVector3Property(_properties, _pose.pos.Ign()); QtVariantProperty *property; property = static_cast(_properties[3]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("roll")); QCOMPARE(property->value().toDouble(), _pose.rot.GetAsEuler().x); property = static_cast(_properties[4]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("pitch")); QCOMPARE(property->value().toDouble(), _pose.rot.GetAsEuler().y); property = static_cast(_properties[5]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("yaw")); QCOMPARE(property->value().toDouble(), _pose.rot.GetAsEuler().z); } ///////////////////////////////////////////////// void ModelListWidget_TEST::SetVector3Property( QtTreePropertyBrowser *_propTreeBrowser, QList _properties, const ignition::math::Vector3d &_xyz) { QVERIFY(_properties.size() >= 3); for (unsigned char c = 0; c < 3; ++c) { QtVariantProperty *property = static_cast(_properties[c]); Q_ASSERT(property); std::string name(1, 'x' + c); QCOMPARE(property->propertyName(), tr(name.c_str())); QVERIFY(_propTreeBrowser->items(property).size() == 1); _propTreeBrowser->setCurrentItem(_propTreeBrowser->items(property)[0]); property->setValue(_xyz[c]); } QTest::qWait(500); } ///////////////////////////////////////////////// void ModelListWidget_TEST::SetPoseProperty( QtTreePropertyBrowser *_propTreeBrowser, QList _properties, const gazebo::math::Pose &_pose) { QCOMPARE(_properties.size(), 6); this->SetVector3Property(_propTreeBrowser, _properties, _pose.pos.Ign()); QtVariantProperty *property; property = static_cast(_properties[3]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("roll")); QVERIFY(_propTreeBrowser->items(property).size() == 1); _propTreeBrowser->setCurrentItem(_propTreeBrowser->items(property)[0]); property->setValue(_pose.rot.GetAsEuler().x); property = static_cast(_properties[4]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("pitch")); QVERIFY(_propTreeBrowser->items(property).size() == 1); _propTreeBrowser->setCurrentItem(_propTreeBrowser->items(property)[0]); property->setValue(_pose.rot.GetAsEuler().y); property = static_cast(_properties[5]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("yaw")); QVERIFY(_propTreeBrowser->items(property).size() == 1); _propTreeBrowser->setCurrentItem(_propTreeBrowser->items(property)[0]); property->setValue(_pose.rot.GetAsEuler().z); QTest::qWait(500); } ///////////////////////////////////////////////// void ModelListWidget_TEST::CheckLinkProperty(QList _properties, const std::string &_name, bool _selfCollide, bool _gravity, bool _kinematic, bool _canonical, const gazebo::math::Pose &_pose) { // ignore checking link id in _properties[0] QtVariantProperty *property = static_cast(_properties[1]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("name")); QCOMPARE(property->valueText(), tr(_name.c_str())); property = static_cast(_properties[2]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("self_collide")); QCOMPARE(property->value().toBool(), _selfCollide); property = static_cast(_properties[3]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("gravity")); QCOMPARE(property->value().toBool(), _gravity); property = static_cast(_properties[4]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("kinematic")); QCOMPARE(property->value().toBool(), _kinematic); property = static_cast(_properties[5]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("canonical")); QCOMPARE(property->value().toBool(), _canonical); property = static_cast(_properties[6]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("pose")); CheckPoseProperty(property->subProperties(), _pose); // pose settings for canonical links should be disabled QCOMPARE(property->isEnabled(), !_canonical); /// TODO check inertial, collision, visual properties } ///////////////////////////////////////////////// void ModelListWidget_TEST::SetLinkProperty( QtTreePropertyBrowser *propTreeBrowser, QList _properties, const std::string &_name, bool _selfCollide, bool _gravity, bool _kinematic, bool _canonical, const gazebo::math::Pose &_pose) { QtVariantProperty *property = static_cast(_properties[1]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("name")); QVERIFY(propTreeBrowser->items(property).size() == 1); propTreeBrowser->setCurrentItem(propTreeBrowser->items(property)[0]); property->setValue(tr(_name.c_str())); property = static_cast(_properties[2]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("self_collide")); QVERIFY(propTreeBrowser->items(property).size() == 1); propTreeBrowser->setCurrentItem(propTreeBrowser->items(property)[0]); property->setValue(_selfCollide); property = static_cast(_properties[3]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("gravity")); QVERIFY(propTreeBrowser->items(property).size() == 1); propTreeBrowser->setCurrentItem(propTreeBrowser->items(property)[0]); property->setValue(_gravity); property = static_cast(_properties[4]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("kinematic")); QVERIFY(propTreeBrowser->items(property).size() == 1); propTreeBrowser->setCurrentItem(propTreeBrowser->items(property)[0]); property->setValue(_kinematic); property = static_cast(_properties[5]); Q_ASSERT(property); // only set the pose for non-canonical links QCOMPARE(property->propertyName(), tr("canonical")); QCOMPARE(property->value().toBool(), _canonical); if (!property->value().toBool()) { property = static_cast(_properties[6]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("pose")); QVERIFY(propTreeBrowser->items(property).size() == 1); propTreeBrowser->setCurrentItem(propTreeBrowser->items(property)[0]); propTreeBrowser->setExpanded(propTreeBrowser->topLevelItem(property), true); this->SetPoseProperty(propTreeBrowser, property->subProperties(), _pose); } QTest::qWait(1000); /// TODO set inertial, collision, visual properties } ///////////////////////////////////////////////// void ModelListWidget_TEST::ModelsTree() { gazebo::gui::ModelListWidget *modelListWidget = new gazebo::gui::ModelListWidget; QCoreApplication::processEvents(); this->Load("worlds/shapes.world"); gazebo::transport::NodePtr node; node = gazebo::transport::NodePtr(new gazebo::transport::Node()); node->Init(); gazebo::transport::PublisherPtr requestPub = node->Advertise("~/request"); gazebo::transport::SubscriberPtr responseSub = node->Subscribe("~/response", &ModelListWidget_TEST::OnResponse, this); gazebo::msgs::Request *requestMsg = gazebo::msgs::CreateRequest("entity_list"); requestPub->Publish(*requestMsg); // Get tree widget QTreeWidget *modelTreeWidget = modelListWidget->findChild( "modelTreeWidget"); QList treeModelItems = modelTreeWidget->findItems(tr("Models"), Qt::MatchExactly); QCOMPARE(treeModelItems.size(), 1); QTreeWidgetItem *modelsItem = treeModelItems.front(); QVERIFY(modelsItem != NULL); // verify that there are 4 models, ground plane, sphere, box, and cylinder int modelCount = 4; int maxSleep = 10; int sleep = 0; while (modelsItem->childCount() < modelCount && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(sleep < maxSleep); // process more events and make sure the child count remain the same sleep = 0; maxSleep = 5; while (sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); QCOMPARE(modelsItem->childCount(), modelCount); sleep++; } // find all models in the tree QTreeWidgetItem *groundPlaneItem = NULL; QTreeWidgetItem *boxItem = NULL; QTreeWidgetItem *sphereItem = NULL; QTreeWidgetItem *cylinderItem = NULL; for (int i = 0; i < modelsItem->childCount(); ++i) { QTreeWidgetItem *item = modelsItem->child(i); if (item->text(0) == "ground_plane") groundPlaneItem = item; else if (item->text(0) == "box") boxItem = item; else if (item->text(0) == "sphere") sphereItem = item; else if (item->text(0) == "cylinder") cylinderItem = item; } // verify all models are present QVERIFY(groundPlaneItem != NULL); QVERIFY(boxItem != NULL); QVERIFY(sphereItem != NULL); QVERIFY(cylinderItem != NULL); node.reset(); delete requestMsg; delete modelListWidget; modelListWidget = NULL; } ///////////////////////////////////////////////// void ModelListWidget_TEST::ModelProperties() { gazebo::gui::ModelListWidget *modelListWidget = new gazebo::gui::ModelListWidget; modelListWidget->show(); QCoreApplication::processEvents(); this->Load("worlds/multilink_shape.world"); gazebo::transport::NodePtr node; node = gazebo::transport::NodePtr(new gazebo::transport::Node()); node->Init(); gazebo::transport::PublisherPtr requestPub = node->Advertise("~/request"); gazebo::transport::SubscriberPtr responseSub = node->Subscribe("~/response", &ModelListWidget_TEST::OnResponse, this); gazebo::msgs::Request *requestMsg = gazebo::msgs::CreateRequest("entity_list"); requestPub->Publish(*requestMsg); // Get tree widget QTreeWidget *modelTreeWidget = modelListWidget->findChild( "modelTreeWidget"); QList treeModelItems = modelTreeWidget->findItems(tr("Models"), Qt::MatchExactly); QCOMPARE(treeModelItems.size(), 1); QTreeWidgetItem *modelsItem = treeModelItems.front(); QVERIFY(modelsItem != NULL); // verify that there is only 1 model int modelCount = 1; int maxSleep = 10; int sleep = 0; while (modelsItem->childCount() < modelCount && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(sleep < maxSleep); // Get the model item QTreeWidgetItem *modelItem = modelsItem->child(0); QVERIFY(modelItem != NULL); std::string modelName = "multilink"; QCOMPARE(modelItem->text(0), tr(modelName.c_str())); // Get propery browser widget QObject *propTreeObj = modelListWidget->findChild("propTreeBrowser"); QtTreePropertyBrowser *propTreeBrowser = dynamic_cast(propTreeObj); QVERIFY(propTreeBrowser != NULL); QCOMPARE(propTreeBrowser->properties().size(), 0); // select the models item QRect modelsRect = modelTreeWidget->visualItemRect(modelsItem); QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, modelsRect.center() ); QCoreApplication::processEvents(); // wait for the model to be selected sleep = 0; maxSleep = 5; while (!modelsItem->isSelected() && sleep < maxSleep) { QTest::qWait(10); sleep++; } QVERIFY(modelsItem->isSelected()); // select the multi-link model QRect modelRect = modelTreeWidget->visualItemRect(modelItem); QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, modelRect.center() ); QCoreApplication::processEvents(); sleep = 0; maxSleep = 5; while (!modelItem->isSelected() && sleep < maxSleep) { QTest::qWait(10); sleep++; } QVERIFY(modelItem->isSelected()); // wait for the model properties to appear sleep = 0; maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); // check the model properties bool hasName = false; bool hasStatic = false; bool hasPose = false; int numLinks = 0; int nameIndex = 1; QList modelProperties = propTreeBrowser->properties(); for (int i = 0; i < modelProperties.size(); ++i) { QtVariantProperty *property = static_cast(modelProperties[i]); if (property->propertyName() == tr("name")) { QCOMPARE(property->valueText(), tr(modelName.c_str())); hasName = true; } else if (property->propertyName() == tr("is_static")) { QCOMPARE(property->value().toBool(), false); hasStatic = true; } else if (property->propertyName() == tr("pose")) { this->CheckPoseProperty(property->subProperties(), gazebo::math::Pose(0, 0, 0.5, 0, 0, 0)); hasPose = true; } else if (property->propertyName() == tr("link")) { QVERIFY(property->subProperties().size() > 0); if (property->subProperties()[nameIndex]->valueText().toStdString(). find("box_link") != std::string::npos) { this->CheckLinkProperty(property->subProperties(), modelName + "::box_link", false, true, false, true, gazebo::math::Pose(1.0, 0, 0, 0, 0, 0)); numLinks++; } else if (property->subProperties()[nameIndex]->valueText().toStdString(). find("sphere_link") != std::string::npos) { this->CheckLinkProperty(property->subProperties(), modelName + "::sphere_link", false, true, false, false, gazebo::math::Pose(-1.5, 0, 0, 0, 0, 1.57)); numLinks++; } } } QVERIFY(hasName); QVERIFY(hasStatic); QVERIFY(hasPose); // there should be 2 links QCOMPARE(numLinks, 2); numLinks = 0; // change model properties for (int i = 0; i < modelProperties.size(); ++i) { QtVariantProperty *property = static_cast(modelProperties[i]); // TODO changing model name currently fails // if (property->propertyName() == tr("name")) // { // propTreeBrowser->setCurrentItem(propTreeBrowser->items(property)[0]); // property->setValue(true); // } if (property->propertyName() == tr("is_static")) { propTreeBrowser->setCurrentItem(propTreeBrowser->items(property)[0]); property->setValue(true); } else if (property->propertyName() == tr("pose")) { this->SetPoseProperty(propTreeBrowser, property->subProperties(), gazebo::math::Pose(0, 0, 1.0, 0, 0, 0)); } else if (property->propertyName() == tr("link")) { QVERIFY(property->subProperties().size() > 0); if (property->subProperties()[nameIndex]->valueText().toStdString(). find("box_link") != std::string::npos) { this->SetLinkProperty(propTreeBrowser, property->subProperties(), modelName + "::box_link", true, false, true, true, gazebo::math::Pose(1.5, 2.0, 3.2, 0.6, 0.7, 0.8)); numLinks++; } else if (property->subProperties()[nameIndex]->valueText().toStdString(). find("sphere_link") != std::string::npos) { this->SetLinkProperty(propTreeBrowser, property->subProperties(), modelName + "::sphere_link", true, false, true, false, gazebo::math::Pose(-2.0, 0.5, 1.0, 3.14, 0, 0)); numLinks++; } } } QCOMPARE(numLinks, 2); // select the multi-link model again to refresh the property browser QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, modelRect.center() ); QCoreApplication::processEvents(); QTest::qWait(100); sleep = 0; maxSleep = 5; while (!modelItem->isSelected() && sleep < maxSleep) { QTest::qWait(10); sleep++; } QVERIFY(modelItem->isSelected()); // wait for the model properties to appear sleep = 0; maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); numLinks = 0; // verify the model properties are sucessfully set for (int i = 0; i < modelProperties.size(); ++i) { QtVariantProperty *property = static_cast(modelProperties[i]); if (property->propertyName() == tr("is_static")) { QCOMPARE(property->value().toBool(), true); } else if (property->propertyName() == tr("pose")) { this->CheckPoseProperty(property->subProperties(), gazebo::math::Pose(0, 0, 1.0, 0, 0, 0)); } else if (property->propertyName() == tr("link")) { QVERIFY(property->subProperties().size() > 0); if (property->subProperties()[nameIndex]->valueText().toStdString(). find("box_link") != std::string::npos) { // as this is the canonical link, the pose properties should remain // unchanged this->CheckLinkProperty(property->subProperties(), modelName + "::box_link", true, false, true, true, gazebo::math::Pose(1.0, 0, 0, 0, 0, 0)); numLinks++; } else if (property->subProperties()[nameIndex]->valueText().toStdString(). find("sphere_link") != std::string::npos) { this->CheckLinkProperty(property->subProperties(), modelName + "::sphere_link", true, false, true, false, gazebo::math::Pose(-2.0, 0.5, 1.0, 3.14, 0, 0)); numLinks++; } } } QCOMPARE(numLinks, 2); modelListWidget->hide(); node.reset(); delete requestMsg; delete modelListWidget; } ///////////////////////////////////////////////// void ModelListWidget_TEST::LinkProperties() { gazebo::gui::ModelListWidget *modelListWidget = new gazebo::gui::ModelListWidget; modelListWidget->show(); modelListWidget->setGeometry(0, 0, 400, 800); QCoreApplication::processEvents(); this->Load("worlds/multilink_shape.world"); gazebo::transport::NodePtr node; node = gazebo::transport::NodePtr(new gazebo::transport::Node()); node->Init(); gazebo::transport::PublisherPtr requestPub = node->Advertise("~/request"); gazebo::transport::SubscriberPtr responseSub = node->Subscribe("~/response", &ModelListWidget_TEST::OnResponse, this); gazebo::msgs::Request *requestMsg = gazebo::msgs::CreateRequest("entity_list"); requestPub->Publish(*requestMsg); // Get tree widget QTreeWidget *modelTreeWidget = modelListWidget->findChild( "modelTreeWidget"); QList treeModelItems = modelTreeWidget->findItems(tr("Models"), Qt::MatchExactly); QCOMPARE(treeModelItems.size(), 1); QTreeWidgetItem *modelsItem = treeModelItems.front(); QVERIFY(modelsItem != NULL); // verify that there is only 1 model int modelCount = 1; int maxSleep = 10; int sleep = 0; while (modelsItem->childCount() < modelCount && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(sleep < maxSleep); // Get the model item QTreeWidgetItem *modelItem = modelsItem->child(0); QVERIFY(modelItem != NULL); std::string modelName = "multilink"; QCOMPARE(modelItem->text(0), tr(modelName.c_str())); // Get propery browser widget QObject *propTreeObj = modelListWidget->findChild("propTreeBrowser"); QtTreePropertyBrowser *propTreeBrowser = dynamic_cast(propTreeObj); QVERIFY(propTreeBrowser != NULL); QCOMPARE(propTreeBrowser->properties().size(), 0); // select the models item QRect modelsRect = modelTreeWidget->visualItemRect(modelsItem); QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, modelsRect.center() ); QCoreApplication::processEvents(); // wait for the models item to be selected sleep = 0; maxSleep = 5; while (!modelsItem->isSelected() && sleep < maxSleep) { QTest::qWait(10); sleep++; } QVERIFY(modelsItem->isSelected()); // select the multi-link model QRect modelRect = modelTreeWidget->visualItemRect(modelItem); QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, modelRect.center()); QCoreApplication::processEvents(); sleep = 0; maxSleep = 5; while (!modelItem->isSelected() && sleep < maxSleep) { QTest::qWait(10); sleep++; } QVERIFY(modelItem->isSelected()); // wait for the model properties to appear sleep = 0; maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); // select the box link QTreeWidgetItem *boxLinkItem = modelItem->child(0); QVERIFY(boxLinkItem != NULL); std::string boxLinkName = "box_link"; QCOMPARE(boxLinkItem->text(0), tr(boxLinkName.c_str())); QRect boxLinkRect = modelTreeWidget->visualItemRect(boxLinkItem); QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, boxLinkRect.center() ); QCoreApplication::processEvents(); sleep = 0; maxSleep = 5; while (!boxLinkItem->isSelected() && sleep < maxSleep) { QTest::qWait(10); sleep++; } QVERIFY(boxLinkItem->isSelected()); // wait for the box link properties to appear sleep = 0; maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); // check the box link properties this->CheckLinkProperty(propTreeBrowser->properties(), modelName + "::" + boxLinkName, false, true, false, true, gazebo::math::Pose(1.0, 0, 0, 0, 0, 0)); // change box link properties // TODO changing link name currently fails. this->SetLinkProperty(propTreeBrowser, propTreeBrowser->properties(), modelName + "::" + boxLinkName, true, false, true, true, gazebo::math::Pose(2.5, 1.0, 4.2, 0.8, 0.5, 0.1)); // select the box link again to refresh the property browser QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, boxLinkRect.center() ); QCoreApplication::processEvents(); QTest::qWait(100); sleep = 0; maxSleep = 5; while (!boxLinkItem->isSelected() && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(10); sleep++; } QVERIFY(boxLinkItem->isSelected()); // wait for the box link properties to appear sleep = 0; maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); // verify the link properties are sucessfully set // the link is canonical so the pose should remain the same this->CheckLinkProperty(propTreeBrowser->properties(), modelName + "::" + boxLinkName, true, false, true, true, gazebo::math::Pose(1.0, 0, 0, 0, 0, 0)); // select the sphere link QTreeWidgetItem *sphereLinkItem = modelItem->child(1); QVERIFY(sphereLinkItem != NULL); std::string sphereLinkName = "sphere_link"; QCOMPARE(sphereLinkItem->text(0), tr(sphereLinkName.c_str())); QRect sphereLinkRect = modelTreeWidget->visualItemRect(sphereLinkItem); QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, sphereLinkRect.center() ); QCoreApplication::processEvents(); QTest::qWait(100); sleep = 0; maxSleep = 5; while (!sphereLinkItem->isSelected() && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(10); sleep++; } QVERIFY(sphereLinkItem->isSelected()); // wait for the sphere link properties to appear sleep = 0; maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); // check the sphere link properties this->CheckLinkProperty(propTreeBrowser->properties(), modelName + "::" + sphereLinkName, false, true, false, false, gazebo::math::Pose(-1.5, 0, 0, 0, 0, 1.57)); // change sphere link properties // TODO changing link name currently fails. this->SetLinkProperty(propTreeBrowser, propTreeBrowser->properties(), modelName + "::" + sphereLinkName, true, false, true, false, gazebo::math::Pose(-2.0, 0.1, -1.2, 0, 1.57, 0)); // select the sphere link again to refresh the property browser QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, sphereLinkRect.center() ); QCoreApplication::processEvents(); QTest::qWait(100); sleep = 0; maxSleep = 5; while (!sphereLinkItem->isSelected() && sleep < maxSleep) { QTest::qWait(10); sleep++; } QVERIFY(sphereLinkItem->isSelected()); // wait for the sphere link properties to appear sleep = 0; maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); // verify the link properties are sucessfully set this->CheckLinkProperty(propTreeBrowser->properties(), modelName + "::" + sphereLinkName, true, false, true, false, gazebo::math::Pose(-2.0, 0.1, -1.2, 0, 1.57, 0)); modelListWidget->hide(); node.reset(); delete requestMsg; delete modelListWidget; } ///////////////////////////////////////////////// void ModelListWidget_TEST::PhysicsProperties() { std::unique_ptr modelListWidget( new gazebo::gui::ModelListWidget); modelListWidget->show(); modelListWidget->setGeometry(0, 0, 400, 800); QCoreApplication::processEvents(); this->Load("worlds/empty.world"); // Verify that property browser widget is initially empty QObject *propTreeObj = modelListWidget->findChild("propTreeBrowser"); QtTreePropertyBrowser *propTreeBrowser = dynamic_cast(propTreeObj); QVERIFY(propTreeBrowser != NULL); QCOMPARE(propTreeBrowser->properties().size(), 0); // Get the physics item from the model tree QTreeWidget *modelTreeWidget = modelListWidget->findChild( "modelTreeWidget"); QList treePhysicsItems = modelTreeWidget->findItems(tr("Physics"), Qt::MatchExactly); QCOMPARE(treePhysicsItems.size(), 1); QTreeWidgetItem *physicsItem = treePhysicsItems.front(); QVERIFY(physicsItem != NULL); // select the physics item after giving it time to be rendered QTest::qWait(10); QRect physicsRect; { physicsRect = modelTreeWidget->visualItemRect(physicsItem); QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, physicsRect.center() ); QCoreApplication::processEvents(); // wait for the physics item to be selected int sleep = 0; int maxSleep = 5; while (!physicsItem->isSelected() && sleep < maxSleep) { QTest::qWait(10); sleep++; } QVERIFY(physicsItem->isSelected()); } // wait for the physics properties to appear { int sleep = 0; int maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); } // verify that there are 8 physics properties QCOMPARE(propTreeBrowser->properties().size(), 8); // check default values of each parameter // physics engine type: ODE { auto properties = propTreeBrowser->properties(); QtVariantProperty *property = static_cast(properties[0]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("physics engine")); QCOMPARE(property->valueText(), tr("ODE")); } // physics enabled: true { auto properties = propTreeBrowser->properties(); QtVariantProperty *property = static_cast(properties[1]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("enable physics")); QCOMPARE(property->value().toBool(), true); } // real time update rate: 1000 { auto properties = propTreeBrowser->properties(); QtVariantProperty *property = static_cast(properties[2]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("real time update rate")); QCOMPARE(property->value().toDouble(), 1e3); } // max step size: 0.001 { auto properties = propTreeBrowser->properties(); QtVariantProperty *property = static_cast(properties[3]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("max step size")); QCOMPARE(property->value().toDouble(), 1e-3); } // gravity: 0 0 -9.8 { const ignition::math::Vector3d gravity(0, 0, -9.8); auto properties = propTreeBrowser->properties(); QtVariantProperty *property = static_cast(properties[4]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("gravity")); this->CheckVector3Property(property->subProperties(), gravity); // set gravity to 0 0 0 this->SetVector3Property(propTreeBrowser, property->subProperties(), ignition::math::Vector3d::Zero); } // magnetic field: 6e-6 2.3e-5 -4.2e-5 { const ignition::math::Vector3d xyz(6e-6, 2.3e-5, -4.2e-5); auto properties = propTreeBrowser->properties(); QtVariantProperty *property = static_cast(properties[5]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("magnetic field")); CheckVector3Property(property->subProperties(), xyz); } // select the box link again to refresh the property browser QTest::mouseClick(modelTreeWidget->viewport(), Qt::LeftButton, 0, physicsRect.center() ); { QCoreApplication::processEvents(); QTest::qWait(100); int sleep = 0; int maxSleep = 5; while (!physicsItem->isSelected() && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(10); sleep++; } QVERIFY(physicsItem->isSelected()); } // wait for the box link properties to appear { int sleep = 0; int maxSleep = 10; while (propTreeBrowser->properties().size() == 0 && sleep < maxSleep) { QCoreApplication::processEvents(); QTest::qWait(500); sleep++; } QVERIFY(propTreeBrowser->properties().size() > 0); } // check gravity: 0 0 0 { auto properties = propTreeBrowser->properties(); QtVariantProperty *property = static_cast(properties[4]); Q_ASSERT(property); QCOMPARE(property->propertyName(), tr("gravity")); this->CheckVector3Property(property->subProperties(), ignition::math::Vector3d::Zero); } modelListWidget->hide(); } // Generate a main function for the test QTEST_MAIN(ModelListWidget_TEST)