From a338699c4ca049cf9cca19a0e3f1594e08f9092f Mon Sep 17 00:00:00 2001 From: Dmitry Kovalev Date: Thu, 4 Aug 2022 23:19:03 +0300 Subject: [PATCH 01/43] BareMetal: Fix bug when cloning jLink gdb server provider Change-Id: I5d5a957aaa25238a6d05462c6a8f40b660ca7ea0 Reviewed-by: hjk --- .../baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp index 42f8973d650..481a8959572 100644 --- a/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp @@ -175,6 +175,11 @@ bool JLinkGdbServerProvider::operator==(const IDebugServerProvider &other) const const auto p = static_cast(&other); return m_executableFile == p->m_executableFile + && m_jlinkDevice == p->m_jlinkDevice + && m_jlinkHost == p->m_jlinkHost + && m_jlinkHostAddr == p->m_jlinkHostAddr + && m_jlinkTargetIface == p->m_jlinkTargetIface + && m_jlinkTargetIfaceSpeed == p->m_jlinkTargetIfaceSpeed && m_additionalArguments == p->m_additionalArguments; } From 892448753c30542c7d9bc9575f116020b8945460 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 5 Aug 2022 12:10:09 +0200 Subject: [PATCH 02/43] Update qbs submodule to HEAD of 1.23 branch Change-Id: I5266c606a254638cfa5440a77043d6f36c49921a Reviewed-by: Ivan Komissarov Reviewed-by: Reviewed-by: Qt CI Bot --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index faac35b5b31..3e0553e4651 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit faac35b5b3191348a72256437ccbb71a68dfb3a9 +Subproject commit 3e0553e4651197e61c5086d96048b75462bde897 From 9fe3aa661282ad04bd458064cab15ea952939718 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 8 Aug 2022 13:05:47 +0200 Subject: [PATCH 03/43] Python: Fix detecting python ls for reopened files Change-Id: Icc601fa43c7b1432d0bf12fae2f65e0c914262ac Reviewed-by: Christian Stenger --- src/plugins/python/pythoneditor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp index 32fd9e92664..2a6c0d094cb 100644 --- a/src/plugins/python/pythoneditor.cpp +++ b/src/plugins/python/pythoneditor.cpp @@ -120,13 +120,13 @@ public: if (python.exists()) PyLSConfigureAssistant::openDocumentWithPython(python, this); }); + connect(this, &PythonDocument::openFinishedSuccessfully, + this, &PythonDocument::checkForPyls); } - void setFilePath(const Utils::FilePath &filePath) override + void checkForPyls() { - TextEditor::TextDocument::setFilePath(filePath); - - const Utils::FilePath &python = detectPython(filePath); + const Utils::FilePath &python = detectPython(filePath()); if (!python.exists()) return; From b732801d6a0db9a9819a261a83270e40fcac6d6a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 8 Aug 2022 08:41:10 +0200 Subject: [PATCH 04/43] Update changelog for 8.0.1 Change-Id: Ib1116deb89c092f66a79d1332919ebc73d33ec2a Reviewed-by: David Schulz --- dist/changes-8.0.1.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/dist/changes-8.0.1.md b/dist/changes-8.0.1.md index cf5fc2f8f02..37247687c2f 100644 --- a/dist/changes-8.0.1.md +++ b/dist/changes-8.0.1.md @@ -13,8 +13,14 @@ the public Git repository. For example: Editing ------- +* Delayed context menu tooltip action creation +* Cached the last QIcon created from a Utils::Icon + ### C++ +* Prevent opening unneeded generated ui header files in clangd +* Fixed documents getting opened in wrong clangd + Projects -------- @@ -42,17 +48,34 @@ Platforms ### Baremetal * Fixed running and debugging applications (QTCREATORBUG-27972) +* Fixed bug when cloning jLink gdb server provider + +Debugging +--------- + +* Fixed bitfield display with Python 3 + Credits for these changes go to: -------------------------------- +Alexander Akulich Alibek Omarov André Pönitz Christian Kandeler +Christian Stenger Cristian Adam +David Schulz +Dmitry Kovalev Eike Ziller Ivan Komissarov Jaroslaw Kobus +Knud Dollereder Mahmoud Badri +Marcus Tillmanns Mats Honkamaa +Miikka Heikkinen +Orgad Shaneh Oswald Buddenhagen +Samuel Ghinet Thomas Hartmann +Vikas Pachdha From 176c3906fe859e4bded0dc749d517fe3269e0fe7 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Tue, 2 Aug 2022 15:20:25 +0200 Subject: [PATCH 05/43] ClangFormat: Fix ignoring DisableFormat option Task-number: QTCREATORBUG-27261 Change-Id: Ib9671f5c4499a39eb40e2a269dc73328fa5ad12f Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/clangformat/clangformatbaseindenter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 22b55170a6f..4ee5daebdba 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -66,7 +66,6 @@ void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) return; - style.DisableFormat = false; style.ColumnLimit = 0; #ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED style.KeepLineBreaksForNonEmptyLines = true; From ff2235bd5d3ba11270f61f8b9cd992d16a0bcfce Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 8 Aug 2022 15:37:45 +0200 Subject: [PATCH 06/43] CppEditor: Add missing hyphen before option names Amends 06e2f8d8fa3a5335e8d91de9d5fe5db2ee4ea379. Change-Id: I514f04ce21b91c80dc15d1e0323b2d80df08aeb5 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Hannes Domani Reviewed-by: David Schulz --- src/plugins/cppeditor/compileroptionsbuilder.cpp | 8 ++++---- src/plugins/cppeditor/compileroptionsbuilder_test.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/cppeditor/compileroptionsbuilder.cpp b/src/plugins/cppeditor/compileroptionsbuilder.cpp index 505cb4ee0a1..d663b227bca 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder.cpp +++ b/src/plugins/cppeditor/compileroptionsbuilder.cpp @@ -473,16 +473,16 @@ void CompilerOptionsBuilder::addLanguageVersionAndExtensions() default: break; case LanguageVersion::CXX14: - option = "-clang:std=c++14"; + option = "-clang:-std=c++14"; break; case LanguageVersion::CXX17: - option = "-clang:std=c++17"; + option = "-clang:-std=c++17"; break; case LanguageVersion::CXX20: - option = "-clang:std=c++20"; + option = "-clang:-std=c++20"; break; case LanguageVersion::CXX2b: - option = "-clang:std=c++2b"; + option = "-clang:-std=c++2b"; break; } diff --git a/src/plugins/cppeditor/compileroptionsbuilder_test.cpp b/src/plugins/cppeditor/compileroptionsbuilder_test.cpp index 65d18291849..6131ce5f023 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder_test.cpp +++ b/src/plugins/cppeditor/compileroptionsbuilder_test.cpp @@ -192,7 +192,7 @@ void CompilerOptionsBuilderTest::testLanguageVersionIsExplicitlySetIfNotProvided UseTweakedHeaderPaths::No, UseLanguageDefines::Yes}; compilerOptionsBuilder.build(ProjectFile::CXXSource, UsePrecompiledHeaders::No); - QVERIFY(compilerOptionsBuilder.options().contains("-clang:std=c++17")); + QVERIFY(compilerOptionsBuilder.options().contains("-clang:-std=c++17")); } void CompilerOptionsBuilderTest::testAddWordWidth() @@ -633,7 +633,7 @@ void CompilerOptionsBuilderTest::testBuildAllOptionsMsvc() [&t](const QString &o) { return o.contains(t.toNative("wrappedQtHeaders/QtCore")); }); QCOMPARE(compilerOptionsBuilder.options(), (QStringList{"-nostdinc", "-nostdinc++", "--driver-mode=cl", "/Zs", "-m64", - "--target=x86_64-apple-darwin10", "/TP", "-clang:std=c++17", + "--target=x86_64-apple-darwin10", "/TP", "-clang:-std=c++17", "-fms-compatibility-version=19.00", "-DprojectFoo=projectBar", "-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"", "-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"", @@ -662,7 +662,7 @@ void CompilerOptionsBuilderTest::testBuildAllOptionsMsvcWithExceptions() [&t](const QString &o) { return o.contains(t.toNative("wrappedQtHeaders/QtCore")); }); QCOMPARE(compilerOptionsBuilder.options(), (QStringList{"-nostdinc", "-nostdinc++", "--driver-mode=cl", "/Zs", "-m64", - "--target=x86_64-apple-darwin10", "/TP", "-clang:std=c++17", "-fcxx-exceptions", + "--target=x86_64-apple-darwin10", "/TP", "-clang:-std=c++17", "-fcxx-exceptions", "-fexceptions", "-fms-compatibility-version=19.00", "-DprojectFoo=projectBar", "-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"", From c86d61846dd5f4725bc8cadf8698d463809710c9 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 8 Aug 2022 16:11:15 +0200 Subject: [PATCH 07/43] CppEditor: Speed up signal/slot check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do the look-up only after the cheaper checks have succeeded. Amends 0087bd492fe7dc6de3a938a1276f66b1d3af5e44. Fixes: QTCREATORBUG-28035 Change-Id: I250588d3fa1a763e87452c6decb0aa7517076024 Reviewed-by: Artem Sokolovskii Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Jean-Michaël Celerier Reviewed-by: David Schulz --- src/plugins/cppeditor/cppmodelmanager.cpp | 41 ++++++++++++----------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 4a7297815ac..dd47ae5f5a5 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -377,7 +377,6 @@ SignalSlotType CppModelManager::getSignalSlotType(const QString &filePath, QTextCursor cursor(&textDocument); cursor.setPosition(position); - // Are we at the second argument of a function call? const QList path = ASTPath(document)(cursor); if (path.isEmpty()) return SignalSlotType::None; @@ -387,9 +386,27 @@ SignalSlotType CppModelManager::getSignalSlotType(const QString &filePath, break; } - // Is the function called "connect" or "disconnect"? if (!callAst || !callAst->base_expression) return SignalSlotType::None; + + const int argumentPosition = argumentPositionOf(path.last(), callAst); + if (argumentPosition != 2 && argumentPosition != 4) + return SignalSlotType::None; + + const NameAST *nameAst = nullptr; + if (const IdExpressionAST * const idAst = callAst->base_expression->asIdExpression()) + nameAst = idAst->name; + else if (const MemberAccessAST * const ast = callAst->base_expression->asMemberAccess()) + nameAst = ast->member_name; + if (!nameAst || !nameAst->name) + return SignalSlotType::None; + const Identifier * const id = nameAst->name->identifier(); + if (!id) + return SignalSlotType::None; + const QString funcName = QString::fromUtf8(id->chars(), id->size()); + if (funcName != "connect" && funcName != "disconnect") + return SignalSlotType::None; + Scope *scope = document->globalNamespace(); for (auto it = path.crbegin(); it != path.crend(); ++it) { if (const CompoundStatementAST * const stmtAst = (*it)->asCompoundStatement()) { @@ -397,12 +414,8 @@ SignalSlotType CppModelManager::getSignalSlotType(const QString &filePath, break; } } - const NameAST *nameAst = nullptr; const LookupContext context(document, snapshot); - if (const IdExpressionAST * const idAst = callAst->base_expression->asIdExpression()) { - nameAst = idAst->name; - } else if (const MemberAccessAST * const ast = callAst->base_expression->asMemberAccess()) { - nameAst = ast->member_name; + if (const MemberAccessAST * const ast = callAst->base_expression->asMemberAccess()) { TypeOfExpression exprType; exprType.setExpandTemplates(true); exprType.init(document, snapshot); @@ -432,14 +445,6 @@ SignalSlotType CppModelManager::getSignalSlotType(const QString &filePath, if (!scope) return SignalSlotType::None; } - if (!nameAst || !nameAst->name) - return SignalSlotType::None; - const Identifier * const id = nameAst->name->identifier(); - if (!id) - return SignalSlotType::None; - const QString funcName = QString::fromUtf8(id->chars(), id->size()); - if (funcName != "connect" && funcName != "disconnect") - return SignalSlotType::None; // Is the function a member function of QObject? const QList matches = context.lookup(nameAst->name, scope); @@ -462,10 +467,8 @@ SignalSlotType CppModelManager::getSignalSlotType(const QString &filePath, expression = expressionUnderCursor(cursor); - const int argumentPosition = argumentPositionOf(path.last(), callAst); - if ((expression.endsWith(QLatin1String("SIGNAL")) - && (argumentPosition == 2 || argumentPosition == 4)) - || (expression.endsWith(QLatin1String("SLOT")) && argumentPosition == 4)) + if (expression.endsWith(QLatin1String("SIGNAL")) + || (expression.endsWith(QLatin1String("SLOT")) && argumentPosition == 4)) return SignalSlotType::OldStyleSignal; if (argumentPosition == 2) From 52b8b51b32a63844004a9073a2d5161dd0e96dac Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 10 Aug 2022 09:30:49 +0200 Subject: [PATCH 08/43] ScxmlEditor: Prevent crash Create the connection after populating the combobox prevents an assertion. Change-Id: I35be1cf724ed7084123e7070b377b50274132e55 Reviewed-by: hjk --- src/plugins/scxmleditor/common/colorsettings.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/plugins/scxmleditor/common/colorsettings.cpp b/src/plugins/scxmleditor/common/colorsettings.cpp index 49bbb395efc..b375bbfe5e5 100644 --- a/src/plugins/scxmleditor/common/colorsettings.cpp +++ b/src/plugins/scxmleditor/common/colorsettings.cpp @@ -39,11 +39,6 @@ ColorSettings::ColorSettings(QWidget *parent) m_ui.setupUi(this); m_ui.m_colorThemeView->setEnabled(false); - connect(m_ui.m_comboColorThemes, QOverload::of(&QComboBox::currentIndexChanged), - this, &ColorSettings::selectTheme); - connect(m_ui.m_colorThemeView, &ColorThemeView::colorChanged, this, &ColorSettings::updateCurrentColors); - connect(m_ui.m_addColorTheme, &QToolButton::clicked, this, &ColorSettings::createTheme); - connect(m_ui.m_removeColorTheme, &QToolButton::clicked, this, &ColorSettings::removeTheme); const QSettings *s = Core::ICore::settings(); @@ -53,6 +48,12 @@ ColorSettings::ColorSettings(QWidget *parent) for (auto it = m_colorThemes.cbegin(); it != m_colorThemes.cend(); ++it) m_ui.m_comboColorThemes->addItem(it.key()); m_ui.m_comboColorThemes->setCurrentText(s->value(Constants::C_SETTINGS_COLORSETTINGS_CURRENTCOLORTHEME).toString()); + + connect(m_ui.m_comboColorThemes, QOverload::of(&QComboBox::currentIndexChanged), + this, &ColorSettings::selectTheme); + connect(m_ui.m_colorThemeView, &ColorThemeView::colorChanged, this, &ColorSettings::updateCurrentColors); + connect(m_ui.m_addColorTheme, &QToolButton::clicked, this, &ColorSettings::createTheme); + connect(m_ui.m_removeColorTheme, &QToolButton::clicked, this, &ColorSettings::removeTheme); } void ColorSettings::save() From 5db3d507ddf4b1582fc32828d9a6b67a3a1309bd Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 10 Aug 2022 09:58:22 +0200 Subject: [PATCH 09/43] Revert "CMake: Reload item data on CMake executable path changed" 057bb3095 makes it impossible to type in dir separators and so a valid path to a cmake executable in the Path field of the cmake settings page. This reverts commit 057bb3095b11e88cf509cea5845a6e4fabad90d8. Change-Id: I3edbdced8eaac15f34ca43acf1e86f4be6cd9be7 Reviewed-by: hjk Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/cmakesettingspage.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp index 826af0c7b67..09a6bfbf2e9 100644 --- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp @@ -433,7 +433,6 @@ public: private: void updateQchFilePath(); - void reload(); CMakeToolItemModel *m_model; QLineEdit *m_displayNameLineEdit; @@ -479,8 +478,8 @@ CMakeToolItemConfigWidget::CMakeToolItemConfigWidget(CMakeToolItemModel *model) connect(m_binaryChooser, &PathChooser::rawPathChanged, this, [this]() { updateQchFilePath(); + m_qchFileChooser->setBaseDirectory(m_binaryChooser->filePath().parentDir()); store(); - reload(); }); connect(m_qchFileChooser, &PathChooser::rawPathChanged, this, &CMakeToolItemConfigWidget::store); connect(m_displayNameLineEdit, &QLineEdit::textChanged, this, &CMakeToolItemConfigWidget::store); @@ -504,18 +503,6 @@ void CMakeToolItemConfigWidget::updateQchFilePath() m_qchFileChooser->setFilePath(CMakeTool::searchQchFile(m_binaryChooser->filePath())); } -void CMakeToolItemConfigWidget::reload() -{ - if (!m_id.isValid()) - return; - - const CMakeToolTreeItem *item = m_model->cmakeToolItem(m_id); - if (!item) - return; - - load(item); -} - void CMakeToolItemConfigWidget::load(const CMakeToolTreeItem *item) { m_loadingItem = true; // avoid intermediate signal handling From 93fbef4de62b6c46ba569ed8c3601c88ec94102d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 9 Aug 2022 16:44:58 +0200 Subject: [PATCH 10/43] ClangCodeModel: Consider the case of a restarted client We must not assume the initialized() signal comes only once. Task-number: QTCREATORBUG-27596 Change-Id: Ife19657b7e0701a0e0dc10806e230bd1744a20aa Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- .../clangmodelmanagersupport.cpp | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index a1dc290a02b..7375cc9c685 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -160,6 +160,20 @@ static void checkSystemForClangdSuitability() Core::ICore::infoBar()->addInfo(info); } +static void updateParserConfig(ClangdClient *client) +{ + if (!client->reachable()) + return; + if (const auto editor = TextEditor::BaseTextEditor::currentTextEditor()) { + if (!client->documentOpen(editor->textDocument())) + return; + const Utils::FilePath filePath = editor->textDocument()->filePath(); + if (const auto processor = ClangEditorDocumentProcessor::get(filePath.toString())) + client->updateParserConfig(filePath, processor->parserConfig()); + } +} + + ClangModelManagerSupport::ClangModelManagerSupport() { QTC_CHECK(!m_instance); @@ -399,6 +413,12 @@ void ClangModelManagerSupport::updateLanguageClient( if (Client * const oldClient = clientForProject(project)) LanguageClientManager::shutdownClient(oldClient); ClangdClient * const client = createClient(project, jsonDbDir); + connect(client, &Client::shadowDocumentSwitched, this, + [](const Utils::FilePath &fp) { + ClangdClient::handleUiHeaderChange(fp.fileName()); + }); + connect(CppModelManager::instance(), &CppModelManager::projectPartsUpdated, + client, [client] { updateParserConfig(client); }); connect(client, &Client::initialized, this, [this, client, project, projectInfo, jsonDbDir] { using namespace ProjectExplorer; if (!SessionManager::hasProject(project)) @@ -410,25 +430,15 @@ void ClangModelManagerSupport::updateLanguageClient( if (!newProjectInfo || *newProjectInfo != *projectInfo) return; - const auto updateParserConfig = [client] { - if (const auto editor = TextEditor::BaseTextEditor::currentTextEditor()) { - if (!client->documentOpen(editor->textDocument())) - return; - const Utils::FilePath filePath = editor->textDocument()->filePath(); - if (const auto processor = ClangEditorDocumentProcessor::get( - filePath.toString())) { - const CppEditor::BaseEditorDocumentParser::Configuration config - = processor->parserConfig(); - client->updateParserConfig(filePath, config); - } - } - }; - // Acquaint the client with all open C++ documents for this project. bool hasDocuments = false; const ClangdSettings settings(ClangdProjectSettings(project).settings()); for (TextEditor::TextDocument * const doc : allCppDocuments()) { Client * const currentClient = LanguageClientManager::clientForDocument(doc); + if (currentClient == client) { + hasDocuments = true; + continue; + } if (!settings.sizeIsOkay(doc->filePath())) continue; const Project * const docProject = SessionManager::projectForFile(doc->filePath()); @@ -457,17 +467,8 @@ void ClangModelManagerSupport::updateLanguageClient( ++it; } } - connect(client, &Client::shadowDocumentSwitched, this, - [](const Utils::FilePath &fp) { - ClangdClient::handleUiHeaderChange(fp.fileName()); - }); - if (client->state() == Client::Initialized) - updateParserConfig(); - else - connect(client, &Client::initialized, client, updateParserConfig); - connect(CppModelManager::instance(), &CppModelManager::projectPartsUpdated, - client, updateParserConfig); + updateParserConfig(client); if (hasDocuments) return; From 9c963ce8aee3c181cef20e2b86dfd2aefc607a4a Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 9 Aug 2022 17:05:07 +0200 Subject: [PATCH 11/43] LanguageClient: Do not clear shadow documents on reset We need to preserve this information. Instead, clear only the list of reverse document dependencies. Change-Id: I5589d5e3eff613706ea5f2029df1f90eacbbbb4e Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz --- src/plugins/languageclient/client.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index e57700133da..eeb1499a747 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -1533,7 +1533,8 @@ bool ClientPrivate::reset() qDeleteAll(m_documentHighlightsTimer); m_documentHighlightsTimer.clear(); m_progressManager.reset(); - m_shadowDocuments.clear(); + for (auto &doc : m_shadowDocuments) + doc.second.clear(); m_documentVersions.clear(); return true; } From 774010d96e49553b77a5cc9c0cd6d14ec50d7686 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Fri, 5 Aug 2022 14:11:10 +0200 Subject: [PATCH 12/43] Add information on how to set up qmlls Fixes: QTCREATORBUG-28025 Change-Id: Id9a74a15f1fd716f714e8f87fc2d986f9b952e94 Reviewed-by: Fabian Kosmale --- .../editors/creator-only/creator-language-server.qdoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc index a2bebb49fb5..80ee71d960f 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc @@ -165,6 +165,16 @@ To disable the Python language server, deselect \uicontrol {Use Python Language Server}. + \section2 Qml Language Server + + Qt 6.4 ships with the qmlls language server that provides completions and warnings for QML. + It can be set up as a \l {Generic StdIO Language Server}, selecting \c {text/x-qml} and + \c {application/x-qt.ui+qml} as MIME Types, and \c {/bin/qmlls} as executable. + + If the language server is used together with the QmlJSEditor plugin duplicate suggestions and + warnings might be shown. To avoid this you might want to disable it as described in + \l {Enabling and Disabling Plugins}. + \section1 Supported Locator Filters The locator enables you to browse not only files, but any items defined by From 45f93a817a527e6dc81a8971dd2868b3da66cd84 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 5 Aug 2022 17:14:05 +0300 Subject: [PATCH 13/43] QmlDesigner: Add environment and model selectors to material preview The model and the scene environment used to render material previews can now be selected via buttons next to the preview in material editor. Task-number: QDS-7347 Change-Id: I03089029e8420f80ed65be1c7b7a1ce4581f2fd4 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Bot --- .../qtcreator/qml/qmlpuppet/editor3d_qt5.qrc | 2 + .../qtcreator/qml/qmlpuppet/editor3d_qt6.qrc | 2 + .../mockfiles/images/preview_landscape.hdr | Bin 0 -> 100900 bytes .../mockfiles/images/preview_studio.hdr | Bin 0 -> 108923 bytes .../mockfiles/qt5/MaterialNodeView.qml | 51 +++++- .../mockfiles/qt5/ModelNode3DImageView.qml | 15 +- .../mockfiles/qt6/MaterialNodeView.qml | 75 +++++++-- .../mockfiles/qt6/ModelNode3DImageView.qml | 19 ++- .../qt5informationnodeinstanceserver.cpp | 32 +++- .../qt5informationnodeinstanceserver.h | 8 + .../EmptyMaterialEditorPane.qml | 6 + .../MaterialEditorPane.qml | 17 ++ .../MaterialEditorTopSection.qml | 150 ++++++++++++++++-- .../imports/StudioTheme/InternalConstants.qml | 134 ++++++++-------- .../imports/StudioTheme/icons.ttf | Bin 23512 -> 23736 bytes .../components/componentcore/theme.h | 2 + .../materialbrowser/materialbrowserview.cpp | 4 + .../materialeditor/materialeditorview.cpp | 126 ++++++++++++++- .../materialeditor/materialeditorview.h | 9 ++ .../instances/nodeinstanceview.cpp | 3 +- 20 files changed, 543 insertions(+), 112 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_landscape.hdr create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_studio.hdr diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc index bbe9a910db6..d4127574a69 100644 --- a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc +++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc @@ -16,6 +16,8 @@ mockfiles/images/static_floor.png mockfiles/images/spot.png mockfiles/images/spot@2x.png + mockfiles/images/preview_landscape.hdr + mockfiles/images/preview_studio.hdr mockfiles/qt5/AdjustableArrow.qml mockfiles/qt5/AreaLightHandle.qml mockfiles/qt5/Arrow.qml diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc index 05459423349..bb29d683a07 100644 --- a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc +++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc @@ -18,6 +18,8 @@ mockfiles/images/floor_tex.png mockfiles/images/spot.png mockfiles/images/spot@2x.png + mockfiles/images/preview_landscape.hdr + mockfiles/images/preview_studio.hdr mockfiles/qt6/AdjustableArrow.qml mockfiles/qt6/AreaLightHandle.qml mockfiles/qt6/Arrow.qml diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_landscape.hdr b/share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_landscape.hdr new file mode 100644 index 0000000000000000000000000000000000000000..2c6b4372d4734cf481324caecdf2406070fa6a01 GIT binary patch literal 100900 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%0AL`e)Eoq*y;N8&!YnQekKf7?z>bH-M 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 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml index 9fee06e0ad1..067e34928b7 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml @@ -29,8 +29,12 @@ View3D { id: root anchors.fill: parent environment: sceneEnv + camera: envMode === "SkyBox" && envValue === "preview_studio" ? studioCamera : defaultCamera property Material previewMaterial + property string envMode + property string envValue + property string modelSrc: "#Sphere" function fitToViewPort(closeUp) { @@ -41,28 +45,59 @@ View3D { id: sceneEnv antialiasingMode: SceneEnvironment.MSAA antialiasingQuality: SceneEnvironment.High + backgroundMode: envMode === "Color" ? SceneEnvironment.Color + : envMode === "SkyBox" ? SceneEnvironment.SkyBox + : SceneEnvironment.Transparent + clearColor: envMode === "Color" ? envValue : "#000000" + lightProbe: envMode === "SkyBox" ? skyBoxTex : null + + Texture { + id: skyBoxTex + source: envMode === "SkyBox" ? "../images/" + envValue + ".hdr" + : "" + } } Node { DirectionalLight { eulerRotation.x: -26 - eulerRotation.y: -57 + eulerRotation.y: modelSrc === "#Cube" ? -10 : -50 + brightness: envMode !== "SkyBox" ? 100 : 0 } PerspectiveCamera { - y: 125.331 - z: 120 - eulerRotation.x: -31 + id: defaultCamera + y: 70 + z: 200 + eulerRotation.x: -5.71 clipNear: 1 clipFar: 1000 } - Model { - id: model + PerspectiveCamera { + id: studioCamera + y: 232 + z: 85 + eulerRotation.x: -64.98 + clipNear: 1 + clipFar: 1000 + } + Node { + rotation: root.camera.rotation y: 50 - source: "#Sphere" - materials: previewMaterial + Node { + y: modelSrc === "#Cone" ? -40 : 10 + eulerRotation.x: 35 + Model { + id: model + source: modelSrc ? modelSrc : "#Sphere" + eulerRotation.y: 45 + materials: previewMaterial + scale: !modelSrc || modelSrc === "#Sphere" + ? Qt.vector3d(1.7, 1.7, 1.7) : Qt.vector3d(1.2, 1.2, 1.2) + } + } } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml index 70b9dbc4d0e..d32a1ea915d 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml @@ -50,25 +50,28 @@ Item { view.destroy(); } - function createViewForObject(obj) + function createViewForObject(obj, env, envValue, model) { if (obj instanceof Material) - createViewForMaterial(obj); + createViewForMaterial(obj, env, envValue, model); else if (obj instanceof Model) createViewForModel(obj); else if (obj instanceof Node) createViewForNode(obj); } - function createViewForMaterial(material) + function createViewForMaterial(material, env, envValue, model) { if (!materialViewComponent) materialViewComponent = Qt.createComponent("MaterialNodeView.qml"); // Always recreate the view to ensure material is up to date - if (materialViewComponent.status === Component.Ready) - view = materialViewComponent.createObject(viewRect, {"previewMaterial": material}); - + if (materialViewComponent.status === Component.Ready) { + view = materialViewComponent.createObject(viewRect, {"previewMaterial": material, + "envMode": env, + "envValue": envValue, + "modelSrc": model}); + } previewObject = material; } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index 94051d5f6e6..12fdd3048eb 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -29,8 +29,12 @@ View3D { id: root anchors.fill: parent environment: sceneEnv + camera: envMode === "SkyBox" && envValue === "preview_studio" ? studioCamera : defaultCamera property Material previewMaterial + property string envMode + property string envValue + property string modelSrc: "#Sphere" function fitToViewPort(closeUp) { @@ -41,30 +45,79 @@ View3D { id: sceneEnv antialiasingMode: SceneEnvironment.MSAA antialiasingQuality: SceneEnvironment.High + backgroundMode: envMode === "Color" ? SceneEnvironment.Color + : envMode === "SkyBox" ? SceneEnvironment.SkyBox + : SceneEnvironment.Transparent + clearColor: envMode === "Color" ? envValue : "#000000" + lightProbe: envMode === "SkyBox" ? skyBoxTex : null + + Texture { + id: skyBoxTex + source: envMode === "SkyBox" ? "../images/" + envValue + ".hdr" + : "" + } } Node { DirectionalLight { eulerRotation.x: -26 - eulerRotation.y: -57 + eulerRotation.y: modelSrc === "#Cube" ? -10 : -50 + brightness: envMode !== "SkyBox" ? 1 : 0 } PerspectiveCamera { - y: 125.331 - z: 120 - eulerRotation.x: -31 + id: defaultCamera + y: 70 + z: 200 + eulerRotation.x: -5.71 clipNear: 1 clipFar: 1000 } - Model { - id: model - readonly property bool _edit3dLocked: true // Make this non-pickable - - y: 50 - source: "#Sphere" - materials: previewMaterial + PerspectiveCamera { + id: studioCamera + y: 232 + z: 85 + eulerRotation.x: -64.98 + clipNear: 1 + clipFar: 1000 } + Node { + rotation: root.camera.rotation + y: 50 + Node { + y: modelSrc === "#Cone" ? -40 : 10 + eulerRotation.x: 35 + Model { + id: model + readonly property bool _edit3dLocked: true // Make this non-pickable + source: modelSrc ? modelSrc : "#Sphere" + eulerRotation.y: 45 + materials: previewMaterial + scale: !modelSrc || modelSrc === "#Sphere" + ? Qt.vector3d(1.7, 1.7, 1.7) : Qt.vector3d(1.2, 1.2, 1.2) + } + } + } + Model { + id: floorModel + source: "#Rectangle" + scale.y: 8 + scale.x: 8 + eulerRotation.x: -60 + visible: !envMode || envMode === "Default" + materials: floorMaterial + DefaultMaterial { + id: floorMaterial + diffuseMap: floorTex + Texture { + id: floorTex + source: "../images/floor_tex.png" + scaleU: floorModel.scale.x + scaleV: floorModel.scale.y + } + } + } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml index 031d01d65fb..e409e35aee0 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml @@ -50,25 +50,31 @@ Item { view.destroy(); } - function createViewForObject(obj) + function createViewForObject(obj, env, envValue, model) { + backgroundView3d.visible = true; if (obj instanceof Material) - createViewForMaterial(obj); + createViewForMaterial(obj, env, envValue, model); else if (obj instanceof Model) createViewForModel(obj); else if (obj instanceof Node) createViewForNode(obj); } - function createViewForMaterial(material) + function createViewForMaterial(material, env, envValue, model) { if (!materialViewComponent) materialViewComponent = Qt.createComponent("MaterialNodeView.qml"); // Always recreate the view to ensure material is up to date - if (materialViewComponent.status === Component.Ready) - view = materialViewComponent.createObject(viewRect, {"previewMaterial": material}); - + if (materialViewComponent.status === Component.Ready) { + view = materialViewComponent.createObject(viewRect, {"previewMaterial": material, + "envMode": env, + "envValue": envValue, + "modelSrc": model}); + } + // Floor must be in same view as material so material can reflect it, so hide it in this one + backgroundView3d.visible = false; previewObject = material; } @@ -129,6 +135,7 @@ Item { // Use View3D instead of static image to make background look good on all resolutions View3D { + id: backgroundView3d anchors.fill: parent environment: sceneEnv diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 516213588c4..365aca3cd3b 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -339,6 +339,31 @@ void Qt5InformationNodeInstanceServer::resolveImportSupport() #endif } +void Qt5InformationNodeInstanceServer::updateMaterialPreviewData(const QVector &valueChanges) +{ + const PropertyName matPrevPrefix("matPrev"); + qint32 materialLibraryId = -1; + for (const auto &container : valueChanges) { + if (container.name().startsWith(matPrevPrefix)) { + if (!hasInstanceForId(container.instanceId())) + continue; + if (materialLibraryId < 0) { + ServerNodeInstance instance = instanceForId(container.instanceId()); + if (instance.id() == "__materialLibrary__") + materialLibraryId = container.instanceId(); + } + if (container.instanceId() == materialLibraryId) { + if (container.name() == "matPrevEnv") + m_materialPreviewData.env = container.value().toString(); + else if (container.name() == "matPrevEnvValue") + m_materialPreviewData.envValue = container.value().toString(); + else if (container.name() == "matPrevModel") + m_materialPreviewData.model = container.value().toString(); + } + } + } +} + void Qt5InformationNodeInstanceServer::updateRotationBlocks(const QVector &valueChanges) { #ifdef QUICK3D_MODULE @@ -1184,7 +1209,10 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView(const Reques } else { QMetaObject::invokeMethod( m_modelNode3DImageViewData.rootItem, "createViewForObject", - Q_ARG(QVariant, objectToVariant(instanceObj))); + Q_ARG(QVariant, objectToVariant(instanceObj)), + Q_ARG(QVariant, m_materialPreviewData.env), + Q_ARG(QVariant, m_materialPreviewData.envValue), + Q_ARG(QVariant, m_materialPreviewData.model)); } // Need to render twice, first render updates spatial nodes @@ -2027,6 +2055,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com if (ViewConfig::isQuick3DMode()) { setup3DEditView(instanceList, command); updateRotationBlocks(command.auxiliaryChanges); + updateMaterialPreviewData(command.auxiliaryChanges); } QObject::connect(&m_renderModelNodeImageViewTimer, &QTimer::timeout, @@ -2431,6 +2460,7 @@ void Qt5InformationNodeInstanceServer::requestModelNodePreviewImage(const Reques void Qt5InformationNodeInstanceServer::changeAuxiliaryValues(const ChangeAuxiliaryCommand &command) { updateRotationBlocks(command.auxiliaryChanges); + updateMaterialPreviewData(command.auxiliaryChanges); Qt5NodeInstanceServer::changeAuxiliaryValues(command); render3DEditView(); } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index f3448de4add..ea104442a6e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -145,6 +145,7 @@ private: void updateLockedAndHiddenStates(const QSet &instances); void handleInputEvents(); void resolveImportSupport(); + void updateMaterialPreviewData(const QVector &valueChanges); void updateRotationBlocks(const QVector &valueChanges); void removeRotationBlocks(const QVector &instanceIds); @@ -191,6 +192,13 @@ private: QObject *m_3dHelper = nullptr; int m_need3DEditViewRender = 0; QSet m_dynamicObjectConstructors; + + struct PreviewData { + QString env; + QString envValue; + QString model; + }; + PreviewData m_materialPreviewData; }; } // namespace QmlDesigner diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml index a9e272b6d51..50b5ce6a7e8 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml @@ -33,6 +33,12 @@ PropertyEditorPane { id: root signal toolBarAction(int action) + signal previewEnvChanged(string env) + signal previewModelChanged(string model) + + // Called from C++, dummy methods to avoid warnings + function closeContextMenu() {} + function initPreviewData(env, model) {} Column { id: col diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml index cfc037bc24f..67b5042c492 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml @@ -31,6 +31,8 @@ PropertyEditorPane { id: itemPane signal toolBarAction(int action) + signal previewEnvChanged(string env) + signal previewModelChanged(string model) // invoked from C++ to refresh material preview image function refreshPreview() @@ -38,10 +40,25 @@ PropertyEditorPane { topSection.refreshPreview() } + // Called also from C++ to close context menu on focus out + function closeContextMenu() + { + topSection.closeContextMenu() + } + + // Called from C++ to initialize preview menu checkmarks + function initPreviewData(env, model) + { + topSection.previewEnv = env; + topSection.previewModel = model + } + MaterialEditorTopSection { id: topSection onToolBarAction: (action) => itemPane.toolBarAction(action) + onPreviewEnvChanged: itemPane.previewEnvChanged(previewEnv) + onPreviewModelChanged: itemPane.previewModelChanged(previewModel) } Item { width: 1; height: 10 } diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml index 2e21d5814ac..0a5bcfab0d9 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml @@ -29,6 +29,7 @@ import QtQuick.Layouts 1.15 import QtQuickDesignerTheme 1.0 import QtQuick.Templates 2.15 as T import HelperWidgets 2.0 +import StudioControls 1.0 as StudioControls import StudioTheme 1.0 as StudioTheme Column { @@ -36,12 +37,22 @@ Column { signal toolBarAction(int action) + property string previewEnv + property string previewModel + function refreshPreview() { materialPreview.source = "" materialPreview.source = "image://materialEditor/preview" } + // Called from C++ to close context menu on focus out + function closeContextMenu() + { + modelMenu.close() + envMenu.close() + } + anchors.left: parent.left anchors.right: parent.right @@ -53,20 +64,135 @@ Column { Item { width: 1; height: 10 } // spacer - Rectangle { - width: 152 - height: 152 - color: "#000000" - anchors.horizontalCenter: parent.horizontalCenter - Image { - id: materialPreview - width: 150 - height: 150 - anchors.centerIn: parent - source: "image://materialEditor/preview" - cache: false + StudioControls.Menu { + id: modelMenu + closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside + + ListModel { + id: modelMenuModel + ListElement { + modelName: qsTr("Cone") + modelStr: "#Cone" + } + ListElement { + modelName: qsTr("Cube") + modelStr: "#Cube" + } + ListElement { + modelName: qsTr("Cylinder") + modelStr: "#Cylinder" + } + ListElement { + modelName: qsTr("Sphere") + modelStr: "#Sphere" + } } + + Repeater { + model: modelMenuModel + StudioControls.MenuItemWithIcon { + text: modelName + onClicked: { + // Force property change notifications to keep check mark when reselected + root.previewModel = "" + root.previewModel = modelStr + } + checkable: true + checked: root.previewModel === modelStr + } + } + } + + StudioControls.Menu { + id: envMenu + closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside + + ListModel { + id: envMenuModel + ListElement { + envName: qsTr("Default") + envStr: "Default" + } + ListElement { + envName: qsTr("Color") + envStr: "Color" + } + ListElement { + envName: qsTr("Studio") + envStr: "SkyBox=preview_studio" + } + ListElement { + envName: qsTr("Landscape") + envStr: "SkyBox=preview_landscape" + } + } + + Repeater { + model: envMenuModel + StudioControls.MenuItemWithIcon { + text: envName + onClicked: { + // Force property change notifications to keep check mark when reselected + root.previewEnv = "" + root.previewEnv = envStr + } + checkable: true + checked: root.previewEnv === envStr + } + } + } + + Item { + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + height: previewRect.height + + Rectangle { + id: previewRect + anchors.horizontalCenter: parent.horizontalCenter + width: 152 + height: 152 + color: "#000000" + + Image { + id: materialPreview + width: 150 + height: 150 + anchors.centerIn: parent + source: "image://materialEditor/preview" + cache: false + } + } + + Item { + id: previewOptions + width: 40 + height: previewRect.height + anchors.top: previewRect.top + anchors.left: previewRect.right + + Column { + anchors.horizontalCenter: parent.horizontalCenter + IconButton { + icon: StudioTheme.Constants.materialPreviewEnvironment + normalColor: "transparent" + iconSize: StudioTheme.Values.bigIconFontSize + buttonSize: previewOptions.width + tooltip: qsTr("Select preview environment.") + onClicked: envMenu.popup() + } + IconButton { + icon: StudioTheme.Constants.materialPreviewModel + normalColor: "transparent" + iconSize: StudioTheme.Values.bigIconFontSize + buttonSize: previewOptions.width + tooltip: qsTr("Select preview model.") + onClicked: modelMenu.popup() + } + } + } + } Section { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml index 5972e56e04c..46b3679198c 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml @@ -122,72 +122,74 @@ QtObject { readonly property string listView: "\u0075" readonly property string lockOff: "\u0076" readonly property string lockOn: "\u0077" - readonly property string mergeCells: "\u0078" - readonly property string minus: "\u0079" - readonly property string mirror: "\u007A" - readonly property string newMaterial: "\u007B" - readonly property string openMaterialBrowser: "\u007C" - readonly property string orientation: "\u007D" - readonly property string paddingEdge: "\u007E" - readonly property string paddingFrame: "\u007F" - readonly property string pasteStyle: "\u0080" - readonly property string pause: "\u0081" - readonly property string pin: "\u0082" - readonly property string play: "\u0083" - readonly property string plus: "\u0084" - readonly property string promote: "\u0085" - readonly property string readOnly: "\u0086" - readonly property string redo: "\u0087" - readonly property string rotationFill: "\u0088" - readonly property string rotationOutline: "\u0089" - readonly property string search: "\u008A" - readonly property string sectionToggle: "\u008B" - readonly property string splitColumns: "\u008C" - readonly property string splitRows: "\u008D" - readonly property string startNode: "\u008E" - readonly property string testIcon: "\u008F" - readonly property string textAlignBottom: "\u0090" - readonly property string textAlignCenter: "\u0091" - readonly property string textAlignJustified: "\u0092" - readonly property string textAlignLeft: "\u0093" - readonly property string textAlignMiddle: "\u0094" - readonly property string textAlignRight: "\u0095" - readonly property string textAlignTop: "\u0096" - readonly property string textBulletList: "\u0097" - readonly property string textFullJustification: "\u0098" - readonly property string textNumberedList: "\u0099" - readonly property string tickIcon: "\u009A" - readonly property string translationCreateFiles: "\u009B" - readonly property string translationCreateReport: "\u009D" - readonly property string translationExport: "\u009E" - readonly property string translationImport: "\u009F" - readonly property string translationSelectLanguages: "\u00A0" - readonly property string translationTest: "\u00A1" - readonly property string transparent: "\u00A2" - readonly property string triState: "\u00A3" - readonly property string triangleArcA: "\u00A4" - readonly property string triangleArcB: "\u00A5" - readonly property string triangleCornerA: "\u00A6" - readonly property string triangleCornerB: "\u00A7" - readonly property string unLinked: "\u00A8" - readonly property string undo: "\u00A9" - readonly property string unpin: "\u00AA" - readonly property string upDownIcon: "\u00AB" - readonly property string upDownSquare2: "\u00AC" - readonly property string visibilityOff: "\u00AE" - readonly property string visibilityOn: "\u00AF" - readonly property string wildcard: "\u00B0" - readonly property string wizardsAutomotive: "\u00B1" - readonly property string wizardsDesktop: "\u00B2" - readonly property string wizardsGeneric: "\u00B3" - readonly property string wizardsMcuEmpty: "\u00B4" - readonly property string wizardsMcuGraph: "\u00B5" - readonly property string wizardsMobile: "\u00B6" - readonly property string wizardsUnknown: "\u00B7" - readonly property string zoomAll: "\u00B8" - readonly property string zoomIn: "\u00B9" - readonly property string zoomOut: "\u00BA" - readonly property string zoomSelection: "\u00BB" + readonly property string materialPreviewEnvironment: "\u0078" + readonly property string materialPreviewModel: "\u0079" + readonly property string mergeCells: "\u007A" + readonly property string minus: "\u007B" + readonly property string mirror: "\u007C" + readonly property string newMaterial: "\u007D" + readonly property string openMaterialBrowser: "\u007E" + readonly property string orientation: "\u007F" + readonly property string paddingEdge: "\u0080" + readonly property string paddingFrame: "\u0081" + readonly property string pasteStyle: "\u0082" + readonly property string pause: "\u0083" + readonly property string pin: "\u0084" + readonly property string play: "\u0085" + readonly property string plus: "\u0086" + readonly property string promote: "\u0087" + readonly property string readOnly: "\u0088" + readonly property string redo: "\u0089" + readonly property string rotationFill: "\u008A" + readonly property string rotationOutline: "\u008B" + readonly property string search: "\u008C" + readonly property string sectionToggle: "\u008D" + readonly property string splitColumns: "\u008E" + readonly property string splitRows: "\u008F" + readonly property string startNode: "\u0090" + readonly property string testIcon: "\u0091" + readonly property string textAlignBottom: "\u0092" + readonly property string textAlignCenter: "\u0093" + readonly property string textAlignJustified: "\u0094" + readonly property string textAlignLeft: "\u0095" + readonly property string textAlignMiddle: "\u0096" + readonly property string textAlignRight: "\u0097" + readonly property string textAlignTop: "\u0098" + readonly property string textBulletList: "\u0099" + readonly property string textFullJustification: "\u009A" + readonly property string textNumberedList: "\u009B" + readonly property string tickIcon: "\u009D" + readonly property string translationCreateFiles: "\u009E" + readonly property string translationCreateReport: "\u009F" + readonly property string translationExport: "\u00A0" + readonly property string translationImport: "\u00A1" + readonly property string translationSelectLanguages: "\u00A2" + readonly property string translationTest: "\u00A3" + readonly property string transparent: "\u00A4" + readonly property string triState: "\u00A5" + readonly property string triangleArcA: "\u00A6" + readonly property string triangleArcB: "\u00A7" + readonly property string triangleCornerA: "\u00A8" + readonly property string triangleCornerB: "\u00A9" + readonly property string unLinked: "\u00AA" + readonly property string undo: "\u00AB" + readonly property string unpin: "\u00AC" + readonly property string upDownIcon: "\u00AE" + readonly property string upDownSquare2: "\u00AF" + readonly property string visibilityOff: "\u00B0" + readonly property string visibilityOn: "\u00B1" + readonly property string wildcard: "\u00B2" + readonly property string wizardsAutomotive: "\u00B3" + readonly property string wizardsDesktop: "\u00B4" + readonly property string wizardsGeneric: "\u00B5" + readonly property string wizardsMcuEmpty: "\u00B6" + readonly property string wizardsMcuGraph: "\u00B7" + readonly property string wizardsMobile: "\u00B8" + readonly property string wizardsUnknown: "\u00B9" + readonly property string zoomAll: "\u00BA" + readonly property string zoomIn: "\u00BB" + readonly property string zoomOut: "\u00BC" + readonly property string zoomSelection: "\u00BD" readonly property font iconFont: Qt.font({ "family": controlIcons.name, diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index cefd1d7d86696ac13a11199df9b1203d65947b94..934c22110e583bd6408d542f41a8fb6f1e9708ba 100644 GIT binary patch delta 5380 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 Yq~>gn3C~~=x##m1G-il2_BVG200QS14*&oF delta 5209 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.first()); if (idx != -1) m_widget->materialBrowserModel()->selectMaterial(idx); + } else if (identifier == "refresh_material_browser") { + QTimer::singleShot(0, this, [this]() { + refreshModel(true); + }); } } diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 974435b5104..c0b766648b6 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -62,6 +62,7 @@ #include #include #include +#include namespace QmlDesigner { @@ -442,6 +443,90 @@ void MaterialEditorView::handleToolBarAction(int action) } } +void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue) +{ + if (envAndValue.isEmpty()) + return; + + QTC_ASSERT(m_hasQuick3DImport, return); + QTC_ASSERT(model(), return); + QTC_ASSERT(model()->nodeInstanceView(), return); + + QStringList parts = envAndValue.split('='); + QString env = parts[0]; + QString value; + if (parts.size() > 1) + value = parts[1]; + + PropertyName matPrevEnvAuxProp("matPrevEnv"); + PropertyName matPrevEnvValueAuxProp("matPrevEnvValue"); + + auto renderPreviews = [=](const QString &auxEnv, const QString &auxValue) { + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + QTC_ASSERT(matLib.isValid(), return); + matLib.setAuxiliaryData(matPrevEnvAuxProp, auxEnv); + matLib.setAuxiliaryData(matPrevEnvValueAuxProp, auxValue); + QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender); + emitCustomNotification("refresh_material_browser", {}); + }; + + if (env == "Color") { + m_colorDialog.clear(); + + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + QTC_ASSERT(matLib.isValid(), return); + // Store color to separate property to persist selection over non-color env changes + PropertyName colorAuxProp("matPrevColor"); + QString oldColor = matLib.auxiliaryData(colorAuxProp).toString(); + QString oldEnv = matLib.auxiliaryData(matPrevEnvAuxProp).toString(); + QString oldValue = matLib.auxiliaryData(matPrevEnvValueAuxProp).toString(); + + m_colorDialog = new QColorDialog(Core::ICore::dialogParent()); + m_colorDialog->setModal(true); + m_colorDialog->setAttribute(Qt::WA_DeleteOnClose); + m_colorDialog->setCurrentColor(QColor(oldColor)); + m_colorDialog->show(); + + QObject::connect(m_colorDialog, &QColorDialog::currentColorChanged, + m_colorDialog, [=](const QColor &color) { + renderPreviews(env, color.name()); + }); + + QObject::connect(m_colorDialog, &QColorDialog::colorSelected, + m_colorDialog, [=](const QColor &color) { + renderPreviews(env, color.name()); + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + QTC_ASSERT(matLib.isValid(), return); + matLib.setAuxiliaryData(colorAuxProp, color.name()); + }); + + QObject::connect(m_colorDialog, &QColorDialog::rejected, + m_colorDialog, [=]() { + renderPreviews(oldEnv, oldValue); + initPreviewData(); + }); + return; + } + renderPreviews(env, value); +} + +void MaterialEditorView::handlePreviewModelChanged(const QString &modelStr) +{ + if (modelStr.isEmpty()) + return; + + QTC_ASSERT(m_hasQuick3DImport, return); + QTC_ASSERT(model(), return); + QTC_ASSERT(model()->nodeInstanceView(), return); + + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + QTC_ASSERT(matLib.isValid(), return); + matLib.setAuxiliaryData("matPrevModel", modelStr); + + QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender); + emitCustomNotification("refresh_material_browser", {}); +} + void MaterialEditorView::setupQmlBackend() { QUrl qmlPaneUrl; @@ -472,17 +557,24 @@ void MaterialEditorView::setupQmlBackend() currentQmlBackend->setSource(qmlPaneUrl); - QObject::connect(currentQmlBackend->widget()->rootObject(), SIGNAL(toolBarAction(int)), + QObject *rootObj = currentQmlBackend->widget()->rootObject(); + QObject::connect(rootObj, SIGNAL(toolBarAction(int)), this, SLOT(handleToolBarAction(int))); + QObject::connect(rootObj, SIGNAL(previewEnvChanged(QString)), + this, SLOT(handlePreviewEnvChanged(QString))); + QObject::connect(rootObj, SIGNAL(previewModelChanged(QString)), + this, SLOT(handlePreviewModelChanged(QString))); } else { currentQmlBackend->setup(m_selectedMaterial, currentStateName, qmlSpecificsUrl, this); } + currentQmlBackend->widget()->installEventFilter(this); currentQmlBackend->contextObject()->setHasQuick3DImport(m_hasQuick3DImport); m_stackedWidget->setCurrentWidget(currentQmlBackend->widget()); m_qmlBackEnd = currentQmlBackend; + initPreviewData(); } void MaterialEditorView::commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value) @@ -528,6 +620,29 @@ bool MaterialEditorView::noValidSelection() const return !QmlObjectNode::isValidQmlObjectNode(m_selectedMaterial); } +void MaterialEditorView::initPreviewData() +{ + if (model() && m_qmlBackEnd) { + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + if (matLib.isValid()) { + QString env = matLib.auxiliaryData("matPrevEnv").toString(); + QString envValue = matLib.auxiliaryData("matPrevEnvValue").toString(); + QString modelStr = matLib.auxiliaryData("matPrevModel").toString(); + if (!envValue.isEmpty() && env != "Color" && env != "Default") { + env += '='; + env += envValue; + } + if (env.isEmpty()) + env = "Default"; + if (modelStr.isEmpty()) + modelStr = "#Sphere"; + QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(), + "initPreviewData", + Q_ARG(QVariant, env), Q_ARG(QVariant, modelStr)); + } + } +} + void MaterialEditorView::modelAttached(Model *model) { AbstractView::modelAttached(model); @@ -844,6 +959,15 @@ void MaterialEditorView::setValue(const QmlObjectNode &qmlObjectNode, const Prop m_locked = false; } +bool MaterialEditorView::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::FocusOut) { + if (m_qmlBackEnd && m_qmlBackEnd->widget() == obj) + QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(), "closeContextMenu"); + } + return QObject::eventFilter(obj, event); +} + void MaterialEditorView::reloadQml() { m_qmlBackendHash.clear(); diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index ff734ed30b8..1c52be87cfa 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -27,12 +27,14 @@ #include #include +#include #include QT_BEGIN_NAMESPACE class QShortcut; class QStackedWidget; class QTimer; +class QColorDialog; QT_END_NAMESPACE namespace QmlDesigner { @@ -87,10 +89,13 @@ public: public slots: void handleToolBarAction(int action); + void handlePreviewEnvChanged(const QString &envAndValue); + void handlePreviewModelChanged(const QString &modelStr); protected: void timerEvent(QTimerEvent *event) override; void setValue(const QmlObjectNode &fxObjectNode, const PropertyName &name, const QVariant &value); + bool eventFilter(QObject *obj, QEvent *event) override; private: static QString materialEditorResourcesPath(); @@ -113,6 +118,8 @@ private: bool noValidSelection() const; + void initPreviewData(); + ModelNode m_selectedMaterial; QTimer m_ensureMatLibTimer; QShortcut *m_updateShortcut = nullptr; @@ -124,6 +131,8 @@ private: bool m_locked = false; bool m_setupCompleted = false; bool m_hasQuick3DImport = false; + + QPointer m_colorDialog; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 4522c14a54f..e84f9224d61 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -660,7 +660,8 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node, const QVariant &value) { QTC_ASSERT(m_nodeInstanceServer, return); - const bool forceAuxChange = name == "invisible" || name == "locked" || name == "rotBlocked@Internal"; + const bool forceAuxChange = name == "invisible" || name == "locked" + || name == "rotBlocked@Internal" || name.startsWith("matPrev"); if (((node.isRootNode() && (name == "width" || name == "height")) || forceAuxChange) || name.endsWith(PropertyName("@NodeInstance"))) { if (hasInstanceForModelNode(node)) { From 675e63e658f82d1922e2a5bb45469d946f859047 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 22 Jul 2022 15:26:47 +0200 Subject: [PATCH 14/43] QmlDesigner: Prepare States Editor for States not in the root node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I612de64447f04a041aa20b1ebc02c7fb6049eb03 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Henning Gründl --- .../stateseditor/stateseditormodel.cpp | 6 +-- .../stateseditor/stateseditorview.cpp | 42 +++++++++++++------ .../stateseditor/stateseditorview.h | 7 +++- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp index 2d96d01a9dc..0d8d39936bd 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp @@ -65,7 +65,7 @@ QModelIndex StatesEditorModel::index(int row, int column, const QModelIndex &par int internalNodeId = 0; if (row > 0 && row < rowCount() - 1) // first and last rows are base state, add state - internalNodeId = m_statesEditorView->rootModelNode().nodeListProperty("states").at(row - 1).internalId(); + internalNodeId = m_statesEditorView->acitveStatesGroupNode().nodeListProperty("states").at(row - 1).internalId(); return hasIndex(row, column, parent) ? createIndex(row, column, internalNodeId) : QModelIndex(); } @@ -75,10 +75,10 @@ int StatesEditorModel::rowCount(const QModelIndex &parent) const if (parent.isValid() || m_statesEditorView.isNull() || !m_statesEditorView->model()) return 0; - if (!m_statesEditorView->rootModelNode().hasNodeListProperty("states")) + if (!m_statesEditorView->acitveStatesGroupNode().hasNodeListProperty("states")) return 2; // base state + add new state - return m_statesEditorView->rootModelNode().nodeListProperty("states").count() + 2; // 2 = base state + add new state + return m_statesEditorView->acitveStatesGroupNode().nodeListProperty("states").count() + 2; // 2 = base state + add new state } void StatesEditorModel::reset() diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp index e9de5defb29..eefde504948 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp @@ -85,6 +85,20 @@ void StatesEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorV checkForStatesAvailability(); } +ModelNode StatesEditorView::acitveStatesGroupNode() const +{ + return m_activeStatesGroupNode; +} + +void StatesEditorView::setAcitveStatesGroupNode(const ModelNode &modelNode) +{ + if (m_activeStatesGroupNode == modelNode) + return; + + m_activeStatesGroupNode = modelNode; + resetModel(); +} + void StatesEditorView::removeState(int nodeId) { try { @@ -193,12 +207,12 @@ void StatesEditorView::createNewState() void StatesEditorView::addState() { // can happen when root node is e.g. a ListModel - if (!QmlVisualNode::isValidQmlVisualNode(rootModelNode())) + if (!QmlVisualNode::isValidQmlVisualNode(acitveStatesGroupNode())) return; QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_STATE_ADDED); - QStringList modelStateNames = rootStateGroup().names(); + QStringList modelStateNames = activeStateGroup().names(); QString newStateName; int index = 1; @@ -209,9 +223,9 @@ void StatesEditorView::addState() } executeInTransaction("addState", [this, newStateName]() { - rootModelNode().validId(); + acitveStatesGroupNode().validId(); - ModelNode newState = rootStateGroup().addState(newStateName); + ModelNode newState = activeStateGroup().addState(newStateName); setCurrentState(newState); }); } @@ -244,7 +258,7 @@ void StatesEditorView::duplicateCurrentState() newName = newName.left(match.capturedStart()); int i = 1; - QStringList stateNames = rootStateGroup().names(); + QStringList stateNames = activeStateGroup().names(); while (stateNames.contains(newName + QString::number(i))) i++; const QString newStateName = newName + QString::number(i); @@ -258,7 +272,7 @@ void StatesEditorView::duplicateCurrentState() void StatesEditorView::checkForStatesAvailability() { if (m_statesEditorWidget) { - const bool isVisual = QmlVisualNode::isValidQmlVisualNode(rootModelNode()); + const bool isVisual = QmlVisualNode::isValidQmlVisualNode(acitveStatesGroupNode()); m_statesEditorWidget->showAddNewStatesButton(isVisual); } } @@ -277,16 +291,16 @@ QmlModelState StatesEditorView::baseState() const return QmlModelState::createBaseState(this); } -QmlModelStateGroup StatesEditorView::rootStateGroup() const +QmlModelStateGroup StatesEditorView::activeStateGroup() const { - return QmlModelStateGroup(rootModelNode()); + return QmlModelStateGroup(acitveStatesGroupNode()); } bool StatesEditorView::validStateName(const QString &name) const { if (name == tr("base state")) return false; - const QList modelStates = rootStateGroup().allStates(); + const QList modelStates = activeStateGroup().allStates(); for (const QmlModelState &state : modelStates) { if (state.name() == name) return false; @@ -392,8 +406,8 @@ void StatesEditorView::resetDefaultState() auto guard = qScopeGuard([&]() { m_block = false; }); try { - if (rootModelNode().hasProperty("state")) - rootModelNode().removeProperty("state"); + if (acitveStatesGroupNode().hasProperty("state")) + acitveStatesGroupNode().removeProperty("state"); } catch (const RewritingException &e) { e.showException(); @@ -402,7 +416,7 @@ void StatesEditorView::resetDefaultState() bool StatesEditorView::hasDefaultState() const { - return rootModelNode().hasProperty("state"); + return acitveStatesGroupNode().hasProperty("state"); } void StatesEditorView::setAnnotation(int internalNodeId) @@ -475,6 +489,8 @@ void StatesEditorView::modelAttached(Model *model) Q_ASSERT(model); AbstractView::modelAttached(model); + m_activeStatesGroupNode = rootModelNode(); + if (m_statesEditorWidget) m_statesEditorWidget->setNodeInstanceView(nodeInstanceView()); @@ -593,7 +609,7 @@ void StatesEditorView::instancesPreviewImageChanged(const QVector &no minimumIndex = qMin(minimumIndex, 0); maximumIndex = qMax(maximumIndex, 0); } else { - int index = rootStateGroup().allStates().indexOf(QmlModelState(node)) + 1; + int index = activeStateGroup().allStates().indexOf(QmlModelState(node)) + 1; if (index > 0) { minimumIndex = qMin(minimumIndex, index); maximumIndex = qMax(maximumIndex, index); diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h index 71a82711eaa..1ee8144a2bb 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h @@ -55,7 +55,7 @@ public: QString currentStateName() const; void setCurrentState(const QmlModelState &state); QmlModelState baseState() const; - QmlModelStateGroup rootStateGroup() const; + QmlModelStateGroup activeStateGroup() const; // AbstractView void modelAttached(Model *model) override; @@ -87,6 +87,10 @@ public: void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override; + ModelNode acitveStatesGroupNode() const; + void setAcitveStatesGroupNode(const ModelNode &modelNode); + + public slots: void synchonizeCurrentStateFromWidget(); void createNewState(); @@ -105,6 +109,7 @@ private: int m_lastIndex; bool m_block = false; QPointer m_editor; + ModelNode m_activeStatesGroupNode; }; } // namespace QmlDesigner From fea338c00040099b86bb26059330b18144b3a3fd Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Wed, 3 Aug 2022 13:19:05 +0200 Subject: [PATCH 15/43] Move keyframes horizontally when shift is pressed It is now possible to move keyframes in the curve editor in the x direction only by pressing shift while dragging. Fixes: QDS-6952 Change-Id: Ic1a25ec6d8dec82cf5599dccbaeff7e5f34d2936 Reviewed-by: Reviewed-by: Thomas Hartmann --- .../curveeditor/detail/keyframeitem.cpp | 27 ++++++++++++++++--- .../curveeditor/detail/keyframeitem.h | 5 +++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp index 49e76a09687..0dbb2d125f0 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp @@ -27,7 +27,10 @@ #include "curveitem.h" #include "handleitem.h" +#include #include +#include +#include #include @@ -453,10 +456,22 @@ QVariant KeyframeItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons lseg.moveRightTo(position); rseg.moveLeftTo(position); - if (legalLeft() && legalRight()) - m_validPos = position; + if (legalLeft() && legalRight()) { + if (qApp->keyboardModifiers().testFlag(Qt::ShiftModifier) && m_validPos.has_value()) { + if (m_firstPos) { + auto firstToNow = QLineF(*m_firstPos, position); + if (std::abs(firstToNow.dx()) > std::abs(firstToNow.dy())) + m_validPos = QPointF(position.x(), m_firstPos->y()); + else + m_validPos = QPointF(m_firstPos->x(), position.y()); + } - return QVariant(m_transform.map(m_validPos)); + } else { + m_validPos = position; + } + } + + return QVariant(m_transform.map(*m_validPos)); } } } @@ -466,6 +481,11 @@ QVariant KeyframeItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons void KeyframeItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + bool ok; + m_firstPos = m_transform.inverted(&ok).map(event->scenePos()); + if (!ok) + m_firstPos = Utils::nullopt; + SelectableItem::mousePressEvent(event); if (auto *curveItem = qgraphicsitem_cast(parentItem())) curveItem->setHandleVisibility(false); @@ -473,6 +493,7 @@ void KeyframeItem::mousePressEvent(QGraphicsSceneMouseEvent *event) void KeyframeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + m_firstPos = Utils::nullopt; SelectableItem::mouseReleaseEvent(event); if (auto *curveItem = qgraphicsitem_cast(parentItem())) curveItem->setHandleVisibility(true); diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h index 14c3ae74266..c7bfa02cd18 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h @@ -30,6 +30,8 @@ #include "keyframe.h" #include "selectableitem.h" +#include + #include namespace QmlDesigner { @@ -133,7 +135,8 @@ private: HandleItem *m_right; - QPointF m_validPos; + Utils::optional< QPointF > m_firstPos; + Utils::optional< QPointF > m_validPos; bool m_visibleOverride = true; From 305517f21289a649380dbf1e053a2b2f56c4153d Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Mon, 15 Aug 2022 15:53:39 +0200 Subject: [PATCH 16/43] QmlDesigner: Fix floating widgets on start up Task-number: QDS-7423 Change-Id: I273b8a3926b574f4ec61500b798bff578684cb1f Reviewed-by: Brook Cronin Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot --- src/plugins/qmldesigner/designmodewidget.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index 28d99003cae..c5c20a7f83f 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -390,19 +390,26 @@ void DesignModeWidget::setup() m_dockManager->initialize(); + // Hide all floating widgets if the initial mode isn't design mode + if (Core::ModeManager::instance()->currentModeId() != Core::Constants::MODE_DESIGN) { + for (auto &floatingWidget : m_dockManager->floatingWidgets()) + floatingWidget->hide(); + } + connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged, this, - [this](Utils::Id mode, Utils::Id oldMode) { + [this](Utils::Id mode, Utils::Id previousMode) { if (mode == Core::Constants::MODE_DESIGN) { m_dockManager->reloadActiveWorkspace(); m_dockManager->setModeChangeState(false); } - if (oldMode == Core::Constants::MODE_DESIGN && mode != Core::Constants::MODE_DESIGN) { + if (previousMode == Core::Constants::MODE_DESIGN + && mode != Core::Constants::MODE_DESIGN) { m_dockManager->save(); m_dockManager->setModeChangeState(true); - for (auto floatingWidget : m_dockManager->floatingWidgets()) + for (auto &floatingWidget : m_dockManager->floatingWidgets()) floatingWidget->hide(); } }); From 725c36e8d081144bc1834dc8e35a923773beb41c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 16 Aug 2022 10:46:21 +0200 Subject: [PATCH 17/43] CppEditor: Keep offering "Extract Function" after all As it turns out, there are some bugs in clangd that prevent this functionality from working in some circumstances. This effectively reverts 840263eb9a7687f2c0ecd9b0503d355fad5bac5e. Fixes: QTCREATORBUG-28030 Change-Id: I511eb9a5cc45e3fd5e3cc25898aebb493f1ba3d3 Reviewed-by: David Schulz Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/cppeditor/cppquickfixes.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 8469327414d..0f76dd8e53b 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -5243,10 +5243,12 @@ ExtractFunction::ExtractFunction(FunctionNameGetter functionNameGetter) void ExtractFunction::match(const CppQuickFixInterface &interface, QuickFixOperations &result) { const CppRefactoringFilePtr file = interface.currentFile(); - if (CppModelManager::usesClangd(file->editor()->textDocument()) - && file->cppDocument()->languageFeatures().cxxEnabled) { - return; - } + + // TODO: Fix upstream and uncomment; see QTCREATORBUG-28030. +// if (CppModelManager::usesClangd(file->editor()->textDocument()) +// && file->cppDocument()->languageFeatures().cxxEnabled) { +// return; +// } QTextCursor cursor = file->cursor(); if (!cursor.hasSelection()) From 9610698c66a170e04ad49c6d8c85ed3788df5afc Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Thu, 11 Aug 2022 11:23:13 +0200 Subject: [PATCH 18/43] Allow editing keyframe values for other types than double Currently, the setKeyframeValue dialog only supports a QDoubleSpinbox as value field. When using this dialog to edit keyframe values of different type, they need to be converted which fails for some types (QColor). With this patch the dialog creates a dedicated control for each value type. In case the type is not caught it falls back to the old behavior. Fixes: QDS-6949 Change-Id: Icbaa2af24f06418fa60648d23269f1a12c08f9de Reviewed-by: Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/CMakeLists.txt | 2 +- .../timelineeditor/setframevaluedialog.cpp | 142 +++++++++++++++--- .../timelineeditor/setframevaluedialog.h | 13 +- .../timelineeditor/setframevaluedialog.ui | 84 ----------- 4 files changed, 129 insertions(+), 112 deletions(-) delete mode 100644 src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.ui diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index ec0eaa65378..8b0081b1d89 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -497,7 +497,7 @@ extend_qtc_plugin(QmlDesigner easingcurve.cpp easingcurve.h easingcurvedialog.cpp easingcurvedialog.h preseteditor.cpp preseteditor.h - setframevaluedialog.cpp setframevaluedialog.h setframevaluedialog.ui + setframevaluedialog.cpp setframevaluedialog.h splineeditor.cpp splineeditor.h timeline.qrc timelineabstracttool.cpp timelineabstracttool.h diff --git a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp index ad4d02df891..1bf437e802a 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp @@ -24,47 +24,147 @@ ****************************************************************************/ #include "setframevaluedialog.h" -#include "ui_setframevaluedialog.h" +#include "curveeditor/detail/colorcontrol.h" -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include namespace QmlDesigner { SetFrameValueDialog::SetFrameValueDialog(qreal frame, const QVariant &value, const QString &propertyName, QWidget *parent) - : QDialog(parent) - , ui(new Ui::SetFrameValueDialog) + : QDialog(parent, Qt::Tool) + , m_valueGetter() + , m_valueType(value.metaType()) + , m_frameControl(new QSpinBox) { - ui->setupUi(this); setWindowTitle(tr("Edit Keyframe")); - setFixedSize(size()); - ui->lineEditFrame->setValidator(new QIntValidator(0, 99999, this)); - auto dv = new QDoubleValidator(this); - dv->setDecimals(2); - ui->lineEditValue->setValidator(dv); + auto frameLabelString = QString(tr("Frame")); + auto labelWidth = fontMetrics().boundingRect(frameLabelString).width(); + if (auto tmp = fontMetrics().boundingRect(propertyName).width(); tmp > labelWidth) + labelWidth = tmp; - QLocale l; - ui->lineEditFrame->setText(l.toString(qRound(frame))); - ui->lineEditValue->setText(l.toString(value.toDouble(), 'f', 2)); - ui->labelValue->setText(propertyName); + auto *frameLabel = new QLabel(frameLabelString); + frameLabel->setAlignment(Qt::AlignRight); + frameLabel->setFixedWidth(labelWidth); + + auto *valueLabel = new QLabel(propertyName); + valueLabel->setAlignment(Qt::AlignRight); + valueLabel->setFixedWidth(labelWidth); + + m_frameControl->setRange(std::numeric_limits::min(), std::numeric_limits::max()); + m_frameControl->setValue(static_cast(frame)); + m_frameControl->setAlignment(Qt::AlignRight); + + auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); + + auto* frameRow = new QHBoxLayout; + frameRow->addWidget(frameLabel); + frameRow->addWidget(m_frameControl); + + auto* valueRow = new QHBoxLayout; + valueRow->addWidget(valueLabel); + valueRow->addWidget(createValueControl(value)); + + auto* hbox = new QVBoxLayout; + hbox->addLayout(frameRow); + hbox->addLayout(valueRow); + hbox->addStretch(); + hbox->addWidget(buttons); + + setLayout(hbox); } SetFrameValueDialog::~SetFrameValueDialog() -{ - delete ui; -} +{ } qreal SetFrameValueDialog::frame() const { - QLocale l; - return l.toDouble(ui->lineEditFrame->text()); + return static_cast(m_frameControl->value()); } QVariant SetFrameValueDialog::value() const { - QLocale l; - return QVariant(l.toDouble(ui->lineEditValue->text())); + if (m_valueGetter) + return m_valueGetter(); + return QVariant(m_valueType); +} + +QWidget* SetFrameValueDialog::createValueControl(const QVariant& value) +{ + m_valueType = value.metaType(); + + switch (value.metaType().id()) + { + + case QMetaType::QColor: { + auto* widget = new StyleEditor::ColorControl(value.value()); + m_valueGetter = [widget]() { return widget->value(); }; + return widget; + } + + case QMetaType::Bool: { + auto* widget = new QCheckBox; + widget->setChecked(value.toBool()); + m_valueGetter = [widget]() { return widget->isChecked(); }; + return widget; + } + + case QMetaType::Int: { + auto* widget = new QSpinBox; + widget->setRange(std::numeric_limits::min(), std::numeric_limits::max()); + widget->setAlignment(Qt::AlignRight); + widget->setValue(value.toInt()); + m_valueGetter = [widget]() { return widget->value(); }; + return widget; + } + + case QMetaType::UInt: { + auto* widget = new QSpinBox; + widget->setRange(0, std::numeric_limits::max()); + widget->setAlignment(Qt::AlignRight); + widget->setValue(value.toUInt()); + m_valueGetter = [widget]() { return static_cast(widget->value()); }; + return widget; + } + + case QMetaType::Float: { + auto* widget = new QDoubleSpinBox; + widget->setRange(std::numeric_limits::min(), std::numeric_limits::max()); + widget->setAlignment(Qt::AlignRight); + widget->setValue(value.toFloat()); + m_valueGetter = [widget]() { return static_cast(widget->value()); }; + return widget; + } + + case QMetaType::Double: + [[fallthrough]]; + + default: { + auto* widget = new QDoubleSpinBox; + widget->setRange(std::numeric_limits::min(), std::numeric_limits::max()); + widget->setAlignment(Qt::AlignRight); + widget->setValue(value.toDouble()); + m_valueGetter = [widget]() { return widget->value(); }; + return widget; + } + + } + + m_valueGetter = nullptr; + return nullptr; } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.h b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.h index 799e3fadc52..e2ca6e39010 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.h +++ b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.h @@ -27,14 +27,10 @@ #include -QT_FORWARD_DECLARE_CLASS(QLineEdit) +QT_FORWARD_DECLARE_CLASS(QSpinBox) namespace QmlDesigner { -namespace Ui { -class SetFrameValueDialog; -} - class SetFrameValueDialog : public QDialog { Q_OBJECT @@ -48,7 +44,12 @@ public: QVariant value() const; private: - Ui::SetFrameValueDialog *ui; + QWidget* createValueControl(const QVariant& value); + + std::function m_valueGetter; + + QMetaType m_valueType; + QSpinBox *m_frameControl; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.ui b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.ui deleted file mode 100644 index 8a3ba3c99cb..00000000000 --- a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.ui +++ /dev/null @@ -1,84 +0,0 @@ - - - QmlDesigner::SetFrameValueDialog - - - - 0 - 0 - 212 - 148 - - - - Dialog - - - - - - Frame - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - - - Value - - - - - - - - - buttonBox - accepted() - QmlDesigner::SetFrameValueDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - QmlDesigner::SetFrameValueDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - From f31638c8561b268c99290e35cc400a81dc657393 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 16 Aug 2022 08:46:53 +0200 Subject: [PATCH 19/43] QmlDesigner: Allow Timer in ui.qml files Change-Id: I0fbf7270f8514b212fab5aae89d2def11d6b53bd Reviewed-by: Reviewed-by: Thomas Hartmann --- src/libs/qmljs/qmljscheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index a0f54fd84bc..dbb0962d0cf 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -612,7 +612,7 @@ class UnsupportedTypesByVisualDesigner : public QStringList { public: UnsupportedTypesByVisualDesigner() - : QStringList({"Timer", "Package", "Particles", "ApplicationWindow"}) + : QStringList({"Package", "Particles", "ApplicationWindow"}) {} }; From 96d0f86552c7dca07089745394174b6880f85689 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 15 Aug 2022 16:31:39 +0200 Subject: [PATCH 20/43] QmlDesigner: Do not throw exception in meta info proxy case If there is a metaInfoProxyModel the version numbers will be different. (e.g. 6.3 im the document has a 6.3 import and 2.0 from the template). This is no problem and we can ignore this case. The check is supposed to be removed anyway. Task-number: QDS-7350 Change-Id: I780fc7d4b744e298bc8f3b991e75f642a4e8ae8a Reviewed-by: Qt CI Bot Reviewed-by: Miikka Heikkinen Reviewed-by: Reviewed-by: Thomas Hartmann --- .../qmldesigner/designercore/model/texttomodelmerger.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 86996baf363..6767bc11d56 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -524,13 +524,14 @@ public: && metaInfo.majorVersion() == majorVersion && metaInfo.minorVersion() == minorVersion; + if (!ok) { qDebug() << Q_FUNC_INFO; qDebug() << astTypeNode->name.toString() << typeName; qDebug() << metaInfo.isValid() << metaInfo.typeName(); qDebug() << metaInfo.directSuperClass().typeName(); - if (!typeName.startsWith("...")) + if (!typeName.startsWith("...") && m_model == m_model->metaInfoProxyModel()) throw RewritingException(__LINE__, __FUNCTION__, __FILE__, "test", "test"); } From 43bf516d1052b7bcba72e5b0d6ae33352040c2f4 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 22 Jul 2022 15:23:04 +0200 Subject: [PATCH 21/43] QmlDesigner: Catch exception that leaves the notifer No exception should ever leave the view and it should be caught locally. If this still happens we should catch it and show an error message. Otherwise we risk throwing a second exception when rewinding, if the changes came from the text editor. Catching and showing an error message should never do harm. Change-Id: If275ed1179e4fa4245fef3df4dbc8d144a1588d3 Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/designercore/model/model.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 5fd4dece8d4..d2277dec3ae 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -406,8 +406,12 @@ void ModelPrivate::notifyNodeInstanceViewLast(Callable call) } for (const QPointer &view : enabledViews()) { - if (!view->isBlockingNotifications()) - call(view.data()); + try { + if (!view->isBlockingNotifications()) + call(view.data()); + } catch (const Exception &e) { + e.showException(tr("Exception thrown by view %1.").arg(view->widgetInfo().tabName)); + } } if (nodeInstanceView() && !nodeInstanceView()->isBlockingNotifications()) From b2567b5e1dfee443183da8de5f5ce0169f2697df Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 17 Aug 2022 09:24:52 +0200 Subject: [PATCH 22/43] QmlDesigner: Do not throw if metainfo is invalid Task-number: QDS-7348 Change-Id: I96433369ad0e013d4fa62df297ade16084f8bc6a Reviewed-by: Thomas Hartmann --- .../qmldesigner/designercore/model/texttomodelmerger.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 6767bc11d56..00f3926a5b7 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -531,7 +531,8 @@ public: qDebug() << metaInfo.isValid() << metaInfo.typeName(); qDebug() << metaInfo.directSuperClass().typeName(); - if (!typeName.startsWith("...") && m_model == m_model->metaInfoProxyModel()) + if (!typeName.startsWith("...") && m_model == m_model->metaInfoProxyModel() + && metaInfo.isValid()) throw RewritingException(__LINE__, __FUNCTION__, __FILE__, "test", "test"); } From 5f41c09eb0fa56441cfc1d6714b1070b32452a71 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Mon, 15 Aug 2022 17:12:57 +0200 Subject: [PATCH 23/43] QmlDesigner: Fix Qt Advanced Docking System Fix an issue with a wrong QWidget background rendering when dragging a dock widget across a floating dock widgets border. Task-number: QDS-7425 Change-Id: I018cc224a6316a0327cb1806512b6aa6a75d88a3 Reviewed-by: Thomas Hartmann --- src/libs/advanceddockingsystem/dockoverlay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/advanceddockingsystem/dockoverlay.cpp b/src/libs/advanceddockingsystem/dockoverlay.cpp index f98c3fbd5ff..046e02dcb81 100644 --- a/src/libs/advanceddockingsystem/dockoverlay.cpp +++ b/src/libs/advanceddockingsystem/dockoverlay.cpp @@ -421,6 +421,7 @@ namespace ADS { d->m_lastLocation = InvalidDockWidgetArea; // Move it over the target. + hide(); resize(target->size()); QPoint topLeft = target->mapToGlobal(target->rect().topLeft()); move(topLeft); From 073693bab3dc95a39dcb8ca4174c41b8d8f762d0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 17 Aug 2022 13:11:25 +0200 Subject: [PATCH 24/43] QmlDesigner: Fix heck in syncSignalDeclarationProperty Change-Id: Ifa5d5ef6000a6a8a7eb6210cece43a09b6e42361 Reviewed-by: Marco Bubke Reviewed-by: Reviewed-by: Qt CI Bot --- .../qmldesigner/designercore/model/texttomodelmerger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 00f3926a5b7..6e7884fca29 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -1712,7 +1712,7 @@ void TextToModelMerger::syncSignalDeclarationProperty(AbstractProperty &modelPro const QString &signature, DifferenceHandler &differenceHandler) { - if (modelProperty.isSignalHandlerProperty()) { + if (modelProperty.isSignalDeclarationProperty()) { SignalDeclarationProperty signalHandlerProperty = modelProperty.toSignalDeclarationProperty(); if (signalHandlerProperty.signature() != signature) differenceHandler.signalDeclarationSignatureDiffer(signalHandlerProperty, signature); From 831e118b33a04229b6651311b67202784ebb2fa7 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 17 Aug 2022 10:16:08 +0200 Subject: [PATCH 25/43] QmlDesigner: Do not amend if rewriter view is not attached Task-number: QDS-7349 Change-Id: I6a4d1906ee6afea25e5dcc878f7f502456c6052b Reviewed-by: Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/designercore/model/rewriterview.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index d3c65a1e239..909c6483b1e 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -88,6 +88,7 @@ RewriterView::RewriterView(DifferenceHandling differenceHandling, QObject *paren m_textToModelMerger(new Internal::TextToModelMerger(this)) { m_amendTimer.setSingleShot(true); + m_amendTimer.setInterval(800); connect(&m_amendTimer, &QTimer::timeout, this, &RewriterView::amendQmlText); @@ -535,6 +536,10 @@ void RewriterView::applyChanges() void RewriterView::amendQmlText() { + + if (!model()->rewriterView()) + return; + emitCustomNotification(StartRewriterAmend); const QString newQmlText = m_textModifier->text(); From 01bb84b8087b4d0df65a8ca64a6e06162844cd8e Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 16 Aug 2022 21:19:41 +0300 Subject: [PATCH 26/43] QmlDesigner: Fix faulty color during IconButton hover animation Also removed hover animation from IconButton based on UX. Fixes: QDS-7432 Change-Id: Ic9b218a288cf30079844b93bbcaec30a9024ca79 Reviewed-by: Brook Cronin Reviewed-by: Reviewed-by: Thomas Hartmann --- .../materialEditorQmlSources/MaterialEditorToolBar.qml | 8 ++++---- .../materialEditorQmlSources/MaterialEditorTopSection.qml | 2 -- .../imports/HelperWidgets/IconButton.qml | 7 ------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml index 80a8d9abbe9..ba980340fe8 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml @@ -47,7 +47,7 @@ Rectangle { IconButton { icon: StudioTheme.Constants.applyMaterialToSelected - normalColor: "transparent" + normalColor: StudioTheme.Values.themeSectionHeadBackground iconSize: StudioTheme.Values.bigIconFontSize buttonSize: root.height enabled: hasMaterial && hasModelSelection && hasQuick3DImport @@ -58,7 +58,7 @@ Rectangle { IconButton { icon: StudioTheme.Constants.newMaterial - normalColor: "transparent" + normalColor: StudioTheme.Values.themeSectionHeadBackground iconSize: StudioTheme.Values.bigIconFontSize buttonSize: root.height enabled: hasQuick3DImport @@ -69,7 +69,7 @@ Rectangle { IconButton { icon: StudioTheme.Constants.deleteMaterial - normalColor: "transparent" + normalColor: StudioTheme.Values.themeSectionHeadBackground iconSize: StudioTheme.Values.bigIconFontSize buttonSize: root.height enabled: hasMaterial && hasQuick3DImport @@ -80,7 +80,7 @@ Rectangle { IconButton { icon: StudioTheme.Constants.openMaterialBrowser - normalColor: "transparent" + normalColor: StudioTheme.Values.themeSectionHeadBackground iconSize: StudioTheme.Values.bigIconFontSize buttonSize: root.height enabled: hasMaterial && hasQuick3DImport diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml index 0a5bcfab0d9..3044171ad8e 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml @@ -176,7 +176,6 @@ Column { anchors.horizontalCenter: parent.horizontalCenter IconButton { icon: StudioTheme.Constants.materialPreviewEnvironment - normalColor: "transparent" iconSize: StudioTheme.Values.bigIconFontSize buttonSize: previewOptions.width tooltip: qsTr("Select preview environment.") @@ -184,7 +183,6 @@ Column { } IconButton { icon: StudioTheme.Constants.materialPreviewModel - normalColor: "transparent" iconSize: StudioTheme.Values.bigIconFontSize buttonSize: previewOptions.width tooltip: qsTr("Select preview model.") diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml index dcd4733134a..9593213e347 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml @@ -51,13 +51,6 @@ Rectangle { : mouseArea.containsMouse ? hoverColor : normalColor - Behavior on color { - ColorAnimation { - duration: 300 - easing.type: Easing.OutQuad - } - } - Text { id: icon From ec565eea996e7faa98571bb3c0bb84caa02b8b0e Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 4 Aug 2022 12:40:06 +0300 Subject: [PATCH 27/43] QmlDesigner: Allow deleting materials using the delete action Fixes: QDS-7012 Change-Id: I5eb03971d33a997fc1463ec4ee70eb33a730a897 Reviewed-by: Thomas Hartmann --- .../componentcore/designeractionmanager.cpp | 2 ++ .../materialbrowser/materialbrowsermodel.cpp | 6 ++++++ .../materialbrowser/materialbrowsermodel.h | 1 + .../materialbrowser/materialbrowserview.cpp | 9 +++++++- .../materialbrowser/materialbrowserwidget.cpp | 19 +++++++++++++++-- .../materialbrowser/materialbrowserwidget.h | 21 +++++++++++-------- src/plugins/qmldesigner/designmodecontext.cpp | 13 ++++++++++++ src/plugins/qmldesigner/designmodecontext.h | 9 ++++++++ .../qmldesigner/qmldesignerconstants.h | 11 +++++----- src/plugins/qmldesigner/qmldesignerplugin.cpp | 5 ++++- src/plugins/qmldesigner/shortcutmanager.cpp | 20 +++++++++++++----- src/plugins/qmldesigner/shortcutmanager.h | 5 ++++- 12 files changed, 97 insertions(+), 24 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index a0bd7a23896..8dc52ad6303 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -129,11 +129,13 @@ void DesignerActionManager::polishActions() const Core::Context qmlDesignerFormEditorContext(Constants::C_QMLFORMEDITOR); Core::Context qmlDesignerEditor3DContext(Constants::C_QMLEDITOR3D); Core::Context qmlDesignerNavigatorContext(Constants::C_QMLNAVIGATOR); + Core::Context qmlDesignerMaterialBrowserContext(Constants::C_QMLMATERIALBROWSER); Core::Context qmlDesignerUIContext; qmlDesignerUIContext.add(qmlDesignerFormEditorContext); qmlDesignerUIContext.add(qmlDesignerEditor3DContext); qmlDesignerUIContext.add(qmlDesignerNavigatorContext); + qmlDesignerUIContext.add(qmlDesignerMaterialBrowserContext); for (auto *action : actions) { if (!action->menuId().isEmpty()) { diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp index 49f313534d1..af74c1489d9 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp @@ -201,6 +201,12 @@ void MaterialBrowserModel::removeMaterial(const ModelNode &material) } } +void MaterialBrowserModel::deleteSelectedMaterial() +{ + if (isValidIndex(m_selectedIndex)) + m_materialList[m_selectedIndex].destroy(); +} + void MaterialBrowserModel::updateSelectedMaterial() { selectMaterial(m_selectedIndex, true); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h index 73e6b2f99c6..eb258b1efef 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h @@ -61,6 +61,7 @@ public: QList materials() const; void setMaterials(const QList &materials, bool hasQuick3DImport); void removeMaterial(const ModelNode &material); + void deleteSelectedMaterial(); void updateMaterialName(const ModelNode &material); void updateSelectedMaterial(); int materialIndex(const ModelNode &material) const; diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index ae04c193ca9..ebb9671e501 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -53,7 +54,11 @@ bool MaterialBrowserView::hasWidget() const WidgetInfo MaterialBrowserView::widgetInfo() { if (m_widget.isNull()) { - m_widget = new MaterialBrowserWidget; + m_widget = new MaterialBrowserWidget(this); + + auto matEditorContext = new Internal::MaterialBrowserContext(m_widget.data()); + Core::ICore::addContextObject(matEditorContext); + MaterialBrowserModel *matBrowserModel = m_widget->materialBrowserModel().data(); // custom notifications below are sent to the MaterialEditor @@ -288,6 +293,8 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt QTimer::singleShot(0, this, [this]() { refreshModel(true); }); + } else if (identifier == "delete_selected_material") { + m_widget->materialBrowserModel()->deleteSelectedMaterial(); } } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp index 816ce4a3dce..71ddd1aca7f 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp @@ -25,6 +25,7 @@ #include "materialbrowserwidget.h" #include "materialbrowsermodel.h" +#include "materialbrowserview.h" #include @@ -130,14 +131,20 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event) return QObject::eventFilter(obj, event); } -MaterialBrowserWidget::MaterialBrowserWidget() - : m_materialBrowserModel(new MaterialBrowserModel(this)) +MaterialBrowserWidget::MaterialBrowserWidget(MaterialBrowserView *view) + : m_materialBrowserView(view) + , m_materialBrowserModel(new MaterialBrowserModel(this)) , m_quickWidget(new QQuickWidget(this)) , m_previewImageProvider(new PreviewImageProvider()) { setWindowTitle(tr("Material Browser", "Title of material browser widget")); setMinimumWidth(120); + Core::Context context(Constants::C_QMLMATERIALBROWSER); + m_context = new Core::IContext(this); + m_context->setContext(context); + m_context->setWidget(this); + m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); m_quickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); @@ -182,6 +189,14 @@ QList MaterialBrowserWidget::createToolBarWidgets() return {}; } +void MaterialBrowserWidget::contextHelp(const Core::IContext::HelpCallback &callback) const +{ + if (m_materialBrowserView) + m_materialBrowserView->contextHelp(callback); + else + callback({}); +} + void MaterialBrowserWidget::handleSearchfilterChanged(const QString &filterText) { if (filterText != m_filterText) { diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h index 30f9d05b509..9c08f21f9af 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h @@ -25,20 +25,19 @@ #pragma once -#include "itemlibraryinfo.h" -#include "import.h" #include "modelnode.h" -#include +#include #include +#include -#include -#include #include -#include -#include -#include +#include #include +#include +#include +#include +#include #include @@ -49,6 +48,7 @@ QT_END_NAMESPACE namespace QmlDesigner { +class MaterialBrowserView; class MaterialBrowserModel; class PreviewImageProvider; @@ -57,10 +57,11 @@ class MaterialBrowserWidget : public QFrame Q_OBJECT public: - MaterialBrowserWidget(); + MaterialBrowserWidget(MaterialBrowserView *view); ~MaterialBrowserWidget() = default; QList createToolBarWidgets(); + void contextHelp(const Core::IContext::HelpCallback &callback) const; static QString qmlSourcesPath(); void clearSearchFilter(); @@ -80,11 +81,13 @@ private: void reloadQmlSource(); void updateSearch(); + QPointer m_materialBrowserView; QPointer m_materialBrowserModel; QScopedPointer m_quickWidget; QShortcut *m_qmlSourceUpdateShortcut = nullptr; PreviewImageProvider *m_previewImageProvider = nullptr; + Core::IContext *m_context = nullptr; QString m_filterText; diff --git a/src/plugins/qmldesigner/designmodecontext.cpp b/src/plugins/qmldesigner/designmodecontext.cpp index a0cb0cf4072..442b8b90536 100644 --- a/src/plugins/qmldesigner/designmodecontext.cpp +++ b/src/plugins/qmldesigner/designmodecontext.cpp @@ -28,6 +28,7 @@ #include "designmodewidget.h" #include "formeditorwidget.h" #include "edit3dwidget.h" +#include "materialbrowserwidget.h" #include "navigatorwidget.h" #include "texteditorwidget.h" @@ -70,6 +71,18 @@ void Editor3DContext::contextHelp(const HelpCallback &callback) const qobject_cast(m_widget)->contextHelp(callback); } +MaterialBrowserContext::MaterialBrowserContext(QWidget *widget) + : IContext(widget) +{ + setWidget(widget); + setContext(Core::Context(Constants::C_QMLMATERIALBROWSER, Constants::C_QT_QUICK_TOOLS_MENU)); +} + +void MaterialBrowserContext::contextHelp(const HelpCallback &callback) const +{ + qobject_cast(m_widget)->contextHelp(callback); +} + NavigatorContext::NavigatorContext(QWidget *widget) : IContext(widget) { diff --git a/src/plugins/qmldesigner/designmodecontext.h b/src/plugins/qmldesigner/designmodecontext.h index b30430b5eeb..fdf5beeecef 100644 --- a/src/plugins/qmldesigner/designmodecontext.h +++ b/src/plugins/qmldesigner/designmodecontext.h @@ -60,6 +60,15 @@ public: void contextHelp(const Core::IContext::HelpCallback &callback) const override; }; +class MaterialBrowserContext : public Core::IContext +{ + Q_OBJECT + +public: + MaterialBrowserContext(QWidget *widget); + void contextHelp(const Core::IContext::HelpCallback &callback) const override; +}; + class NavigatorContext : public Core::IContext { Q_OBJECT diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 3cc0c3b8ae6..ee5fa690dca 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -32,11 +32,12 @@ const char C_BACKSPACE[] = "QmlDesigner.Backspace"; const char C_DELETE[] = "QmlDesigner.Delete"; // Context -const char C_QMLDESIGNER[] = "QmlDesigner::QmlDesignerMain"; -const char C_QMLFORMEDITOR[] = "QmlDesigner::FormEditor"; -const char C_QMLEDITOR3D[] = "QmlDesigner::Editor3D"; -const char C_QMLNAVIGATOR[] = "QmlDesigner::Navigator"; -const char C_QMLTEXTEDITOR[] = "QmlDesigner::TextEditor"; +const char C_QMLDESIGNER[] = "QmlDesigner::QmlDesignerMain"; +const char C_QMLFORMEDITOR[] = "QmlDesigner::FormEditor"; +const char C_QMLEDITOR3D[] = "QmlDesigner::Editor3D"; +const char C_QMLNAVIGATOR[] = "QmlDesigner::Navigator"; +const char C_QMLTEXTEDITOR[] = "QmlDesigner::TextEditor"; +const char C_QMLMATERIALBROWSER[] = "QmlDesigner::MaterialBrowser"; // Special context for preview menu, shared b/w designer and text editor const char C_QT_QUICK_TOOLS_MENU[] = "QmlDesigner::ToolsMenu"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 331c8e7852f..69d3db51c32 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -399,15 +399,18 @@ void QmlDesignerPlugin::integrateIntoQtCreator(QWidget *modeWidget) Core::Context qmlDesignerFormEditorContext(Constants::C_QMLFORMEDITOR); Core::Context qmlDesignerEditor3dContext(Constants::C_QMLEDITOR3D); Core::Context qmlDesignerNavigatorContext(Constants::C_QMLNAVIGATOR); + Core::Context qmlDesignerMaterialBrowserContext(Constants::C_QMLMATERIALBROWSER); context->context().add(qmlDesignerMainContext); context->context().add(qmlDesignerFormEditorContext); context->context().add(qmlDesignerEditor3dContext); context->context().add(qmlDesignerNavigatorContext); + context->context().add(qmlDesignerMaterialBrowserContext); context->context().add(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); d->shortCutManager.registerActions(qmlDesignerMainContext, qmlDesignerFormEditorContext, - qmlDesignerEditor3dContext, qmlDesignerNavigatorContext); + qmlDesignerEditor3dContext, qmlDesignerNavigatorContext, + qmlDesignerMaterialBrowserContext); const QStringList mimeTypes = { QmlJSTools::Constants::QML_MIMETYPE, QmlJSTools::Constants::QMLUI_MIMETYPE }; diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp index e82e7a04c01..4cda11748c6 100644 --- a/src/plugins/qmldesigner/shortcutmanager.cpp +++ b/src/plugins/qmldesigner/shortcutmanager.cpp @@ -77,8 +77,11 @@ ShortCutManager::ShortCutManager() void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContext, const Core::Context &qmlDesignerFormEditorContext, const Core::Context &qmlDesignerEditor3DContext, - const Core::Context &qmlDesignerNavigatorContext) + const Core::Context &qmlDesignerNavigatorContext, + const Core::Context &qmlDesignerMaterialBrowserContext) { + Q_UNUSED(qmlDesignerMaterialBrowserContext) + Core::ActionContainer *editMenu = Core::ActionManager::actionContainer(Core::Constants::M_EDIT); Core::ActionContainer *fileMenu = Core::ActionManager::actionContainer(Core::Constants::M_FILE); @@ -195,9 +198,12 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex m_pasteAction.setEnabled(true); }); - connect(Core::ICore::instance(), &Core::ICore::contextChanged, this, [&designerActionManager, this](const Core::Context &context){ - if (!context.contains(Constants::C_QMLFORMEDITOR) && !context.contains(Constants::C_QMLEDITOR3D) && !context.contains(Constants::C_QMLNAVIGATOR)) { - m_deleteAction.setEnabled(false); + connect(Core::ICore::instance(), &Core::ICore::contextChanged, this, [&](const Core::Context &context) { + isMatBrowserActive = context.contains(Constants::C_QMLMATERIALBROWSER); + + if (!context.contains(Constants::C_QMLFORMEDITOR) && !context.contains(Constants::C_QMLEDITOR3D) + && !context.contains(Constants::C_QMLNAVIGATOR)) { + m_deleteAction.setEnabled(isMatBrowserActive); m_cutAction.setEnabled(false); m_copyAction.setEnabled(false); m_pasteAction.setEnabled(false); @@ -249,8 +255,12 @@ void ShortCutManager::redo() void ShortCutManager::deleteSelected() { - if (currentDesignDocument()) + if (isMatBrowserActive) { + DesignerActionManager &designerActionManager = QmlDesignerPlugin::instance()->viewManager().designerActionManager(); + designerActionManager.view()->emitCustomNotification("delete_selected_material"); + } else if (currentDesignDocument()) { currentDesignDocument()->deleteSelected(); + } } void ShortCutManager::cutSelected() diff --git a/src/plugins/qmldesigner/shortcutmanager.h b/src/plugins/qmldesigner/shortcutmanager.h index 4bc4ae5f848..149bf566400 100644 --- a/src/plugins/qmldesigner/shortcutmanager.h +++ b/src/plugins/qmldesigner/shortcutmanager.h @@ -47,7 +47,8 @@ public: void registerActions(const Core::Context &qmlDesignerMainContext, const Core::Context &qmlDesignerFormEditorContext, const Core::Context &qmlDesignerEditor3DContext, - const Core::Context &qmlDesignerNavigatorContext); + const Core::Context &qmlDesignerNavigatorContext, + const Core::Context &qmlDesignerMaterialBrowserContext); void connectUndoActions(DesignDocument *designDocument); void disconnectUndoActions(DesignDocument *designDocument); @@ -84,6 +85,8 @@ private: QAction m_pasteAction; QAction m_selectAllAction; QAction m_escapeAction; + + bool isMatBrowserActive = false; }; } // namespace QmlDesigner From aa893cb652980e2abd68f2439b6ebfbc5732434f Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 17 Aug 2022 14:39:46 +0200 Subject: [PATCH 28/43] QmlDesigner: Do not open the Screen01 from wizard The qmlproject wizard will open the main ui file with a slight delay for the code model. Task-number: QDS-7349 Change-Id: Ic4265eba78f3914564de0ba251d43aeb477bef5e Reviewed-by: Reviewed-by: Thomas Hartmann --- .../studio_templates/projects/application/wizard.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json index 3e7ef11beb7..6912200c14b 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json @@ -318,8 +318,7 @@ }, { "source": "Screen01.ui.qml.tpl", - "target": "%{ProjectDirectory}/content/Screen01.ui.qml", - "openInEditor": true + "target": "%{ProjectDirectory}/content/Screen01.ui.qml" }, { "source": "../common/fonts.txt", From ec733999e1d5c31e75e5aa950f75bd41c136554b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 18 Aug 2022 07:23:51 +0200 Subject: [PATCH 29/43] QmlDesigner: Fix qbs build Change-Id: If9fdad7ee19c1ab6e1180a1ba59d2cdc2d2535f5 Reviewed-by: David Schulz --- src/plugins/qmldesigner/qmldesignerplugin.qbs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 7e7dc7c7af4..9125ec82a3a 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -970,7 +970,6 @@ Project { "timelineeditor/preseteditor.h", "timelineeditor/setframevaluedialog.cpp", "timelineeditor/setframevaluedialog.h", - "timelineeditor/setframevaluedialog.ui", "timelineeditor/splineeditor.cpp", "timelineeditor/splineeditor.h", "timelineeditor/timeline.qrc", From d4cc3fddc908bc87d806796f426ac91e5ee34f30 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 9 Aug 2022 12:56:47 +0300 Subject: [PATCH 30/43] QmlDesigner: Implement copy/paste material properties Fixes: QDS-7014 Change-Id: I2a8b779f97de353836a4d506b715720b490c349f Reviewed-by: Reviewed-by: Samuel Ghinet Reviewed-by: Miikka Heikkinen --- .../MaterialBrowser.qml | 41 +++++++++++---- .../materialbrowser/materialbrowsermodel.cpp | 50 +++++++++++++++---- .../materialbrowser/materialbrowsermodel.h | 12 +++++ .../materialbrowser/materialbrowserview.cpp | 29 ++++++++++- 4 files changed, 111 insertions(+), 21 deletions(-) diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml index 0419b945b9c..bc8582d3596 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml @@ -92,27 +92,48 @@ Item { StudioControls.MenuItem { text: qsTr("Apply to selected (replace)") - enabled: currentMaterial && materialBrowserModel.hasModelSelection - onTriggered: materialBrowserModel.applyToSelected(currentMaterial.materialInternalId, false) + enabled: root.currentMaterial && materialBrowserModel.hasModelSelection + onTriggered: materialBrowserModel.applyToSelected(root.currentMaterial.materialInternalId, false) } StudioControls.MenuItem { text: qsTr("Apply to selected (add)") - enabled: currentMaterial && materialBrowserModel.hasModelSelection - onTriggered: materialBrowserModel.applyToSelected(currentMaterial.materialInternalId, true) + enabled: root.currentMaterial && materialBrowserModel.hasModelSelection + onTriggered: materialBrowserModel.applyToSelected(root.currentMaterial.materialInternalId, true) + } + + StudioControls.MenuSeparator { + height: StudioTheme.Values.border + } + + StudioControls.MenuItem { + text: qsTr("Copy properties") + enabled: root.currentMaterial + onTriggered: materialBrowserModel.copyMaterialProperties(root.currentMaterialIdx) + } + + StudioControls.MenuItem { + text: qsTr("Paste properties") + enabled: root.currentMaterial && root.currentMaterial.materialType.toString() + === materialBrowserModel.copiedMaterialType.toString() + onTriggered: materialBrowserModel.pasteMaterialProperties(root.currentMaterialIdx) + } + + StudioControls.MenuSeparator { + height: StudioTheme.Values.border } StudioControls.MenuItem { text: qsTr("Duplicate") - enabled: currentMaterial - onTriggered: materialBrowserModel.duplicateMaterial(currentMaterialIdx) + enabled: root.currentMaterial + onTriggered: materialBrowserModel.duplicateMaterial(root.currentMaterialIdx) } StudioControls.MenuItem { text: qsTr("Rename") - enabled: currentMaterial + enabled: root.currentMaterial onTriggered: { - var item = gridRepeater.itemAt(currentMaterialIdx); + var item = gridRepeater.itemAt(root.currentMaterialIdx); if (item) item.startRename(); } @@ -120,9 +141,9 @@ Item { StudioControls.MenuItem { text: qsTr("Delete") - enabled: currentMaterial + enabled: root.currentMaterial - onTriggered: materialBrowserModel.deleteMaterial(currentMaterialIdx) + onTriggered: materialBrowserModel.deleteMaterial(root.currentMaterialIdx) } StudioControls.MenuSeparator {} diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp index af74c1489d9..2998cc38c8a 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp @@ -24,9 +24,13 @@ ****************************************************************************/ #include "materialbrowsermodel.h" -#include "variantproperty.h" + +#include #include #include +#include +#include "variantproperty.h" +#include "utils/qtcassert.h" namespace QmlDesigner { @@ -46,24 +50,23 @@ int MaterialBrowserModel::rowCount(const QModelIndex &) const QVariant MaterialBrowserModel::data(const QModelIndex &index, int role) const { - if (!index.isValid() || index.row() >= m_materialList.count()) { - qWarning() << Q_FUNC_INFO << "invalid index requested"; - return {}; - } + QTC_ASSERT(index.isValid() && index.row() < m_materialList.count(), return {}); + QTC_ASSERT(roleNames().contains(role), return {}); - if (roleNames().value(role) == "materialName") { + QByteArray roleName = roleNames().value(role); + if (roleName == "materialName") { QVariant objName = m_materialList.at(index.row()).variantProperty("objectName").value(); return objName.isValid() ? objName : ""; } - if (roleNames().value(role) == "materialInternalId") + if (roleName == "materialInternalId") return m_materialList.at(index.row()).internalId(); - if (roleNames().value(role) == "materialVisible") + if (roleName == "materialVisible") return isMaterialVisible(index.row()); - if (!roleNames().contains(role)) - qWarning() << Q_FUNC_INFO << "invalid role requested"; + if (roleName == "materialType") + return m_materialList.at(index.row()).type(); return {}; } @@ -88,6 +91,7 @@ QHash MaterialBrowserModel::roleNames() const {Qt::UserRole + 1, "materialName"}, {Qt::UserRole + 2, "materialInternalId"}, {Qt::UserRole + 3, "materialVisible"}, + {Qt::UserRole + 4, "materialType"} }; return roles; } @@ -120,6 +124,20 @@ void MaterialBrowserModel::setHasModelSelection(bool b) emit hasModelSelectionChanged(); } +TypeName MaterialBrowserModel::copiedMaterialType() const +{ + return m_copiedMaterialType; +} + +void MaterialBrowserModel::setCopiedMaterialType(const TypeName &matType) +{ + if (matType == m_copiedMaterialType) + return; + + m_copiedMaterialType = matType; + emit copiedMaterialTypeChanged(); +} + QList MaterialBrowserModel::materials() const { return m_materialList; @@ -262,6 +280,18 @@ void MaterialBrowserModel::duplicateMaterial(int idx) emit duplicateMaterialTriggered(m_materialList.at(idx)); } +void MaterialBrowserModel::copyMaterialProperties(int idx) +{ + ModelNode mat = m_materialList.at(idx); + m_copiedMaterialProps = mat.properties(); + setCopiedMaterialType(mat.type()); +} + +void MaterialBrowserModel::pasteMaterialProperties(int idx) +{ + emit pasteMaterialPropertiesTriggered(m_materialList.at(idx), m_copiedMaterialProps); +} + void MaterialBrowserModel::deleteMaterial(int idx) { m_materialList[idx].destroy(); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h index eb258b1efef..cb40ecd9d5e 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h @@ -26,6 +26,7 @@ #pragma once #include +#include #include #include @@ -41,6 +42,7 @@ class MaterialBrowserModel : public QAbstractListModel Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged) Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged) Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged) + Q_PROPERTY(TypeName copiedMaterialType READ copiedMaterialType WRITE setCopiedMaterialType NOTIFY copiedMaterialTypeChanged) public: MaterialBrowserModel(QObject *parent = nullptr); @@ -58,6 +60,9 @@ public: bool hasModelSelection() const; void setHasModelSelection(bool b); + TypeName copiedMaterialType() const; + void setCopiedMaterialType(const TypeName &matType); + QList materials() const; void setMaterials(const QList &materials, bool hasQuick3DImport); void removeMaterial(const ModelNode &material); @@ -71,6 +76,8 @@ public: Q_INVOKABLE void selectMaterial(int idx, bool force = false); Q_INVOKABLE void duplicateMaterial(int idx); + Q_INVOKABLE void copyMaterialProperties(int idx); + Q_INVOKABLE void pasteMaterialProperties(int idx); Q_INVOKABLE void deleteMaterial(int idx); Q_INVOKABLE void renameMaterial(int idx, const QString &newName); Q_INVOKABLE void addNewMaterial(); @@ -81,11 +88,14 @@ signals: void isEmptyChanged(); void hasQuick3DImportChanged(); void hasModelSelectionChanged(); + void copiedMaterialTypeChanged(); void selectedIndexChanged(int idx); void renameMaterialTriggered(const QmlDesigner::ModelNode &material, const QString &newName); void applyToSelectedTriggered(const QmlDesigner::ModelNode &material, bool add = false); void addNewMaterialTriggered(); void duplicateMaterialTriggered(const QmlDesigner::ModelNode &material); + void pasteMaterialPropertiesTriggered(const QmlDesigner::ModelNode &material, + const QList &props); private: bool isMaterialVisible(int idx) const; @@ -93,12 +103,14 @@ private: QString m_searchText; QList m_materialList; + QList m_copiedMaterialProps; QHash m_materialIndexHash; // internalId -> index int m_selectedIndex = 0; bool m_isEmpty = true; bool m_hasQuick3DImport = false; bool m_hasModelSelection = false; + TypeName m_copiedMaterialType; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index ebb9671e501..c8b788ea3a3 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -24,15 +24,18 @@ ****************************************************************************/ #include "materialbrowserview.h" + +#include "bindingproperty.h" #include "materialbrowserwidget.h" #include "materialbrowsermodel.h" #include "nodeabstractproperty.h" #include "qmlobjectnode.h" #include "variantproperty.h" + #include +#include #include #include -#include #include @@ -86,6 +89,30 @@ WidgetInfo MaterialBrowserView::widgetInfo() [&] (const ModelNode &material) { emitCustomNotification("duplicate_material", {material}); }); + + connect(matBrowserModel, &MaterialBrowserModel::pasteMaterialPropertiesTriggered, this, + [&] (const ModelNode &material, const QList &props) { + QmlObjectNode mat(material); + executeInTransaction(__FUNCTION__, [&] { + // remove current properties + const PropertyNameList propNames = material.propertyNames(); + for (const PropertyName &propName : propNames) { + if (propName != "objectName") + mat.removeProperty(propName); + } + + // apply pasted properties + for (const AbstractProperty &prop : props) { + if (prop.name() == "objectName") + continue; + + if (prop.isVariantProperty()) + mat.setVariantProperty(prop.name(), prop.toVariantProperty().value()); + else if (prop.isBindingProperty()) + mat.setBindingProperty(prop.name(), prop.toBindingProperty().expression()); + } + }); + }); } return createWidgetInfo(m_widget.data(), From 2e8574bd7696be5d7158b56a3500fbc97dab4ac2 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 11 Aug 2022 12:45:05 +0300 Subject: [PATCH 31/43] QmlDesigner: Add scene root material support to material editor/browser If the scene root item is Material subclass, material library is not created for the scene. Material editor and browser functionalities that relate to having material library are disabled. Material editor will always show the material that is the scene root. Fixes: QDS-7374 Change-Id: Icd1c212c17b59e4a2caa6b3b4d7e615e68b21eb9 Reviewed-by: Mahmoud Badri --- .../qt5informationnodeinstanceserver.cpp | 24 ++---- .../MaterialBrowser.qml | 34 ++++---- .../MaterialEditorToolBar.qml | 8 +- .../imports/HelperWidgets/SearchBox.qml | 2 +- .../materialbrowser/materialbrowsermodel.cpp | 14 ++++ .../materialbrowser/materialbrowsermodel.h | 6 ++ .../materialbrowser/materialbrowserview.cpp | 1 + .../materialeditorcontextobject.cpp | 14 ++++ .../materialeditorcontextobject.h | 6 ++ .../materialeditor/materialeditorview.cpp | 81 ++++++++++--------- .../materialeditor/materialeditorview.h | 1 + .../designercore/model/abstractview.cpp | 6 +- 12 files changed, 116 insertions(+), 81 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 365aca3cd3b..dae4f975b40 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -342,24 +342,14 @@ void Qt5InformationNodeInstanceServer::resolveImportSupport() void Qt5InformationNodeInstanceServer::updateMaterialPreviewData(const QVector &valueChanges) { const PropertyName matPrevPrefix("matPrev"); - qint32 materialLibraryId = -1; for (const auto &container : valueChanges) { - if (container.name().startsWith(matPrevPrefix)) { - if (!hasInstanceForId(container.instanceId())) - continue; - if (materialLibraryId < 0) { - ServerNodeInstance instance = instanceForId(container.instanceId()); - if (instance.id() == "__materialLibrary__") - materialLibraryId = container.instanceId(); - } - if (container.instanceId() == materialLibraryId) { - if (container.name() == "matPrevEnv") - m_materialPreviewData.env = container.value().toString(); - else if (container.name() == "matPrevEnvValue") - m_materialPreviewData.envValue = container.value().toString(); - else if (container.name() == "matPrevModel") - m_materialPreviewData.model = container.value().toString(); - } + if (container.instanceId() == 0) { + if (container.name() == "matPrevEnv") + m_materialPreviewData.env = container.value().toString(); + else if (container.name() == "matPrevEnvValue") + m_materialPreviewData.envValue = container.value().toString(); + else if (container.name() == "matPrevModel") + m_materialPreviewData.model = container.value().toString(); } } } diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml index bc8582d3596..468b4fb424d 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml @@ -67,8 +67,10 @@ Item { acceptedButtons: Qt.RightButton onClicked: { - root.currentMaterial = null - contextMenu.popup() + if (!materialBrowserModel.hasMaterialRoot) { + root.currentMaterial = null + contextMenu.popup() + } } } @@ -162,6 +164,7 @@ Item { Row { width: root.width + enabled: !materialBrowserModel.hasMaterialRoot && materialBrowserModel.hasQuick3DImport SearchBox { id: searchBox @@ -186,22 +189,22 @@ Item { color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.baseFontSize leftPadding: 10 - visible: materialBrowserModel.hasQuick3DImport && materialBrowserModel.isEmpty && !searchBox.isEmpty() + visible: materialBrowserModel.hasQuick3DImport && materialBrowserModel.isEmpty + && !searchBox.isEmpty() && !materialBrowserModel.hasMaterialRoot } Text { - text: qsTr("There are no materials in this project.
Select '+' to create one.") - textFormat: Text.RichText - color: StudioTheme.Values.themeTextColor - font.pixelSize: StudioTheme.Values.mediumFontSize - horizontalAlignment: Text.AlignHCenter - topPadding: 30 - anchors.horizontalCenter: parent.horizontalCenter - visible: materialBrowserModel.hasQuick3DImport && materialBrowserModel.isEmpty && searchBox.isEmpty() - } + text: { + if (materialBrowserModel.hasMaterialRoot) + qsTr("Material Browser is disabled inside a material component.") + else if (!materialBrowserModel.hasQuick3DImport) + qsTr("To use Material Browser, first add the QtQuick3D module in the Components view.") + else if (materialBrowserModel.isEmpty && searchBox.isEmpty()) + qsTr("There are no materials in this project.
Select '+' to create one.") + else + "" + } - Text { - text: qsTr("To use Material Browser, first add the QtQuick3D module in the Components view."); textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize @@ -209,8 +212,7 @@ Item { horizontalAlignment: Text.AlignHCenter wrapMode: Text.WordWrap width: root.width - anchors.horizontalCenter: parent.horizontalCenter - visible: !materialBrowserModel.hasQuick3DImport + visible: text !== "" } ScrollView { diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml index ba980340fe8..5d53bfc87d3 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml @@ -50,7 +50,7 @@ Rectangle { normalColor: StudioTheme.Values.themeSectionHeadBackground iconSize: StudioTheme.Values.bigIconFontSize buttonSize: root.height - enabled: hasMaterial && hasModelSelection && hasQuick3DImport + enabled: hasMaterial && hasModelSelection && hasQuick3DImport && !hasMaterialRoot onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected) tooltip: qsTr("Apply material to selected model.") } @@ -61,7 +61,7 @@ Rectangle { normalColor: StudioTheme.Values.themeSectionHeadBackground iconSize: StudioTheme.Values.bigIconFontSize buttonSize: root.height - enabled: hasQuick3DImport + enabled: hasQuick3DImport && !hasMaterialRoot onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial) tooltip: qsTr("Create new material.") } @@ -72,7 +72,7 @@ Rectangle { normalColor: StudioTheme.Values.themeSectionHeadBackground iconSize: StudioTheme.Values.bigIconFontSize buttonSize: root.height - enabled: hasMaterial && hasQuick3DImport + enabled: hasMaterial && hasQuick3DImport && !hasMaterialRoot onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentMaterial) tooltip: qsTr("Delete current material.") } @@ -83,7 +83,7 @@ Rectangle { normalColor: StudioTheme.Values.themeSectionHeadBackground iconSize: StudioTheme.Values.bigIconFontSize buttonSize: root.height - enabled: hasMaterial && hasQuick3DImport + enabled: hasMaterial && hasQuick3DImport && !hasMaterialRoot onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser) tooltip: qsTr("Open material browser.") } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SearchBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SearchBox.qml index 8f0079249db..c50d2e1d68e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SearchBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SearchBox.qml @@ -136,7 +136,7 @@ Item { }, State { name: "hover" - when: searchFilterText.hovered && !searchFilterText.activeFocus + when: root.enabled && searchFilterText.hovered && !searchFilterText.activeFocus PropertyChanges { target: textFieldBackground color: StudioTheme.Values.themeControlBackgroundHover diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp index 2998cc38c8a..78c25d2c2bf 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp @@ -124,6 +124,20 @@ void MaterialBrowserModel::setHasModelSelection(bool b) emit hasModelSelectionChanged(); } +bool MaterialBrowserModel::hasMaterialRoot() const +{ + return m_hasMaterialRoot; +} + +void MaterialBrowserModel::setHasMaterialRoot(bool b) +{ + if (m_hasMaterialRoot == b) + return; + + m_hasMaterialRoot = b; + emit hasMaterialRootChanged(); +} + TypeName MaterialBrowserModel::copiedMaterialType() const { return m_copiedMaterialType; diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h index cb40ecd9d5e..bafcdc1fa8f 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h @@ -42,6 +42,7 @@ class MaterialBrowserModel : public QAbstractListModel Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged) Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged) Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged) + Q_PROPERTY(bool hasMaterialRoot READ hasMaterialRoot WRITE setHasMaterialRoot NOTIFY hasMaterialRootChanged) Q_PROPERTY(TypeName copiedMaterialType READ copiedMaterialType WRITE setCopiedMaterialType NOTIFY copiedMaterialTypeChanged) public: @@ -60,6 +61,9 @@ public: bool hasModelSelection() const; void setHasModelSelection(bool b); + bool hasMaterialRoot() const; + void setHasMaterialRoot(bool b); + TypeName copiedMaterialType() const; void setCopiedMaterialType(const TypeName &matType); @@ -88,6 +92,7 @@ signals: void isEmptyChanged(); void hasQuick3DImportChanged(); void hasModelSelectionChanged(); + void hasMaterialRootChanged(); void copiedMaterialTypeChanged(); void selectedIndexChanged(int idx); void renameMaterialTriggered(const QmlDesigner::ModelNode &material, const QString &newName); @@ -110,6 +115,7 @@ private: bool m_isEmpty = true; bool m_hasQuick3DImport = false; bool m_hasModelSelection = false; + bool m_hasMaterialRoot = false; TypeName m_copiedMaterialType; }; diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index c8b788ea3a3..51595656d59 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -127,6 +127,7 @@ void MaterialBrowserView::modelAttached(Model *model) AbstractView::modelAttached(model); m_widget->clearSearchFilter(); + m_widget->materialBrowserModel()->setHasMaterialRoot(rootModelNode().isSubclassOf("QtQuick3D.Material")); m_hasQuick3DImport = model->hasImport("QtQuick3D"); // Project load is already very busy and may even trigger puppet reset, so let's wait a moment diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp index 435c5318979..9323435db79 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp @@ -233,6 +233,20 @@ void MaterialEditorContextObject::setHasQuick3DImport(bool b) emit hasQuick3DImportChanged(); } +bool MaterialEditorContextObject::hasMaterialRoot() const +{ + return m_hasMaterialRoot; +} + +void MaterialEditorContextObject::setHasMaterialRoot(bool b) +{ + if (b == m_hasMaterialRoot) + return; + + m_hasMaterialRoot = b; + emit hasMaterialRootChanged(); +} + bool MaterialEditorContextObject::hasModelSelection() const { return m_hasModelSelection; diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h index 54d72171a56..ed1540d574b 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h @@ -56,6 +56,7 @@ class MaterialEditorContextObject : public QObject Q_PROPERTY(bool hasActiveTimeline READ hasActiveTimeline NOTIFY hasActiveTimelineChanged) Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged) Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged) + Q_PROPERTY(bool hasMaterialRoot READ hasMaterialRoot WRITE setHasMaterialRoot NOTIFY hasMaterialRootChanged) Q_PROPERTY(QQmlPropertyMap *backendValues READ backendValues WRITE setBackendValues NOTIFY backendValuesChanged) @@ -105,6 +106,9 @@ public: bool hasQuick3DImport() const; void setHasQuick3DImport(bool b); + bool hasMaterialRoot() const; + void setHasMaterialRoot(bool b); + bool hasModelSelection() const; void setHasModelSelection(bool b); @@ -134,6 +138,7 @@ signals: void hasAliasExportChanged(); void hasActiveTimelineChanged(); void hasQuick3DImportChanged(); + void hasMaterialRootChanged(); void hasModelSelectionChanged(); private: @@ -155,6 +160,7 @@ private: bool m_aliasExport = false; bool m_hasActiveTimeline = false; bool m_hasQuick3DImport = false; + bool m_hasMaterialRoot = false; bool m_hasModelSelection = false; ModelNode m_selectedMaterial; diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index c0b766648b6..295935e8acc 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -420,12 +420,15 @@ void MaterialEditorView::handleToolBarAction(int action) if (!model()) break; executeInTransaction("MaterialEditorView:handleToolBarAction", [&] { + ModelNode matLib = materialLibraryNode(); + if (!matLib.isValid()) + return; + NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); ModelNode newMatNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), metaInfo.minorVersion()); renameMaterial(newMatNode, "New Material"); - - materialLibraryNode().defaultNodeListProperty().reparentHere(newMatNode); + matLib.defaultNodeListProperty().reparentHere(newMatNode); }); break; } @@ -462,10 +465,8 @@ void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue) PropertyName matPrevEnvValueAuxProp("matPrevEnvValue"); auto renderPreviews = [=](const QString &auxEnv, const QString &auxValue) { - ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); - QTC_ASSERT(matLib.isValid(), return); - matLib.setAuxiliaryData(matPrevEnvAuxProp, auxEnv); - matLib.setAuxiliaryData(matPrevEnvValueAuxProp, auxValue); + rootModelNode().setAuxiliaryData(matPrevEnvAuxProp, auxEnv); + rootModelNode().setAuxiliaryData(matPrevEnvValueAuxProp, auxValue); QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender); emitCustomNotification("refresh_material_browser", {}); }; @@ -473,13 +474,11 @@ void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue) if (env == "Color") { m_colorDialog.clear(); - ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); - QTC_ASSERT(matLib.isValid(), return); // Store color to separate property to persist selection over non-color env changes PropertyName colorAuxProp("matPrevColor"); - QString oldColor = matLib.auxiliaryData(colorAuxProp).toString(); - QString oldEnv = matLib.auxiliaryData(matPrevEnvAuxProp).toString(); - QString oldValue = matLib.auxiliaryData(matPrevEnvValueAuxProp).toString(); + QString oldColor = rootModelNode().auxiliaryData(colorAuxProp).toString(); + QString oldEnv = rootModelNode().auxiliaryData(matPrevEnvAuxProp).toString(); + QString oldValue = rootModelNode().auxiliaryData(matPrevEnvValueAuxProp).toString(); m_colorDialog = new QColorDialog(Core::ICore::dialogParent()); m_colorDialog->setModal(true); @@ -495,9 +494,7 @@ void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue) QObject::connect(m_colorDialog, &QColorDialog::colorSelected, m_colorDialog, [=](const QColor &color) { renderPreviews(env, color.name()); - ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); - QTC_ASSERT(matLib.isValid(), return); - matLib.setAuxiliaryData(colorAuxProp, color.name()); + rootModelNode().setAuxiliaryData(colorAuxProp, color.name()); }); QObject::connect(m_colorDialog, &QColorDialog::rejected, @@ -519,9 +516,7 @@ void MaterialEditorView::handlePreviewModelChanged(const QString &modelStr) QTC_ASSERT(model(), return); QTC_ASSERT(model()->nodeInstanceView(), return); - ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); - QTC_ASSERT(matLib.isValid(), return); - matLib.setAuxiliaryData("matPrevModel", modelStr); + rootModelNode().setAuxiliaryData("matPrevModel", modelStr); QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender); emitCustomNotification("refresh_material_browser", {}); @@ -570,6 +565,7 @@ void MaterialEditorView::setupQmlBackend() currentQmlBackend->widget()->installEventFilter(this); currentQmlBackend->contextObject()->setHasQuick3DImport(m_hasQuick3DImport); + currentQmlBackend->contextObject()->setHasMaterialRoot(m_hasMaterialRoot); m_stackedWidget->setCurrentWidget(currentQmlBackend->widget()); @@ -623,23 +619,20 @@ bool MaterialEditorView::noValidSelection() const void MaterialEditorView::initPreviewData() { if (model() && m_qmlBackEnd) { - ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); - if (matLib.isValid()) { - QString env = matLib.auxiliaryData("matPrevEnv").toString(); - QString envValue = matLib.auxiliaryData("matPrevEnvValue").toString(); - QString modelStr = matLib.auxiliaryData("matPrevModel").toString(); - if (!envValue.isEmpty() && env != "Color" && env != "Default") { - env += '='; - env += envValue; - } - if (env.isEmpty()) - env = "Default"; - if (modelStr.isEmpty()) - modelStr = "#Sphere"; - QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(), - "initPreviewData", - Q_ARG(QVariant, env), Q_ARG(QVariant, modelStr)); + QString env = rootModelNode().auxiliaryData("matPrevEnv").toString(); + QString envValue = rootModelNode().auxiliaryData("matPrevEnvValue").toString(); + QString modelStr = rootModelNode().auxiliaryData("matPrevModel").toString(); + if (!envValue.isEmpty() && env != "Color" && env != "Default") { + env += '='; + env += envValue; } + if (env.isEmpty()) + env = "Default"; + if (modelStr.isEmpty()) + modelStr = "#Sphere"; + QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(), + "initPreviewData", + Q_ARG(QVariant, env), Q_ARG(QVariant, modelStr)); } } @@ -650,11 +643,15 @@ void MaterialEditorView::modelAttached(Model *model) m_locked = true; m_hasQuick3DImport = model->hasImport("QtQuick3D"); + m_hasMaterialRoot = rootModelNode().isSubclassOf("QtQuick3D.Material"); - // Creating the material library node on model attach causes errors as long as the type information - // not complete yet, so we keep checking until type info is complete. - if (m_hasQuick3DImport) + if (m_hasMaterialRoot) { + m_selectedMaterial = rootModelNode(); + } else if (m_hasQuick3DImport) { + // Creating the material library node on model attach causes errors as long as the type + // information is not complete yet, so we keep checking until type info is complete. m_ensureMatLibTimer.start(500); + } if (!m_setupCompleted) { reloadQml(); @@ -868,6 +865,10 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) QmlObjectNode sourceMat(material); executeInTransaction(__FUNCTION__, [&] { + ModelNode matLib = materialLibraryNode(); + if (!matLib.isValid()) + return; + // create the duplicate material NodeMetaInfo metaInfo = model()->metaInfo(matType); QmlObjectNode duplicateMat = createModelNode(matType, metaInfo.majorVersion(), metaInfo.minorVersion()); @@ -889,7 +890,7 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) duplicateMat.setBindingProperty(prop.name(), prop.toBindingProperty().expression()); } - materialLibraryNode().defaultNodeListProperty().reparentHere(duplicateMat); + matLib.defaultNodeListProperty().reparentHere(duplicateMat); }); } @@ -899,8 +900,10 @@ void MaterialEditorView::customNotification(const AbstractView *view, const QStr Q_UNUSED(view) if (identifier == "selected_material_changed") { - m_selectedMaterial = nodeList.first(); - QTimer::singleShot(0, this, &MaterialEditorView::resetView); + if (!m_hasMaterialRoot) { + m_selectedMaterial = nodeList.first(); + QTimer::singleShot(0, this, &MaterialEditorView::resetView); + } } else if (identifier == "apply_to_selected_triggered") { applyMaterialToSelectedModels(nodeList.first(), data.first().toBool()); } else if (identifier == "rename_material") { diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index 1c52be87cfa..cda537280ff 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -131,6 +131,7 @@ private: bool m_locked = false; bool m_setupCompleted = false; bool m_hasQuick3DImport = false; + bool m_hasMaterialRoot = false; QPointer m_colorDialog; }; diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 3899d37d491..8bf0e4347f2 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -834,7 +834,7 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in void AbstractView::ensureMaterialLibraryNode() { ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); - if (matLib.isValid()) + if (matLib.isValid() || rootModelNode().isSubclassOf("QtQuick3D.Material")) return; // Create material library node @@ -863,13 +863,11 @@ void AbstractView::ensureMaterialLibraryNode() } // Returns ModelNode for project's material library. +// Since this calls ensureMaterialLibraryNode(), it should only be called within a transaction. ModelNode AbstractView::materialLibraryNode() { ensureMaterialLibraryNode(); - ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); - QTC_ASSERT(matLib.isValid(), return {}); - return matLib; } From 326f70c40f3f6d5abad2e1f4cad03015538995b1 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 12 Aug 2022 12:47:21 +0300 Subject: [PATCH 32/43] QmlDesigner: Add support for component materials Component materials can now be seen on material browser and their properties are properly shown on material editor Fixes: QDS-7390 Change-Id: I3f7edfe655bdb0da1fa71739c825d09d6101c386 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Bot --- .../MaterialEditorPane.qml | 18 +++ .../MaterialEditorTopSection.qml | 13 +-- .../materialbrowser/materialbrowserview.cpp | 2 +- .../materialeditorcontextobject.cpp | 70 +++++++++++- .../materialeditorcontextobject.h | 27 ++++- .../materialeditorqmlbackend.cpp | 2 +- .../materialeditor/materialeditorview.cpp | 108 ++++++++++++++++-- .../materialeditor/materialeditorview.h | 7 ++ 8 files changed, 223 insertions(+), 24 deletions(-) diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml index 67b5042c492..19d25e7fdc1 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml @@ -63,6 +63,24 @@ PropertyEditorPane { Item { width: 1; height: 10 } + Loader { + id: specificsTwo + + property string theSource: specificQmlData + + anchors.left: parent.left + anchors.right: parent.right + visible: theSource !== "" + sourceComponent: specificQmlComponent + + onTheSourceChanged: { + active = false + active = true + } + } + + Item { width: 1; height: 10 } + Loader { id: specificsOne anchors.left: parent.left diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml index 3044171ad8e..80ac9b2aacb 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml @@ -227,17 +227,8 @@ Column { Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth } ComboBox { - currentIndex: { - if (backendValues.__classNamePrivateInternal.value === "CustomMaterial") - return 2 - - if (backendValues.__classNamePrivateInternal.value === "PrincipledMaterial") - return 1 - - return 0 - } - - model: ["DefaultMaterial", "PrincipledMaterial", "CustomMaterial"] + currentIndex: possibleTypeIndex + model: possibleTypes showExtendedFunctionButton: false implicitWidth: StudioTheme.Values.singleControlColumnWidth diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 51595656d59..ac792f64709 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -163,7 +163,7 @@ void MaterialBrowserView::refreshModel(bool updateImages) bool MaterialBrowserView::isMaterial(const ModelNode &node) const { - if (!node.isValid() || node.isComponent()) + if (!node.isValid()) return false; return node.isSubclassOf("QtQuick3D.Material"); diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp index 9323435db79..31105e84dc0 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -47,12 +48,24 @@ namespace QmlDesigner { -MaterialEditorContextObject::MaterialEditorContextObject(QObject *parent) +MaterialEditorContextObject::MaterialEditorContextObject(QQmlContext *context, QObject *parent) : QObject(parent) + , m_qmlContext(context) { qmlRegisterUncreatableType("ToolBarAction", 1, 0, "ToolBarAction", "Enum type"); } +QQmlComponent *MaterialEditorContextObject::specificQmlComponent() +{ + if (m_specificQmlComponent) + return m_specificQmlComponent; + + m_specificQmlComponent = new QQmlComponent(m_qmlContext->engine(), this); + m_specificQmlComponent->setData(m_specificQmlData.toUtf8(), QUrl::fromLocalFile("specifics.qml")); + + return m_specificQmlComponent; +} + QString MaterialEditorContextObject::convertColorToString(const QVariant &color) { QString colorString; @@ -158,8 +171,10 @@ void MaterialEditorContextObject::changeTypeName(const QString &typeName) msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); - if (msgBox.exec() == QMessageBox::Cancel) + if (msgBox.exec() == QMessageBox::Cancel) { + updatePossibleTypeIndex(); return; + } for (const auto &p : std::as_const(incompatibleProperties)) m_selectedMaterial.removeProperty(p); @@ -275,6 +290,20 @@ void MaterialEditorContextObject::setSpecificsUrl(const QUrl &newSpecificsUrl) emit specificsUrlChanged(); } +void MaterialEditorContextObject::setSpecificQmlData(const QString &newSpecificQmlData) +{ + if (newSpecificQmlData == m_specificQmlData) + return; + + m_specificQmlData = newSpecificQmlData; + + delete m_specificQmlComponent; + m_specificQmlComponent = nullptr; + + emit specificQmlComponentChanged(); + emit specificQmlDataChanged(); +} + void MaterialEditorContextObject::setStateName(const QString &newStateName) { if (newStateName == m_stateName) @@ -293,6 +322,23 @@ void MaterialEditorContextObject::setAllStateNames(const QStringList &allStates) emit allStateNamesChanged(); } +void MaterialEditorContextObject::setPossibleTypes(const QStringList &types) +{ + if (types == m_possibleTypes) + return; + + m_possibleTypes = types; + emit possibleTypesChanged(); + + updatePossibleTypeIndex(); +} + +void MaterialEditorContextObject::setCurrentType(const QString &type) +{ + m_currentType = type.split('.').last(); + updatePossibleTypeIndex(); +} + void MaterialEditorContextObject::setIsBaseState(bool newIsBaseState) { if (newIsBaseState == m_isBaseState) @@ -339,6 +385,20 @@ void MaterialEditorContextObject::setHasAliasExport(bool hasAliasExport) emit hasAliasExportChanged(); } +void MaterialEditorContextObject::updatePossibleTypeIndex() +{ + int newIndex = -1; + if (!m_currentType.isEmpty()) + newIndex = m_possibleTypes.indexOf(m_currentType); + + // Emit valid possible type index change even if the index doesn't change, as currentIndex on + // QML side will change to default internally if model is updated + if (m_possibleTypeIndex != -1 || m_possibleTypeIndex != newIndex) { + m_possibleTypeIndex = newIndex; + emit possibleTypeIndexChanged(); + } +} + void MaterialEditorContextObject::hideCursor() { if (QApplication::overrideCursor()) @@ -403,4 +463,10 @@ bool MaterialEditorContextObject::isBlocked(const QString &propName) const return false; } +void MaterialEditorContextObject::goIntoComponent() +{ + QTC_ASSERT(m_model, return); + DocumentManager::goIntoComponent(m_selectedMaterial); +} + } // QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h index ed1540d574b..07ce582d443 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h @@ -43,9 +43,13 @@ class MaterialEditorContextObject : public QObject Q_OBJECT Q_PROPERTY(QUrl specificsUrl READ specificsUrl WRITE setSpecificsUrl NOTIFY specificsUrlChanged) + Q_PROPERTY(QString specificQmlData READ specificQmlData WRITE setSpecificQmlData NOTIFY specificQmlDataChanged) + Q_PROPERTY(QQmlComponent *specificQmlComponent READ specificQmlComponent NOTIFY specificQmlComponentChanged) Q_PROPERTY(QString stateName READ stateName WRITE setStateName NOTIFY stateNameChanged) Q_PROPERTY(QStringList allStateNames READ allStateNames WRITE setAllStateNames NOTIFY allStateNamesChanged) + Q_PROPERTY(QStringList possibleTypes READ possibleTypes WRITE setPossibleTypes NOTIFY possibleTypesChanged) + Q_PROPERTY(int possibleTypeIndex READ possibleTypeIndex NOTIFY possibleTypeIndexChanged) Q_PROPERTY(bool isBaseState READ isBaseState WRITE setIsBaseState NOTIFY isBaseStateChanged) Q_PROPERTY(bool selectionChanged READ selectionChanged WRITE setSelectionChanged NOTIFY selectionChangedChanged) @@ -61,11 +65,15 @@ class MaterialEditorContextObject : public QObject Q_PROPERTY(QQmlPropertyMap *backendValues READ backendValues WRITE setBackendValues NOTIFY backendValuesChanged) public: - MaterialEditorContextObject(QObject *parent = nullptr); + MaterialEditorContextObject(QQmlContext *context, QObject *parent = nullptr); QUrl specificsUrl() const { return m_specificsUrl; } + QString specificQmlData() const {return m_specificQmlData; } + QQmlComponent *specificQmlComponent(); QString stateName() const { return m_stateName; } QStringList allStateNames() const { return m_allStateNames; } + QStringList possibleTypes() const { return m_possibleTypes; } + int possibleTypeIndex() const { return m_possibleTypeIndex; } bool isBaseState() const { return m_isBaseState; } bool selectionChanged() const { return m_selectionChanged; } @@ -87,6 +95,7 @@ public: Q_INVOKABLE QStringList allStatesForId(const QString &id); Q_INVOKABLE bool isBlocked(const QString &propName) const; + Q_INVOKABLE void goIntoComponent(); enum ToolBarAction { ApplyToSelected = 0, @@ -117,8 +126,11 @@ public: void setSelectedMaterial(const ModelNode &matNode); void setSpecificsUrl(const QUrl &newSpecificsUrl); + void setSpecificQmlData(const QString &newSpecificQmlData); void setStateName(const QString &newStateName); void setAllStateNames(const QStringList &allStates); + void setPossibleTypes(const QStringList &types); + void setCurrentType(const QString &type); void setIsBaseState(bool newIsBaseState); void setSelectionChanged(bool newSelectionChanged); void setBackendValues(QQmlPropertyMap *newBackendValues); @@ -129,8 +141,12 @@ public: signals: void specificsUrlChanged(); + void specificQmlDataChanged(); + void specificQmlComponentChanged(); void stateNameChanged(); void allStateNamesChanged(); + void possibleTypesChanged(); + void possibleTypeIndexChanged(); void isBaseStateChanged(); void selectionChangedChanged(); void backendValuesChanged(); @@ -142,15 +158,22 @@ signals: void hasModelSelectionChanged(); private: + void updatePossibleTypeIndex(); + QUrl m_specificsUrl; + QString m_specificQmlData; + QQmlComponent *m_specificQmlComponent = nullptr; + QQmlContext *m_qmlContext = nullptr; QString m_stateName; QStringList m_allStateNames; + QStringList m_possibleTypes; + int m_possibleTypeIndex = -1; + QString m_currentType; int m_majorVersion = 1; QQmlPropertyMap *m_backendValues = nullptr; - QQmlComponent *m_qmlComponent = nullptr; Model *m_model = nullptr; QPoint m_lastPos; diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp index 79e0e80fc51..588d62f892e 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp @@ -102,7 +102,7 @@ public: MaterialEditorQmlBackend::MaterialEditorQmlBackend(MaterialEditorView *materialEditor) : m_view(new QQuickWidget) , m_materialEditorTransaction(new MaterialEditorTransaction(materialEditor)) - , m_contextObject(new MaterialEditorContextObject()) + , m_contextObject(new MaterialEditorContextObject(m_view->rootContext())) , m_materialEditorImageProvider(new MaterialEditorImageProvider()) { m_view->setResizeMode(QQuickWidget::SizeRootObjectToView); diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 295935e8acc..d9e36363d9d 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,10 @@ MaterialEditorView::MaterialEditorView(QWidget *parent) } }); + m_typeUpdateTimer.setSingleShot(true); + m_typeUpdateTimer.setInterval(500); + connect(&m_typeUpdateTimer, &QTimer::timeout, this, &MaterialEditorView::updatePossibleTypes); + m_stackedWidget->setStyleSheet(Theme::replaceCssColors( QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); m_stackedWidget->setMinimumWidth(250); @@ -526,14 +531,30 @@ void MaterialEditorView::setupQmlBackend() { QUrl qmlPaneUrl; QUrl qmlSpecificsUrl; + QString specificQmlData; + QString currentTypeName; if (m_selectedMaterial.isValid() && m_hasQuick3DImport) { qmlPaneUrl = QUrl::fromLocalFile(materialEditorResourcesPath() + "/MaterialEditorPane.qml"); + TypeName diffClassName; NodeMetaInfo metaInfo = m_selectedMaterial.metaInfo(); - QDir importDir(metaInfo.importDirectoryPath() + Constants::QML_DESIGNER_SUBFOLDER); - QString typeName = QString::fromUtf8(metaInfo.typeName().split('.').constLast()); - qmlSpecificsUrl = QUrl::fromLocalFile(importDir.absoluteFilePath(typeName + "Specifics.qml")); + if (metaInfo.isValid()) { + diffClassName = metaInfo.typeName(); + const QList hierarchy = metaInfo.classHierarchy(); + for (const NodeMetaInfo &metaInfo : hierarchy) { + if (PropertyEditorQmlBackend::checkIfUrlExists(qmlSpecificsUrl)) + break; + qmlSpecificsUrl = PropertyEditorQmlBackend::getQmlFileUrl(metaInfo.typeName() + + "Specifics", metaInfo); + diffClassName = metaInfo.typeName(); + } + } + if (metaInfo.isValid() && diffClassName != m_selectedMaterial.type()) { + specificQmlData = PropertyEditorQmlBackend::templateGeneration( + metaInfo, model()->metaInfo(diffClassName), m_selectedMaterial); + } + currentTypeName = QString::fromLatin1(m_selectedMaterial.type()); } else { qmlPaneUrl = QUrl::fromLocalFile(materialEditorResourcesPath() + "/EmptyMaterialEditorPane.qml"); } @@ -566,11 +587,15 @@ void MaterialEditorView::setupQmlBackend() currentQmlBackend->widget()->installEventFilter(this); currentQmlBackend->contextObject()->setHasQuick3DImport(m_hasQuick3DImport); currentQmlBackend->contextObject()->setHasMaterialRoot(m_hasMaterialRoot); - - m_stackedWidget->setCurrentWidget(currentQmlBackend->widget()); + currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData); + currentQmlBackend->contextObject()->setCurrentType(currentTypeName); m_qmlBackEnd = currentQmlBackend; + + delayedTypeUpdate(); initPreviewData(); + + m_stackedWidget->setCurrentWidget(m_qmlBackEnd->widget()); } void MaterialEditorView::commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value) @@ -636,6 +661,53 @@ void MaterialEditorView::initPreviewData() } } +void MaterialEditorView::delayedTypeUpdate() +{ + m_typeUpdateTimer.start(); +} + +static Import entryToImport(const ItemLibraryEntry &entry) +{ + if (entry.majorVersion() == -1 && entry.minorVersion() == -1) + return Import::createFileImport(entry.requiredImport()); + return Import::createLibraryImport(entry.requiredImport(), + QString::number(entry.majorVersion()) + QLatin1Char('.') + + QString::number(entry.minorVersion())); +} + +void MaterialEditorView::updatePossibleTypes() +{ + QTC_ASSERT(model(), return); + + if (!m_qmlBackEnd) + return; + + // Ensure basic types are always first + static const QStringList basicTypes {"DefaultMaterial", "PrincipledMaterial", "CustomMaterial"}; + QStringList allTypes = basicTypes; + + const QList itemLibEntries = m_itemLibraryInfo->entries(); + for (const ItemLibraryEntry &entry : itemLibEntries) { + NodeMetaInfo metaInfo = model()->metaInfo(entry.typeName()); + bool valid = metaInfo.isValid() + && (metaInfo.majorVersion() >= entry.majorVersion() + || metaInfo.majorVersion() < 0); + if (valid && metaInfo.isSubclassOf("QtQuick3D.Material")) { + bool addImport = entry.requiredImport().isEmpty(); + if (!addImport) { + Import import = entryToImport(entry); + addImport = model()->hasImport(import, true, true); + } + if (addImport) { + QString typeName = QString::fromLatin1(entry.typeName().split('.').last()); + if (!allTypes.contains(typeName)) + allTypes.append(typeName); + } + } + } + m_qmlBackEnd->contextObject()->setPossibleTypes(allTypes); +} + void MaterialEditorView::modelAttached(Model *model) { AbstractView::modelAttached(model); @@ -653,6 +725,18 @@ void MaterialEditorView::modelAttached(Model *model) m_ensureMatLibTimer.start(500); } + if (m_itemLibraryInfo.data() != model->metaInfo().itemLibraryInfo()) { + if (m_itemLibraryInfo) { + disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged, + this, &MaterialEditorView::delayedTypeUpdate); + } + m_itemLibraryInfo = model->metaInfo().itemLibraryInfo(); + if (m_itemLibraryInfo) { + connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged, + this, &MaterialEditorView::delayedTypeUpdate); + } + } + if (!m_setupCompleted) { reloadQml(); m_setupCompleted = true; @@ -816,10 +900,20 @@ void MaterialEditorView::instancePropertyChanged(const QListcontextObject()->setCurrentType(QString::fromLatin1(typeName)); delayedResetView(); + } +} + +void MaterialEditorView::rootNodeTypeChanged(const QString &type, int, int) +{ + if (rootModelNode() == m_selectedMaterial) { + m_qmlBackEnd->contextObject()->setCurrentType(type); + delayedResetView(); + } } void MaterialEditorView::modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index cda537280ff..64260ead765 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -26,6 +26,8 @@ #pragma once #include +#include + #include #include #include @@ -70,6 +72,7 @@ public: void instancePropertyChanged(const QList > &propertyList) override; void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override; + void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override; void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap) override; void importsChanged(const QList &addedImports, const QList &removedImports) override; void customNotification(const AbstractView *view, const QString &identifier, @@ -119,9 +122,12 @@ private: bool noValidSelection() const; void initPreviewData(); + void delayedTypeUpdate(); + void updatePossibleTypes(); ModelNode m_selectedMaterial; QTimer m_ensureMatLibTimer; + QTimer m_typeUpdateTimer; QShortcut *m_updateShortcut = nullptr; int m_timerId = 0; QStackedWidget *m_stackedWidget = nullptr; @@ -134,6 +140,7 @@ private: bool m_hasMaterialRoot = false; QPointer m_colorDialog; + QPointer m_itemLibraryInfo; }; } // namespace QmlDesigner From e4b35fa5763e4a11258f94fc2381acb4c8792d29 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 15 Aug 2022 14:57:56 +0300 Subject: [PATCH 33/43] QmlDesigner: Block preview data change handling when initializing Handling the data change is pointless when we are initializing UI to stored values, and can also trigger undesirable secondary effects like showing color selection dialog. Fixes: QDS-7415 Change-Id: I0321c47d5a63971dc890c37f90ec6fedc8293eca Reviewed-by: Mahmoud Badri Reviewed-by: --- .../components/materialeditor/materialeditorview.cpp | 6 ++++-- .../components/materialeditor/materialeditorview.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index d9e36363d9d..1a3ab43763a 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -453,7 +453,7 @@ void MaterialEditorView::handleToolBarAction(int action) void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue) { - if (envAndValue.isEmpty()) + if (envAndValue.isEmpty() || m_initializingPreviewData) return; QTC_ASSERT(m_hasQuick3DImport, return); @@ -514,7 +514,7 @@ void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue) void MaterialEditorView::handlePreviewModelChanged(const QString &modelStr) { - if (modelStr.isEmpty()) + if (modelStr.isEmpty() || m_initializingPreviewData) return; QTC_ASSERT(m_hasQuick3DImport, return); @@ -655,9 +655,11 @@ void MaterialEditorView::initPreviewData() env = "Default"; if (modelStr.isEmpty()) modelStr = "#Sphere"; + m_initializingPreviewData = true; QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(), "initPreviewData", Q_ARG(QVariant, env), Q_ARG(QVariant, modelStr)); + m_initializingPreviewData = false; } } diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index 64260ead765..e631ae9ca8a 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -138,6 +138,7 @@ private: bool m_setupCompleted = false; bool m_hasQuick3DImport = false; bool m_hasMaterialRoot = false; + bool m_initializingPreviewData = false; QPointer m_colorDialog; QPointer m_itemLibraryInfo; From dc2cd9db946d4f176269b852e55f21134590f4b0 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 18 Aug 2022 10:16:42 +0200 Subject: [PATCH 34/43] LanguageClient: correctly disconnect documents changed signal on reset connect calls to a lambda can not be disconnected with the sender->disconnect(receiver); syntax, so save the connection in a QMetaObject::Connection and use this to disconnect the signal. Fixes: QTCREATORBUG-27596 Change-Id: I69f5d990aab4e85d768e2101f0157a7dee3c1fa1 Reviewed-by: Christian Kandeler --- src/plugins/languageclient/client.cpp | 31 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index eeb1499a747..bb4c4e6e328 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -278,7 +278,17 @@ public: QString m_displayName; LanguageFilter m_languagFilter; QJsonObject m_initializationOptions; - QMap m_openedDocument; + class OpenedDocument + { + public: + ~OpenedDocument() + { + QObject::disconnect(contentsChangedConnection); + } + QMetaObject::Connection contentsChangedConnection; + QString documentContents; + }; + QMap m_openedDocument; // Used for build system artifacts (e.g. UI headers) that Qt Creator "live-generates" ahead of // the build. @@ -610,11 +620,14 @@ void Client::openDocument(TextEditor::TextDocument *document) } } - d->m_openedDocument[document] = document->plainText(); - connect(document, &TextDocument::contentsChangedWithPosition, this, - [this, document](int position, int charsRemoved, int charsAdded) { - documentContentsChanged(document, position, charsRemoved, charsAdded); - }); + d->m_openedDocument[document].documentContents = document->plainText(); + d->m_openedDocument[document].contentsChangedConnection + = connect(document, + &TextDocument::contentsChangedWithPosition, + this, + [this, document](int position, int charsRemoved, int charsAdded) { + documentContentsChanged(document, position, charsRemoved, charsAdded); + }); if (!d->m_documentVersions.contains(filePath)) d->m_documentVersions[filePath] = 0; d->sendOpenNotification(filePath, document->mimeType(), document->plainText(), @@ -1075,7 +1088,7 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document, } } if (append) { - QTextDocument oldDoc(d->m_openedDocument[document]); + QTextDocument oldDoc(d->m_openedDocument[document].documentContents); QTextCursor cursor(&oldDoc); // Workaround https://bugreports.qt.io/browse/QTBUG-80662 // The contentsChanged gives a character count that can be wrong for QTextCursor @@ -1096,7 +1109,7 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document, d->m_documentsToUpdate[document] = { DidChangeTextDocumentParams::TextDocumentContentChangeEvent(document->plainText())}; } - d->m_openedDocument[document] = document->plainText(); + d->m_openedDocument[document].documentContents = document->plainText(); } ++d->m_documentVersions[document->filePath()]; @@ -1521,8 +1534,6 @@ bool ClientPrivate::reset() m_dynamicCapabilities.reset(); if (m_diagnosticManager) m_diagnosticManager->clearDiagnostics(); - for (auto it = m_openedDocument.cbegin(); it != m_openedDocument.cend(); ++it) - it.key()->disconnect(this); m_openedDocument.clear(); // temporary container needed since m_resetAssistProvider is changed in resetAssistProviders for (TextEditor::TextDocument *document : m_resetAssistProvider.keys()) From 5c68fb68ceff9222eed7e199b0622217140a7bc7 Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Thu, 18 Aug 2022 13:13:09 +0200 Subject: [PATCH 35/43] Do not update control values when pressing cancel Change-Id: I3d365e760fa8ba4a0b36a995d0bf6a59f2d9734b Reviewed-by: Thomas Hartmann --- .../components/curveeditor/detail/colorcontrol.cpp | 2 +- .../components/timelineeditor/setframevaluedialog.cpp | 4 ++-- .../components/timelineeditor/timelinecontrols.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.cpp index f8587df06fe..cb6811c9750 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.cpp @@ -85,7 +85,7 @@ void ColorControl::mouseReleaseEvent(QMouseEvent *event) event->accept(); - if (color != m_color) { + if (color.isValid() && color != m_color) { m_color = color; update(); emit valueChanged(); diff --git a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp index 1bf437e802a..60553dc6202 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp @@ -24,7 +24,7 @@ ****************************************************************************/ #include "setframevaluedialog.h" -#include "curveeditor/detail/colorcontrol.h" +#include "timelinecontrols.h" #include #include @@ -110,7 +110,7 @@ QWidget* SetFrameValueDialog::createValueControl(const QVariant& value) { case QMetaType::QColor: { - auto* widget = new StyleEditor::ColorControl(value.value()); + auto* widget = new ColorControl(value.value()); m_valueGetter = [widget]() { return widget->value(); }; return widget; } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp index 185b12ea422..f417d5dad06 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp @@ -191,7 +191,7 @@ void ColorControl::mouseReleaseEvent(QMouseEvent *event) event->accept(); - if (color != m_color) { + if (color.isValid() && color != m_color) { m_color = color; update(); emit valueChanged(); From 792c5271e2053b03710ecd621eb9372dad1185d1 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 18 Aug 2022 12:46:36 +0200 Subject: [PATCH 36/43] Bump version to 8.0.2 Change-Id: Ib7e45eb039bcba4430259babbd3d398258f62c5c Reviewed-by: Reviewed-by: David Schulz --- cmake/QtCreatorIDEBranding.cmake | 4 ++-- qbs/modules/qtc/qtc.qbs | 4 ++-- qtcreator_ide_branding.pri | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index d2e2ac15fff..5f423dda8d0 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ -set(IDE_VERSION "8.0.1") # The IDE version. +set(IDE_VERSION "8.0.2") # The IDE version. set(IDE_VERSION_COMPAT "8.0.0") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "8.0.1") # The IDE display version. +set(IDE_VERSION_DISPLAY "8.0.2") # The IDE display version. set(IDE_COPYRIGHT_YEAR "2022") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 47f09259552..0f7d6dd344a 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -6,10 +6,10 @@ import qbs.Utilities Module { Depends { name: "cpp"; required: false } - property string qtcreator_display_version: '8.0.1' + property string qtcreator_display_version: '8.0.2' property string ide_version_major: '8' property string ide_version_minor: '0' - property string ide_version_release: '1' + property string ide_version_release: '2' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release diff --git a/qtcreator_ide_branding.pri b/qtcreator_ide_branding.pri index d7826cb62a5..7b430683b6d 100644 --- a/qtcreator_ide_branding.pri +++ b/qtcreator_ide_branding.pri @@ -1,6 +1,6 @@ -QTCREATOR_VERSION = 8.0.1 +QTCREATOR_VERSION = 8.0.2 QTCREATOR_COMPAT_VERSION = 8.0.0 -QTCREATOR_DISPLAY_VERSION = 8.0.1 +QTCREATOR_DISPLAY_VERSION = 8.0.2 QTCREATOR_COPYRIGHT_YEAR = 2022 IDE_DISPLAY_NAME = Qt Creator From b899a27c863da4fc294edba25c798344b6909fc0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 20 Jul 2022 19:16:15 +0200 Subject: [PATCH 37/43] StudioWelcome: Disable welcome page during download Change-Id: Ic85dfd79e4c43822805ce2a7f392f9b0a5d2a923 Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Bot --- src/plugins/studiowelcome/examplecheckout.cpp | 16 +++++++++++++--- src/plugins/studiowelcome/examplecheckout.h | 3 ++- .../studiowelcome/studiowelcomeplugin.cpp | 9 ++++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp index cdb0e878c39..9131009f563 100644 --- a/src/plugins/studiowelcome/examplecheckout.cpp +++ b/src/plugins/studiowelcome/examplecheckout.cpp @@ -456,21 +456,28 @@ DataModelDownloader::DataModelDownloader(QObject * /* parent */) &FileDownloader::progressChanged, this, &DataModelDownloader::progressChanged); + + connect(&m_fileDownloader, + &FileDownloader::downloadFailed, + this, + &DataModelDownloader::downloadFailed); } -void DataModelDownloader::start() +bool DataModelDownloader::start() { if (!enableDownload()) { m_available = false; emit availableChanged(); - return; + return false; } m_fileDownloader.setUrl(QUrl::fromUserInput( "https://download.qt.io/learning/examples/qtdesignstudio/dataImports.zip")); - connect(&m_fileDownloader, &FileDownloader::availableChanged, this, [this]() { + bool started = false; + + connect(&m_fileDownloader, &FileDownloader::availableChanged, this, [this, &started]() { m_available = m_fileDownloader.available(); @@ -484,6 +491,8 @@ void DataModelDownloader::start() if (!m_forceDownload && (m_fileDownloader.lastModified() <= m_birthTime)) return; + started = true; + m_fileDownloader.start(); connect(&m_fileDownloader, &FileDownloader::finishedChanged, this, [this]() { if (m_fileDownloader.finished()) { @@ -501,6 +510,7 @@ void DataModelDownloader::start() } }); }); + return started; } bool DataModelDownloader::exists() const diff --git a/src/plugins/studiowelcome/examplecheckout.h b/src/plugins/studiowelcome/examplecheckout.h index fae0fea3368..42b8b9a41b9 100644 --- a/src/plugins/studiowelcome/examplecheckout.h +++ b/src/plugins/studiowelcome/examplecheckout.h @@ -163,7 +163,7 @@ class DataModelDownloader : public QObject public: explicit DataModelDownloader(QObject *parent = nullptr); - void start(); + bool start(); bool exists() const; bool available() const; Utils::FilePath targetFolder() const; @@ -174,6 +174,7 @@ signals: void finished(); void availableChanged(); void progressChanged(); + void downloadFailed(); private: FileDownloader m_fileDownloader; diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 3fe21396a99..33d29afa959 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -656,9 +656,16 @@ WelcomeMode::WelcomeMode() m_modeWidget->engine()->clearComponentCache(); m_modeWidget->setSource(source); m_modeWidget->rootObject()->setProperty("loadingProgress", 100); + m_modeWidget->setEnabled(true); }); - m_dataModelDownloader->start(); + connect(m_dataModelDownloader, &DataModelDownloader::downloadFailed, this, [this]() { + m_modeWidget->setEnabled(true); + }); + + + if (m_dataModelDownloader->start()) + m_modeWidget->setEnabled(false); /* connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged, this, [this](Utils::Id mode){ From e8d05da529b125d4b3f75bb2b60105d73aa88052 Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Thu, 18 Aug 2022 14:56:57 +0200 Subject: [PATCH 38/43] QmlDesigner: Exclude Behavior children from Scene Task-number: QDS-7444 Change-Id: I6bd04f7619ae15d2fce81d79d1a1c59e33e834c8 Reviewed-by: Thomas Hartmann --- .../designercore/instances/nodeinstanceview.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index e84f9224d61..1a703463ccf 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -988,6 +988,18 @@ QList filterNodesForSkipItems(const QList &nodeList) return filteredNodeList; } +bool parentIsBehavior(ModelNode node) +{ + while (node.isValid() && !node.isRootNode()) { + if (!node.behaviorPropertyName().isEmpty()) + return true; + + node = node.parentProperty().parentModelNode(); + } + + return false; +} + CreateSceneCommand NodeInstanceView::createCreateSceneCommand() { QList nodeList = allModelNodes(); @@ -1051,7 +1063,7 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() nodeMetaType, nodeFlags); - if (instance.modelNode().behaviorPropertyName().isEmpty()) + if (!parentIsBehavior(instance.modelNode())) instanceContainerList.append(container); } From c7f742a54603b77b9ad34da299996122b970574b Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 18 Aug 2022 14:09:50 +0200 Subject: [PATCH 39/43] QmlDesigner: Recreate QuickWidget on download Instead of resetting the engine we have to recreate the widget to avoid a crashes. Task-number: QDS-7355 Change-Id: Id0d202c5da1d13433a95442156815056168b998b Reviewed-by: Tim Jenssen --- .../studiowelcome/studiowelcomeplugin.cpp | 114 ++++++++++-------- 1 file changed, 67 insertions(+), 47 deletions(-) diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 33d29afa959..c7845f231ec 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -450,7 +450,11 @@ public: ~WelcomeMode() override; private: - QQuickWidget *m_modeWidget = nullptr; + void setupQuickWidget(const QString &welcomePagePath); + void createQuickWidget(); + + QQuickWidget *m_quickWidget = nullptr; + QWidget *m_modeWidget = nullptr; DataModelDownloader *m_dataModelDownloader = nullptr; }; @@ -634,38 +638,31 @@ WelcomeMode::WelcomeMode() QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf"); ExampleCheckout::registerTypes(); - m_modeWidget = new QQuickWidget; - m_modeWidget->setMinimumSize(640, 480); - m_modeWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - QmlDesigner::Theme::setupTheme(m_modeWidget->engine()); - m_modeWidget->engine()->addImportPath("qrc:/studiofonts"); - - QmlDesigner::QmlDesignerPlugin::registerPreviewImageProvider(m_modeWidget->engine()); - - m_modeWidget->engine()->setOutputWarningsToStandardError(false); + createQuickWidget(); if (forceDownLoad() || !readme.exists()) // Only downloads contain the readme m_dataModelDownloader->setForceDownload(true); connect(m_dataModelDownloader, &DataModelDownloader::progressChanged, this, [this](){ - m_modeWidget->rootObject()->setProperty("loadingProgress", m_dataModelDownloader->progress()); + m_quickWidget->rootObject()->setProperty("loadingProgress", m_dataModelDownloader->progress()); }); - connect(m_dataModelDownloader, &DataModelDownloader::finished, this, [this](){ - auto source = m_modeWidget->source(); - m_modeWidget->engine()->clearComponentCache(); - m_modeWidget->setSource(source); - m_modeWidget->rootObject()->setProperty("loadingProgress", 100); - m_modeWidget->setEnabled(true); + m_quickWidget->setEnabled(false); + + connect(m_dataModelDownloader, &DataModelDownloader::finished, this, [this, welcomePagePath]() { + delete m_quickWidget; + createQuickWidget(); + setupQuickWidget(welcomePagePath); + m_modeWidget->layout()->addWidget(m_quickWidget); }); connect(m_dataModelDownloader, &DataModelDownloader::downloadFailed, this, [this]() { - m_modeWidget->setEnabled(true); + m_quickWidget->setEnabled(true); }); if (m_dataModelDownloader->start()) - m_modeWidget->setEnabled(false); + m_quickWidget->setEnabled(false); /* connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged, this, [this](Utils::Id mode){ @@ -673,36 +670,14 @@ WelcomeMode::WelcomeMode() m_modeWidget->rootObject()->setProperty("active", active); }); */ + setupQuickWidget(welcomePagePath); - if (!useNewWelcomePage()) { - -#ifdef QT_DEBUG - m_modeWidget->engine()->addImportPath(QLatin1String(STUDIO_QML_PATH) - + "welcomepage/imports"); - m_modeWidget->setSource(QUrl::fromLocalFile(QLatin1String(STUDIO_QML_PATH) - + "welcomepage/main.qml")); -#else - m_modeWidget->engine()->addImportPath("qrc:/qml/welcomepage/imports"); - m_modeWidget->setSource(QUrl("qrc:/qml/welcomepage/main.qml")); -#endif - } else { - - m_modeWidget->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString()); - - m_modeWidget->engine()->addImportPath(welcomePagePath + "/imports"); - m_modeWidget->engine()->addImportPath(m_dataModelDownloader->targetFolder().toString()); - m_modeWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml")); - - QShortcut *updateShortcut = nullptr; - if (Utils::HostOsInfo::isMacHost()) - updateShortcut = new QShortcut(QKeySequence(Qt::ALT | Qt::Key_F5), m_modeWidget); - else - updateShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_F5), m_modeWidget); - connect(updateShortcut, &QShortcut::activated, this, [this, welcomePagePath](){ - m_modeWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml")); - }); - } + QVBoxLayout *boxLayout = new QVBoxLayout(); + boxLayout->setContentsMargins(0, 0, 0, 0); + m_modeWidget = new QWidget; + m_modeWidget->setLayout(boxLayout); + boxLayout->addWidget(m_quickWidget); setWidget(m_modeWidget); QStringList designStudioQchPathes @@ -753,6 +728,51 @@ WelcomeMode::~WelcomeMode() delete m_modeWidget; } +void WelcomeMode::setupQuickWidget(const QString &welcomePagePath) +{ + if (!useNewWelcomePage()) { + +#ifdef QT_DEBUG + m_modeWidget->engine()->addImportPath(QLatin1String(STUDIO_QML_PATH) + + "welcomepage/imports"); + m_modeWidget->setSource(QUrl::fromLocalFile(QLatin1String(STUDIO_QML_PATH) + + "welcomepage/main.qml")); +#else + m_quickWidget->engine()->addImportPath("qrc:/qml/welcomepage/imports"); + m_quickWidget->setSource(QUrl("qrc:/qml/welcomepage/main.qml")); +#endif + } else { + + m_quickWidget->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString()); + + m_quickWidget->engine()->addImportPath(welcomePagePath + "/imports"); + m_quickWidget->engine()->addImportPath(m_dataModelDownloader->targetFolder().toString()); + m_quickWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml")); + + QShortcut *updateShortcut = nullptr; + if (Utils::HostOsInfo::isMacHost()) + updateShortcut = new QShortcut(QKeySequence(Qt::ALT | Qt::Key_F5), m_quickWidget); + else + updateShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_F5), m_quickWidget); + connect(updateShortcut, &QShortcut::activated, this, [this, welcomePagePath](){ + m_quickWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml")); + }); + } +} + +void WelcomeMode::createQuickWidget() +{ + m_quickWidget = new QQuickWidget; + m_quickWidget->setMinimumSize(640, 480); + m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + QmlDesigner::Theme::setupTheme(m_quickWidget->engine()); + m_quickWidget->engine()->addImportPath("qrc:/studiofonts"); + + QmlDesigner::QmlDesignerPlugin::registerPreviewImageProvider(m_quickWidget->engine()); + + m_quickWidget->engine()->setOutputWarningsToStandardError(false); +} + StudioSettingsPage::StudioSettingsPage() : m_buildCheckBox(new QCheckBox(tr("Build"))) , m_debugCheckBox(new QCheckBox(tr("Debug"))) From 2d86c290ce52953dbb723017b8b226b8599bbeed Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 12 Aug 2022 11:47:36 +0300 Subject: [PATCH 40/43] QmlDesigner: Implement copying specific material properties section Change-Id: I34bed00c89018e86941c4e5a7ddeae44c06f850d Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann Reviewed-by: --- .../MaterialBrowser.qml | 41 +++++++-- .../materialbrowser/materialbrowsermodel.cpp | 88 +++++++++++++++++-- .../materialbrowser/materialbrowsermodel.h | 24 +++-- .../materialbrowser/materialbrowserview.cpp | 20 +++-- 4 files changed, 147 insertions(+), 26 deletions(-) diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml index 468b4fb424d..a8692f3ef9d 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml @@ -39,6 +39,8 @@ Item { property var currentMaterial: null property int currentMaterialIdx: 0 + property var matSectionsModel: [] + // Called also from C++ to close context menu on focus out function closeContextMenu() { @@ -108,16 +110,45 @@ Item { height: StudioTheme.Values.border } - StudioControls.MenuItem { - text: qsTr("Copy properties") + StudioControls.Menu { + title: qsTr("Copy properties") enabled: root.currentMaterial - onTriggered: materialBrowserModel.copyMaterialProperties(root.currentMaterialIdx) + + width: parent.width + + onAboutToShow: { + root.matSectionsModel = ["All"]; + + switch (root.currentMaterial.materialType) { + case "DefaultMaterial": + root.matSectionsModel = root.matSectionsModel.concat(materialBrowserModel.defaultMaterialSections); + break; + + case "PrincipledMaterial": + root.matSectionsModel = root.matSectionsModel.concat(materialBrowserModel.principledMaterialSections); + break; + + case "CustomMaterial": + root.matSectionsModel = root.matSectionsModel.concat(materialBrowserModel.customMaterialSections); + break; + } + } + + Repeater { + model: root.matSectionsModel + + StudioControls.MenuItem { + text: modelData + enabled: root.currentMaterial + onTriggered: materialBrowserModel.copyMaterialProperties(root.currentMaterialIdx, modelData) + } + } } StudioControls.MenuItem { text: qsTr("Paste properties") - enabled: root.currentMaterial && root.currentMaterial.materialType.toString() - === materialBrowserModel.copiedMaterialType.toString() + enabled: root.currentMaterial && root.currentMaterial.materialType + === materialBrowserModel.copiedMaterialType onTriggered: materialBrowserModel.pasteMaterialProperties(root.currentMaterialIdx) } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp index 78c25d2c2bf..4027a1c75ae 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp @@ -65,8 +65,12 @@ QVariant MaterialBrowserModel::data(const QModelIndex &index, int role) const if (roleName == "materialVisible") return isMaterialVisible(index.row()); - if (roleName == "materialType") - return m_materialList.at(index.row()).type(); + if (roleName == "materialType") { + QString matType = QString::fromLatin1(m_materialList.at(index.row()).type()); + if (matType.startsWith("QtQuick3D.")) + matType.remove("QtQuick3D."); + return matType; + } return {}; } @@ -85,6 +89,50 @@ bool MaterialBrowserModel::isValidIndex(int idx) const return idx > -1 && idx < rowCount(); } +/** + * @brief Loads and parses propertyGroups.json from QtQuick3D module's designer folder + * + * propertyGroups.json contains lists of QtQuick3D objects' properties grouped by sections + * + * @param path path to propertyGroups.json file + */ +void MaterialBrowserModel::loadPropertyGroups(const QString &path) +{ + bool ok = true; + + if (m_propertyGroupsObj.isEmpty()) { + QFile matPropsFile(path); + + if (!matPropsFile.open(QIODevice::ReadOnly)) { + qWarning("Couldn't open propertyGroups.json"); + ok = false; + } + + if (ok) { + QJsonDocument matPropsJsonDoc = QJsonDocument::fromJson(matPropsFile.readAll()); + if (matPropsJsonDoc.isNull()) { + qWarning("Invalid propertyGroups.json file"); + ok = false; + } else { + m_propertyGroupsObj = matPropsJsonDoc.object(); + } + } + } + + m_defaultMaterialSections.clear(); + m_principledMaterialSections.clear(); + m_customMaterialSections.clear(); + if (ok) { + m_defaultMaterialSections.append(m_propertyGroupsObj.value("DefaultMaterial").toObject().keys()); + m_principledMaterialSections.append(m_propertyGroupsObj.value("PrincipledMaterial").toObject().keys()); + + QStringList customMatSections = m_propertyGroupsObj.value("CustomMaterial").toObject().keys(); + if (customMatSections.size() > 1) // as of now custom material has only 1 section, so we don't add it + m_customMaterialSections.append(customMatSections); + } + emit materialSectionsChanged(); +} + QHash MaterialBrowserModel::roleNames() const { static const QHash roles { @@ -138,12 +186,12 @@ void MaterialBrowserModel::setHasMaterialRoot(bool b) emit hasMaterialRootChanged(); } -TypeName MaterialBrowserModel::copiedMaterialType() const +QString MaterialBrowserModel::copiedMaterialType() const { return m_copiedMaterialType; } -void MaterialBrowserModel::setCopiedMaterialType(const TypeName &matType) +void MaterialBrowserModel::setCopiedMaterialType(const QString &matType) { if (matType == m_copiedMaterialType) return; @@ -294,16 +342,40 @@ void MaterialBrowserModel::duplicateMaterial(int idx) emit duplicateMaterialTriggered(m_materialList.at(idx)); } -void MaterialBrowserModel::copyMaterialProperties(int idx) +void MaterialBrowserModel::copyMaterialProperties(int idx, const QString §ion) { ModelNode mat = m_materialList.at(idx); - m_copiedMaterialProps = mat.properties(); - setCopiedMaterialType(mat.type()); + QString matType = QString::fromLatin1(mat.type()); + + if (matType.startsWith("QtQuick3D.")) + matType.remove("QtQuick3D."); + + setCopiedMaterialType(matType); + m_allPropsCopied = section == "All"; + + if (m_allPropsCopied || m_propertyGroupsObj.empty()) { + m_copiedMaterialProps = mat.properties(); + } else { + QJsonObject propsSpecObj = m_propertyGroupsObj.value(m_copiedMaterialType).toObject(); + if (propsSpecObj.contains(section)) { // should always be true + m_copiedMaterialProps.clear(); + const QJsonArray propNames = propsSpecObj.value(section).toArray(); + for (const QJsonValueRef &propName : propNames) + m_copiedMaterialProps.append(mat.property(propName.toString().toLatin1())); + + if (section == "Base") { // add QtQuick3D.Material base props as well + QJsonObject propsMatObj = m_propertyGroupsObj.value("Material").toObject(); + const QJsonArray propNames = propsMatObj.value("Base").toArray(); + for (const QJsonValueRef &propName : propNames) + m_copiedMaterialProps.append(mat.property(propName.toString().toLatin1())); + } + } + } } void MaterialBrowserModel::pasteMaterialProperties(int idx) { - emit pasteMaterialPropertiesTriggered(m_materialList.at(idx), m_copiedMaterialProps); + emit pasteMaterialPropertiesTriggered(m_materialList.at(idx), m_copiedMaterialProps, m_allPropsCopied); } void MaterialBrowserModel::deleteMaterial(int idx) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h index bafcdc1fa8f..5f38e7488eb 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h @@ -25,6 +25,7 @@ #pragma once +#include "qjsonobject.h" #include #include @@ -43,7 +44,10 @@ class MaterialBrowserModel : public QAbstractListModel Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged) Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged) Q_PROPERTY(bool hasMaterialRoot READ hasMaterialRoot WRITE setHasMaterialRoot NOTIFY hasMaterialRootChanged) - Q_PROPERTY(TypeName copiedMaterialType READ copiedMaterialType WRITE setCopiedMaterialType NOTIFY copiedMaterialTypeChanged) + Q_PROPERTY(QString copiedMaterialType READ copiedMaterialType WRITE setCopiedMaterialType NOTIFY copiedMaterialTypeChanged) + Q_PROPERTY(QStringList defaultMaterialSections MEMBER m_defaultMaterialSections NOTIFY materialSectionsChanged) + Q_PROPERTY(QStringList principledMaterialSections MEMBER m_principledMaterialSections NOTIFY materialSectionsChanged) + Q_PROPERTY(QStringList customMaterialSections MEMBER m_customMaterialSections NOTIFY materialSectionsChanged) public: MaterialBrowserModel(QObject *parent = nullptr); @@ -64,8 +68,8 @@ public: bool hasMaterialRoot() const; void setHasMaterialRoot(bool b); - TypeName copiedMaterialType() const; - void setCopiedMaterialType(const TypeName &matType); + QString copiedMaterialType() const; + void setCopiedMaterialType(const QString &matType); QList materials() const; void setMaterials(const QList &materials, bool hasQuick3DImport); @@ -75,12 +79,13 @@ public: void updateSelectedMaterial(); int materialIndex(const ModelNode &material) const; ModelNode materialAt(int idx) const; + void loadPropertyGroups(const QString &path); void resetModel(); Q_INVOKABLE void selectMaterial(int idx, bool force = false); Q_INVOKABLE void duplicateMaterial(int idx); - Q_INVOKABLE void copyMaterialProperties(int idx); + Q_INVOKABLE void copyMaterialProperties(int idx, const QString §ion); Q_INVOKABLE void pasteMaterialProperties(int idx); Q_INVOKABLE void deleteMaterial(int idx); Q_INVOKABLE void renameMaterial(int idx, const QString &newName); @@ -94,13 +99,15 @@ signals: void hasModelSelectionChanged(); void hasMaterialRootChanged(); void copiedMaterialTypeChanged(); + void materialSectionsChanged(); void selectedIndexChanged(int idx); void renameMaterialTriggered(const QmlDesigner::ModelNode &material, const QString &newName); void applyToSelectedTriggered(const QmlDesigner::ModelNode &material, bool add = false); void addNewMaterialTriggered(); void duplicateMaterialTriggered(const QmlDesigner::ModelNode &material); void pasteMaterialPropertiesTriggered(const QmlDesigner::ModelNode &material, - const QList &props); + const QList &props, + bool all); private: bool isMaterialVisible(int idx) const; @@ -108,15 +115,20 @@ private: QString m_searchText; QList m_materialList; + QStringList m_defaultMaterialSections; + QStringList m_principledMaterialSections; + QStringList m_customMaterialSections; QList m_copiedMaterialProps; QHash m_materialIndexHash; // internalId -> index + QJsonObject m_propertyGroupsObj; int m_selectedIndex = 0; bool m_isEmpty = true; bool m_hasQuick3DImport = false; bool m_hasModelSelection = false; bool m_hasMaterialRoot = false; - TypeName m_copiedMaterialType; + bool m_allPropsCopied = true; + QString m_copiedMaterialType; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index ac792f64709..0d05b12d6a1 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -29,6 +29,7 @@ #include "materialbrowserwidget.h" #include "materialbrowsermodel.h" #include "nodeabstractproperty.h" +#include "nodemetainfo.h" #include "qmlobjectnode.h" #include "variantproperty.h" @@ -43,7 +44,6 @@ namespace QmlDesigner { MaterialBrowserView::MaterialBrowserView(QObject *parent) : AbstractView(parent) - {} MaterialBrowserView::~MaterialBrowserView() @@ -91,14 +91,16 @@ WidgetInfo MaterialBrowserView::widgetInfo() }); connect(matBrowserModel, &MaterialBrowserModel::pasteMaterialPropertiesTriggered, this, - [&] (const ModelNode &material, const QList &props) { + [&] (const ModelNode &material, const QList &props, bool all) { QmlObjectNode mat(material); executeInTransaction(__FUNCTION__, [&] { - // remove current properties - const PropertyNameList propNames = material.propertyNames(); - for (const PropertyName &propName : propNames) { - if (propName != "objectName") - mat.removeProperty(propName); + if (all) { // all material properties copied + // remove current properties + const PropertyNameList propNames = material.propertyNames(); + for (const PropertyName &propName : propNames) { + if (propName != "objectName") + mat.removeProperty(propName); + } } // apply pasted properties @@ -126,6 +128,10 @@ void MaterialBrowserView::modelAttached(Model *model) { AbstractView::modelAttached(model); + QString matPropsPath = model->metaInfo("QtQuick3D.Material").importDirectoryPath() + + "/designer/propertyGroups.json"; + m_widget->materialBrowserModel()->loadPropertyGroups(matPropsPath); + m_widget->clearSearchFilter(); m_widget->materialBrowserModel()->setHasMaterialRoot(rootModelNode().isSubclassOf("QtQuick3D.Material")); m_hasQuick3DImport = model->hasImport("QtQuick3D"); From 56b0fab13eadccdb881437d977ae509d03f291f3 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 18 Aug 2022 18:31:53 +0200 Subject: [PATCH 41/43] QmlDesigner: Fix debug compilation error In WelcomeMode accidentally the wrong widget was used. Fix by replacing m_modeWidget (QWidget) with m_quickWidget (QQuickWidget). Change-Id: Ie04dc3a2cc843ee4d430c3cefba6c48697c6046f Reviewed-by: Tim Jenssen --- src/plugins/studiowelcome/studiowelcomeplugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index c7845f231ec..f78bc1ca626 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -733,10 +733,10 @@ void WelcomeMode::setupQuickWidget(const QString &welcomePagePath) if (!useNewWelcomePage()) { #ifdef QT_DEBUG - m_modeWidget->engine()->addImportPath(QLatin1String(STUDIO_QML_PATH) - + "welcomepage/imports"); - m_modeWidget->setSource(QUrl::fromLocalFile(QLatin1String(STUDIO_QML_PATH) - + "welcomepage/main.qml")); + m_quickWidget->engine()->addImportPath(QLatin1String(STUDIO_QML_PATH) + + "welcomepage/imports"); + m_quickWidget->setSource( + QUrl::fromLocalFile(QLatin1String(STUDIO_QML_PATH) + "welcomepage/main.qml")); #else m_quickWidget->engine()->addImportPath("qrc:/qml/welcomepage/imports"); m_quickWidget->setSource(QUrl("qrc:/qml/welcomepage/main.qml")); From 814115256ce9d0f03fda593c8e1e4df9a0b81024 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 10 Aug 2022 12:24:13 +0300 Subject: [PATCH 42/43] Doc: Update info on how to get Bridges Qt Bridges are nowadays avaialble in the QDS enterprise license. Task-number: QDS-7356 Change-Id: Iec78d8879698462292626c413bfc0810e68c40b7 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc | 6 ++---- doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc | 8 ++++---- .../src/qtbridge/qtbridge-sketch-setup.qdoc | 8 ++++---- doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc | 8 ++++---- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc index bc27d5e3484..b8b787face3 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc @@ -43,10 +43,8 @@ \section1 2D Assets - You can use the Qt Installer to install \QB if you have a commercial - \QDS license. You can also purchase a \QB license separately from the - \l{https://marketplace.qt.io/}{Qt Marketplace} and then install \QB using - the Qt Installer. + You can use the Qt Installer to install \QB if you have a + \QDS enterprise license. \table \row diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc index ba43f329238..8dc0620032f 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc @@ -30,10 +30,10 @@ \title Setting Up \QBPS - You can purchase a \QBPS license from the \l{https://marketplace.qt.io/} - {Qt Marketplace}, and then use the Qt Installer to have the \QBPS - installation package copied to the following path in your Qt installation - folder: + \QBPS is included in the + \l{https://www.qt.io/pricing}{Qt Design Studio Enterprise license}. + You can use the Qt Installer to have the \QBPS plugin package copied to the + following path in your Qt installation folder: \list \li On Windows: \c {Tools\QtDesignStudio\photoshop_bridge} diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-setup.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-setup.qdoc index 6f883a1f859..dd507243507 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-setup.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-setup.qdoc @@ -30,10 +30,10 @@ \title Setting Up \QBSK - You can purchase a \QBSK license from the \l{https://marketplace.qt.io/} - {Qt Marketplace}, and then use the Qt Installer to have the \QBSK - plugin package copied to the following path in your Qt installation - folder: + \QBSK is included in the + \l{https://www.qt.io/pricing}{Qt Design Studio Enterprise license}. + You can use the Qt Installer to have the \QBSK plugin package copied to the + following path in your Qt installation folder: \list \li On Windows: diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc index 8ecead5647e..58959166751 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc @@ -30,10 +30,10 @@ \title Setting Up \QBXD - You can purchase a \QBXD license from the \l{https://marketplace.qt.io/} - {Qt Marketplace}, and then use the Qt Installer to have the \QBXD - plugin package copied to the following path in your Qt installation - folder: + \QBXD is included in the + \l{https://www.qt.io/pricing}{Qt Design Studio Enterprise license}. + You can use the Qt Installer to have the \QBXD plugin package copied to the + following path in your Qt installation folder: \list \li On Windows: From 0fc8e31af9e3dcf47bbe4520a980e4fc3cfd4438 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 18 Aug 2022 14:19:26 +0200 Subject: [PATCH 43/43] QmlDesigner: Fix some more license headers Change-Id: I19419745ce79a339875e92e86d7e599a8c2ddeb0 Reviewed-by: Lucie Gerard Reviewed-by: Thomas Hartmann Reviewed-by: --- .../qmldesigner/studioplugin/studioplugin.cpp | 25 ++++++++++++------- .../qmldesigner/studioplugin/studioplugin.h | 25 ++++++++++++------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/plugins/qmldesigner/studioplugin/studioplugin.cpp b/src/plugins/qmldesigner/studioplugin/studioplugin.cpp index 6d3f7b8e8b4..313d97c1238 100644 --- a/src/plugins/qmldesigner/studioplugin/studioplugin.cpp +++ b/src/plugins/qmldesigner/studioplugin/studioplugin.cpp @@ -1,18 +1,25 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Qt Enterprise QML Live Preview Add-on. +** This file is part of Qt Creator. ** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ diff --git a/src/plugins/qmldesigner/studioplugin/studioplugin.h b/src/plugins/qmldesigner/studioplugin/studioplugin.h index 28f04a7d110..5543b03946b 100644 --- a/src/plugins/qmldesigner/studioplugin/studioplugin.h +++ b/src/plugins/qmldesigner/studioplugin/studioplugin.h @@ -1,18 +1,25 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Qt Enterprise QML Live Preview Add-on. +** This file is part of Qt Creator. ** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/