From 970914a35339a710d36619a0e2788ef6d1e26c6d Mon Sep 17 00:00:00 2001 From: Nikhil Nair <43491351+NickNair@users.noreply.github.com> Date: Thu, 11 Nov 2021 23:09:46 +0530 Subject: [PATCH 1/5] Added log storing for ign-gui (#272) Signed-off-by: Nikhil Nair Signed-off-by: Louise Poubel Co-authored-by: Louise Poubel --- src/ign.cc | 20 +++++++++++++++++++ src/ign_TEST.cc | 39 ++++++++++++++++++++++++++++++++++++- tutorials/02_commandline.md | 3 +++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/ign.cc b/src/ign.cc index 12ef07713..faba5dcc3 100644 --- a/src/ign.cc +++ b/src/ign.cc @@ -33,6 +33,18 @@ char* g_argv[] = reinterpret_cast(const_cast("./ignition")), }; +////////////////////////////////////////////////// +void startConsoleLog() +{ + std::string home; + ignition::common::env(IGN_HOMEDIR, home); + + std::string logPathMod = ignition::common::joinPaths(home, + ".ignition", "gui", "log", + ignition::common::timeToIso(IGN_SYSTEM_TIME())); + ignLogInit(logPathMod, "console.log"); +} + ////////////////////////////////////////////////// extern "C" IGNITION_GUI_VISIBLE char *ignitionVersion() { @@ -42,6 +54,8 @@ extern "C" IGNITION_GUI_VISIBLE char *ignitionVersion() ////////////////////////////////////////////////// extern "C" IGNITION_GUI_VISIBLE void cmdPluginList() { + startConsoleLog(); + ignition::gui::Application app(g_argc, g_argv); auto pluginsList = app.PluginList(); @@ -65,6 +79,8 @@ extern "C" IGNITION_GUI_VISIBLE void cmdPluginList() ////////////////////////////////////////////////// extern "C" IGNITION_GUI_VISIBLE void cmdStandalone(const char *_filename) { + startConsoleLog(); + ignition::gui::Application app(g_argc, g_argv, ignition::gui::WindowType::kDialog); @@ -79,6 +95,8 @@ extern "C" IGNITION_GUI_VISIBLE void cmdStandalone(const char *_filename) ////////////////////////////////////////////////// extern "C" IGNITION_GUI_VISIBLE void cmdConfig(const char *_config) { + startConsoleLog(); + ignition::gui::Application app(g_argc, g_argv); if (!app.findChild()) @@ -103,6 +121,8 @@ extern "C" IGNITION_GUI_VISIBLE void cmdVerbose(const char *_verbosity) ////////////////////////////////////////////////// extern "C" IGNITION_GUI_VISIBLE void cmdEmptyWindow() { + startConsoleLog(); + ignition::gui::Application app(g_argc, g_argv); if (!app.findChild()) diff --git a/src/ign_TEST.cc b/src/ign_TEST.cc index 80a240ac8..cf3ba5ea7 100644 --- a/src/ign_TEST.cc +++ b/src/ign_TEST.cc @@ -21,6 +21,8 @@ #include +#include +#include #include #include "test_config.h" // NOLINT(build/include) @@ -52,10 +54,45 @@ std::string custom_exec_str(std::string _cmd) return result; } +using namespace ignition; + +class CmdLine : public ::testing::Test +{ + // Documentation inherited + protected: void SetUp() override + { + // Change environment variable so that test files aren't written to $HOME + common::env(IGN_HOMEDIR, this->realHome); + EXPECT_TRUE(common::setenv(IGN_HOMEDIR, this->kFakeHome.c_str())); + } + + // Documentation inherited + protected: void TearDown() override + { + // Restore $HOME + EXPECT_TRUE(common::setenv(IGN_HOMEDIR, this->realHome.c_str())); + } + + /// \brief Directory to act as $HOME for tests + public: const std::string kFakeHome = common::joinPaths(PROJECT_BINARY_PATH, + "test", "fake_home"); + + /// \brief Store user's real $HOME to set it back at the end of tests. + public: std::string realHome; +}; + // See https://github.com/ignitionrobotics/ign-gui/issues/75 -TEST(CmdLine, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(list)) +TEST_F(CmdLine, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(list)) { + // Clear home if it exists + common::removeAll(this->kFakeHome); + + EXPECT_FALSE(common::exists(this->kFakeHome)); + std::string output = custom_exec_str("ign gui -l"); EXPECT_NE(output.find("TopicEcho"), std::string::npos) << output; EXPECT_NE(output.find("Publisher"), std::string::npos) << output; + + EXPECT_TRUE(common::exists(common::joinPaths(this->kFakeHome, ".ignition", + "gui"))); } diff --git a/tutorials/02_commandline.md b/tutorials/02_commandline.md index daa19ab4e..978021331 100644 --- a/tutorials/02_commandline.md +++ b/tutorials/02_commandline.md @@ -32,3 +32,6 @@ If you have Ignition Tools installed, you can use the `ign gui` command line too --force-version Use a specific library version. --versions Show the available versions. + +When using the command line tool, all console messages are logged to +`$HOME/.ignition/gui/log/`. From 8b3f2b0a646d1a11b9dedc1d49f5c59db87bf59d Mon Sep 17 00:00:00 2001 From: Louise Poubel Date: Thu, 18 Nov 2021 22:24:19 -0800 Subject: [PATCH 2/5] Don't crash if a plugin has invalid QML (#315) Signed-off-by: Louise Poubel --- src/Application.cc | 3 ++ src/Application_TEST.cc | 8 ++++++ test/plugins/CMakeLists.txt | 1 + test/plugins/TestInvalidQmlPlugin.cc | 38 +++++++++++++++++++++++++ test/plugins/TestInvalidQmlPlugin.hh | 40 +++++++++++++++++++++++++++ test/plugins/TestInvalidQmlPlugin.qml | 21 ++++++++++++++ test/plugins/TestInvalidQmlPlugin.qrc | 5 ++++ 7 files changed, 116 insertions(+) create mode 100644 test/plugins/TestInvalidQmlPlugin.cc create mode 100644 test/plugins/TestInvalidQmlPlugin.hh create mode 100644 test/plugins/TestInvalidQmlPlugin.qml create mode 100644 test/plugins/TestInvalidQmlPlugin.qrc diff --git a/src/Application.cc b/src/Application.cc index 3d9ecd301..ac60ce07a 100644 --- a/src/Application.cc +++ b/src/Application.cc @@ -387,6 +387,9 @@ bool Application::LoadPlugin(const std::string &_filename, else plugin->Load(_pluginElem); + if (nullptr == plugin->CardItem()) + return false; + // Store plugin in queue to be added to the window this->dataPtr->pluginsToAdd.push(plugin); diff --git a/src/Application_TEST.cc b/src/Application_TEST.cc index ddd5e6b6a..5d575a3c9 100644 --- a/src/Application_TEST.cc +++ b/src/Application_TEST.cc @@ -136,6 +136,14 @@ TEST(ApplicationTest, IGN_UTILS_TEST_DISABLED_ON_WIN32(LoadPlugin)) EXPECT_FALSE(app.LoadPlugin("TestNotRegisteredPlugin")); } + + // Plugin with invalid QML + { + Application app(g_argc, g_argv); + app.AddPluginPath(std::string(PROJECT_BINARY_PATH) + "/lib"); + + EXPECT_FALSE(app.LoadPlugin("TestInvalidQmlPlugin")); + } } ////////////////////////////////////////////////// diff --git a/test/plugins/CMakeLists.txt b/test/plugins/CMakeLists.txt index 7451a7329..5381233cc 100644 --- a/test/plugins/CMakeLists.txt +++ b/test/plugins/CMakeLists.txt @@ -11,6 +11,7 @@ link_directories( set (plugins TestBadInheritancePlugin + TestInvalidQmlPlugin TestNotRegisteredPlugin TestPlugin ) diff --git a/test/plugins/TestInvalidQmlPlugin.cc b/test/plugins/TestInvalidQmlPlugin.cc new file mode 100644 index 000000000..c4b604799 --- /dev/null +++ b/test/plugins/TestInvalidQmlPlugin.cc @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 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 "TestInvalidQmlPlugin.hh" + +using namespace ignition; +using namespace gui; + +///////////////////////////////////////////////// +TestInvalidQmlPlugin::TestInvalidQmlPlugin() + : Plugin() +{ +} + +///////////////////////////////////////////////// +TestInvalidQmlPlugin::~TestInvalidQmlPlugin() +{ +} + +// Register this plugin +IGNITION_ADD_PLUGIN(ignition::gui::TestInvalidQmlPlugin, + ignition::gui::Plugin) diff --git a/test/plugins/TestInvalidQmlPlugin.hh b/test/plugins/TestInvalidQmlPlugin.hh new file mode 100644 index 000000000..412dbd1e6 --- /dev/null +++ b/test/plugins/TestInvalidQmlPlugin.hh @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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. + * +*/ + +#ifndef IGNITION_GUI_TEST_MALFORMEDPLUGIN_HH_ +#define IGNITION_GUI_TEST_MALFORMEDPLUGIN_HH_ + +#include + +namespace ignition +{ + namespace gui + { + class TestInvalidQmlPlugin : public Plugin + { + Q_OBJECT + + /// \brief Constructor + public: TestInvalidQmlPlugin(); + + /// \brief Destructor + public: virtual ~TestInvalidQmlPlugin(); + }; + } +} + +#endif diff --git a/test/plugins/TestInvalidQmlPlugin.qml b/test/plugins/TestInvalidQmlPlugin.qml new file mode 100644 index 000000000..17cdc890e --- /dev/null +++ b/test/plugins/TestInvalidQmlPlugin.qml @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 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. + * +*/ +import QtQuick 2.9 + +Rectangle { + banana: fail +} diff --git a/test/plugins/TestInvalidQmlPlugin.qrc b/test/plugins/TestInvalidQmlPlugin.qrc new file mode 100644 index 000000000..c48ea9d64 --- /dev/null +++ b/test/plugins/TestInvalidQmlPlugin.qrc @@ -0,0 +1,5 @@ + + + TestInvalidQmlPlugin.qml + + From aa8632da5f30e414e3b62c62114f3ef79fde61c4 Mon Sep 17 00:00:00 2001 From: Rhys Mainwaring Date: Wed, 1 Dec 2021 06:40:17 +0000 Subject: [PATCH 3/5] Fix TopicEcho plugin message display (#322) - Change binding of width property in delegate (see: https://stackoverflow.com/questions/63767669/parent-is-null-in-listview-delegate-after-upgrade-to-qt-5-15) - Use scoped reference to model.display (see: https://forum.qt.io/topic/92085/using-qstringlistmodel-as-model-in-listview) Signed-off-by: Rhys Mainwaring --- src/plugins/topic_echo/TopicEcho.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/topic_echo/TopicEcho.qml b/src/plugins/topic_echo/TopicEcho.qml index e1b91543c..aef2cd3a5 100644 --- a/src/plugins/topic_echo/TopicEcho.qml +++ b/src/plugins/topic_echo/TopicEcho.qml @@ -97,8 +97,8 @@ Rectangle { currentIndex: -1 delegate: ItemDelegate { - width: parent.width - text: display + width: listView.width + text: model.display } model: TopicEchoMsgList From 182789999441f7c812a7b15ddb7660a3966fb4f1 Mon Sep 17 00:00:00 2001 From: Will <1305536+zflat@users.noreply.github.com> Date: Thu, 2 Dec 2021 02:19:36 -0500 Subject: [PATCH 4/5] Use qmldir to define QML module with IgnSpinBox (#319) Signed-off-by: William Wedler Co-authored-by: Louise Poubel --- include/ignition/gui/Helpers.hh | 10 ++++++++++ include/ignition/gui/qml/qmldir | 3 +++ include/ignition/gui/resources.qrc | 6 ++++++ src/Application.cc | 2 ++ src/Helpers.cc | 6 ++++++ src/plugins/teleop/Teleop.qml | 2 +- 6 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 include/ignition/gui/qml/qmldir diff --git a/include/ignition/gui/Helpers.hh b/include/ignition/gui/Helpers.hh index 2a22abf0d..a83e7fa51 100644 --- a/include/ignition/gui/Helpers.hh +++ b/include/ignition/gui/Helpers.hh @@ -79,6 +79,16 @@ namespace ignition IGNITION_GUI_VISIBLE QStringList worldNames(); + + /// \brief Import path for ign-gui QML modules added to the Qt resource system + /// This helper function returns the QRC resource path where custom ignition QML + /// modules can be imported from. To import an ignition QML module, add this path + /// to the QML engine's import path list before attempting to load a QML file + /// that imports ignition QML modules. + /// \return Resousrce path prefix as a string + IGNITION_GUI_VISIBLE + const QString qmlQrcImportPath(); + /// \brief Returns the first element on a QList which matches the given /// property. /// \param[in] _list The list to search through. diff --git a/include/ignition/gui/qml/qmldir b/include/ignition/gui/qml/qmldir new file mode 100644 index 000000000..f4f66ebc1 --- /dev/null +++ b/include/ignition/gui/qml/qmldir @@ -0,0 +1,3 @@ +module ignition.gui + +IgnSpinBox 1.0 IgnSpinBox.qml \ No newline at end of file diff --git a/include/ignition/gui/resources.qrc b/include/ignition/gui/resources.qrc index fd0cb74ce..934624c10 100644 --- a/include/ignition/gui/resources.qrc +++ b/include/ignition/gui/resources.qrc @@ -20,4 +20,10 @@ qml/images/menu.png qml/images/search.svg + + + qml/qmldir + + qml/IgnSpinBox.qml + diff --git a/src/Application.cc b/src/Application.cc index ac60ce07a..6ca02efd8 100644 --- a/src/Application.cc +++ b/src/Application.cc @@ -28,6 +28,7 @@ #include "ignition/gui/Application.hh" #include "ignition/gui/config.hh" #include "ignition/gui/Dialog.hh" +#include "ignition/gui/Helpers.hh" #include "ignition/gui/MainWindow.hh" #include "ignition/gui/Plugin.hh" @@ -91,6 +92,7 @@ Application::Application(int &_argc, char **_argv, const WindowType _type) // QML engine this->dataPtr->engine = new QQmlApplicationEngine(); + this->dataPtr->engine->addImportPath(qmlQrcImportPath()); // Install signal handler for graceful shutdown this->dataPtr->signalHandler.AddCallback( diff --git a/src/Helpers.cc b/src/Helpers.cc index 4c6a51329..0fc89d7cc 100644 --- a/src/Helpers.cc +++ b/src/Helpers.cc @@ -180,3 +180,9 @@ QStringList ignition::gui::worldNames() return worldNamesVariant.toStringList(); } + +///////////////////////////////////////////////// +const QString ignition::gui::qmlQrcImportPath() +{ + return "qrc:/ign-gui-qml/"; +} diff --git a/src/plugins/teleop/Teleop.qml b/src/plugins/teleop/Teleop.qml index 74f9eed9d..f4001a578 100644 --- a/src/plugins/teleop/Teleop.qml +++ b/src/plugins/teleop/Teleop.qml @@ -20,7 +20,7 @@ import QtQuick.Controls 2.2 import QtQuick.Controls.Material 2.1 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 -import "qrc:/qml" +import ignition.gui 1.0 Rectangle { color:"transparent" From 803bf2311ba6fde08da557376b0ff85fe2137f79 Mon Sep 17 00:00:00 2001 From: Louise Poubel Date: Mon, 6 Dec 2021 10:29:49 -0800 Subject: [PATCH 5/5] Fix codecheck (#329) Signed-off-by: Louise Poubel --- include/ignition/gui/Helpers.hh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/ignition/gui/Helpers.hh b/include/ignition/gui/Helpers.hh index a83e7fa51..bb88ec828 100644 --- a/include/ignition/gui/Helpers.hh +++ b/include/ignition/gui/Helpers.hh @@ -80,11 +80,11 @@ namespace ignition QStringList worldNames(); - /// \brief Import path for ign-gui QML modules added to the Qt resource system - /// This helper function returns the QRC resource path where custom ignition QML - /// modules can be imported from. To import an ignition QML module, add this path - /// to the QML engine's import path list before attempting to load a QML file - /// that imports ignition QML modules. + /// \brief Import path for ign-gui QML modules added to the Qt resource + /// system. This helper function returns the QRC resource path where custom + /// ignition QML modules can be imported from. To import an ignition QML + /// module, add this path to the QML engine's import path list before + /// attempting to load a QML file that imports ignition QML modules. /// \return Resousrce path prefix as a string IGNITION_GUI_VISIBLE const QString qmlQrcImportPath();