From 89d36b418ae980e1db766c54d9b444b4932472c2 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 12 Oct 2020 21:19:44 +0200 Subject: [PATCH 01/21] Make Help mode Squish-testable again Change-Id: I09bcdb63c44c4728cce63d5a5c2b29bf9fc96ac1 Reviewed-by: Eike Ziller --- src/plugins/help/qlitehtml/qlitehtmlwidget.h | 8 +++++--- tests/system/shared/utils.py | 6 +++--- tests/system/suite_HELP/tst_HELP04/test.py | 16 +++------------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/plugins/help/qlitehtml/qlitehtmlwidget.h b/src/plugins/help/qlitehtml/qlitehtmlwidget.h index 5da2c90c72d..740ea27d54f 100644 --- a/src/plugins/help/qlitehtml/qlitehtmlwidget.h +++ b/src/plugins/help/qlitehtml/qlitehtmlwidget.h @@ -41,10 +41,11 @@ public: explicit QLiteHtmlWidget(QWidget *parent = nullptr); ~QLiteHtmlWidget() override; + // declaring the getters Q_INVOKABLE to make them Squish-testable void setUrl(const QUrl &url); - QUrl url() const; + Q_INVOKABLE QUrl url() const; void setHtml(const QString &content); - QString title() const; + Q_INVOKABLE QString title() const; void setZoomFactor(qreal scale); qreal zoomFactor() const; @@ -62,7 +63,8 @@ public: using ResourceHandler = std::function; void setResourceHandler(const ResourceHandler &handler); - QString selectedText() const; + // declaring this Q_INVOKABLE to make it Squish-testable + Q_INVOKABLE QString selectedText() const; signals: void linkClicked(const QUrl &url); diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py index 26afa78c8a6..e3adb5c49d5 100644 --- a/tests/system/shared/utils.py +++ b/tests/system/shared/utils.py @@ -670,9 +670,9 @@ def getChildByClass(parent, classToSearchFor, occurrence=1): return children[occurrence - 1] def getHelpViewer(): - return waitForObject("{type='Help::Internal::TextBrowserHelpWidget' unnamed='1' " - "visible='1' window=':Qt Creator_Core::Internal::MainWindow'}", + return waitForObject("{type='QLiteHtmlWidget' unnamed='1' visible='1' " + "window=':Qt Creator_Core::Internal::MainWindow'}", 1000) def getHelpTitle(): - return str(getHelpViewer().documentTitle) + return str(getHelpViewer().title()) diff --git a/tests/system/suite_HELP/tst_HELP04/test.py b/tests/system/suite_HELP/tst_HELP04/test.py index 8a3049c173a..18e3ee45639 100644 --- a/tests/system/suite_HELP/tst_HELP04/test.py +++ b/tests/system/suite_HELP/tst_HELP04/test.py @@ -32,27 +32,17 @@ urlDictionary = { "abundance":"qthelp://com.trolltech.qt.487/qdoc/gettingstarted def __getSelectedText__(): - hv = getHelpViewer() try: - return hv.textCursor().selectedText() - except: - pass - try: - test.log("Falling back to searching for selection in HTML.") - return getHighlightsInHtml(str(hv.toHtml())) + return str(getHelpViewer().selectedText()) except: test.warning("Could not get highlighted text.") return str("") def __getUrl__(): - helpViewer = getHelpViewer() try: - url = helpViewer.url + url = getHelpViewer().url() except: - try: - url = helpViewer.source - except: - return "" + return "" return str(url.scheme) + "://" + str(url.host) + str(url.path) def getHighlightsInHtml(htmlCode): From b1cd859219442de9f021466efd71858ac17aec11 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 22 Oct 2020 14:48:33 +0300 Subject: [PATCH 02/21] VcsManager: Fix adding files to VCS from locator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The files are listed by file name without path, so git add was executed from the user's working directory instead of the target directory. Amends commit 48c56416f5e128c04f2d2d867b518775e0527607. Change-Id: Iba7c5ff33378265d3c22479d7abb6ccf8db75d07 Reviewed-by: Eike Ziller Reviewed-by: André Hartmann --- src/plugins/coreplugin/vcsmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index 96beaf565f1..0dbd72e88c0 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -445,7 +445,7 @@ void VcsManager::promptToAdd(const QString &directory, const QStringList &fileNa if (dlg.exec() == QDialog::Accepted) { QStringList notAddedToVc; foreach (const QString &file, unmanagedFiles) { - if (!vc->vcsAdd(file)) + if (!vc->vcsAdd(QDir(directory).filePath(file))) notAddedToVc << file; } From 98a649ccfd96e542b05024e67e4af82f7cd1d60f Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 21 Oct 2020 20:35:46 +0200 Subject: [PATCH 03/21] Fix crash for missing BuildSystem There is no gurantee that a Target has a BuildSystem. Target::additionalData() does expect a BuildSystem. Task-number: QTCREATORBUG-24817 Change-Id: I41edf89fa6dbf6ed24a27129b8353a9506b7b176 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/target.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index 5d253eb0977..3e83ae80867 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -775,7 +775,10 @@ void Target::setNamedSettings(const QString &name, const QVariant &value) QVariant Target::additionalData(Utils::Id id) const { - return buildSystem()->additionalData(id); + if (const BuildSystem *bs = buildSystem()) + return bs->additionalData(id); + + return {}; } MakeInstallCommand Target::makeInstallCommand(const QString &installRoot) const From c2913f65e4d8a54c374fd6a72025e24a3c8f7321 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 22 Oct 2020 15:58:47 +0200 Subject: [PATCH 04/21] QbsProjectManager: Do not cache incomplete environment Retrieving the run environment for a qbs product can fail if the qbs session is busy at the time of the call. In such a case, caching the result will cause subsequent accesses to retrieve an incomplete environment. This patch fixes the latter problem. Task-number: QTCREATORBUG-24599 Change-Id: Ia0c6831cf371995ac8399d15e4dd93b8bb6e4f3b Reviewed-by: Mitch Curtis --- src/plugins/qbsprojectmanager/qbsproject.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index ba15c006754..2258a99e279 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -1121,13 +1121,13 @@ void QbsBuildSystem::updateApplicationTargets() if (result.error().hasError()) { Core::MessageManager::write(tr("Error retrieving run environment: %1") .arg(result.error().toString())); - } else { - QProcessEnvironment fullEnv = result.environment(); - QTC_ASSERT(!fullEnv.isEmpty(), fullEnv = procEnv); - env = Utils::Environment(); - for (const QString &key : fullEnv.keys()) - env.set(key, fullEnv.value(key)); + return; } + QProcessEnvironment fullEnv = result.environment(); + QTC_ASSERT(!fullEnv.isEmpty(), fullEnv = procEnv); + env = Utils::Environment(); + for (const QString &key : fullEnv.keys()) + env.set(key, fullEnv.value(key)); m_envCache.insert(key, env); }; From c9c0e80339c803b6c6b871d5aca52f107c02260e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 22 Oct 2020 17:00:19 +0200 Subject: [PATCH 05/21] Qmake: Fix wildcard expansion for absolute paths Wildcard expansion for e.g. deployment purposes was implemented, but accidentally only for relative file paths. Amends 9e32603c3d. Fixes: QTCREATORBUG-24695 Change-Id: Iab5c761ad68c2d4facecef5b44e6e50e66ed4941 Reviewed-by: Joerg Bornemann --- src/shared/proparser/profileevaluator.cpp | 46 +++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index 131105b91f3..e1e5e32f035 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -86,32 +86,32 @@ QVector ProFileEvaluator::fixifiedValues( QVector result; foreach (const ProString &str, d->values(ProKey(variable))) { const QString &el = d->m_option->expandEnvVars(str.toQString()); - if (IoUtils::isAbsolutePath(el)) { - result << SourceFile{QDir::cleanPath(el), str.sourceFile()}; + const QString fn = IoUtils::isAbsolutePath(el) + ? QDir::cleanPath(el) : QDir::cleanPath(baseDirectory + QLatin1Char('/') + el); + if (IoUtils::exists(fn)) { + result << SourceFile{fn, str.sourceFile()}; + continue; + } + QStringView fileNamePattern; + if (expandWildcards) { + fileNamePattern = IoUtils::fileName(fn); + expandWildcards = fileNamePattern.contains('*') || fileNamePattern.contains('?'); + } + if (expandWildcards) { + const QString patternBaseDir = IoUtils::pathName(fn).toString(); + const QDir::Filters filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot; + for (const QString &fileName : QDir(patternBaseDir).entryList( + QStringList(fileNamePattern.toString()), filters)) { + const QString fullFilePath + = QDir::cleanPath(patternBaseDir + '/' + fileName); + result << SourceFile({fullFilePath, str.sourceFile()}); + } } else { - QString fn = QDir::cleanPath(baseDirectory + QLatin1Char('/') + el); - if (IoUtils::exists(fn)) { + if (IoUtils::isAbsolutePath(el)) { result << SourceFile{fn, str.sourceFile()}; } else { - QStringView fileNamePattern; - if (expandWildcards) { - fileNamePattern = IoUtils::fileName(fn); - expandWildcards = fileNamePattern.contains('*') - || fileNamePattern.contains('?'); - } - if (expandWildcards) { - const QString patternBaseDir = IoUtils::pathName(fn).toString(); - const QDir::Filters filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot; - for (const QString &fileName : QDir(patternBaseDir).entryList( - QStringList(fileNamePattern.toString()), filters)) { - const QString fullFilePath - = QDir::cleanPath(patternBaseDir + '/' + fileName); - result << SourceFile({fullFilePath, str.sourceFile()}); - } - } else { - result << SourceFile{QDir::cleanPath(buildDirectory + QLatin1Char('/') + el), - str.sourceFile()}; - } + result << SourceFile{QDir::cleanPath(buildDirectory + QLatin1Char('/') + el), + str.sourceFile()}; } } } From 8d8473daf6bab11be1c58c2187e699ce816f1631 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 22 Oct 2020 17:08:21 +0200 Subject: [PATCH 06/21] Debugger: Fix compiler warning in dumper test Change-Id: I9f3633065890bb5e574fd688b39b0bc93a94c8b1 Reviewed-by: David Schulz --- tests/auto/debugger/tst_dumpers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 657dadb2d85..4b0704efc1d 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -519,6 +519,7 @@ enum AdditionalCriteria static bool matchesAdditionalCriteria(int criteria) { #ifdef Q_OS_UNIX + Q_UNUSED(criteria) return true; #else return !(criteria & NeedsInferiorCall); From 2bf40dddfdff769c9cb377b0205a28ad3597349c Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 22 Oct 2020 23:25:27 +0300 Subject: [PATCH 07/21] QmlDesigner: Fix copy / paste bug Fix a bug in calculating the scatter value when pasting an object. Also some tweaks and clean ups in the same file. Fixes: QDS-2982 Change-Id: Ic2847d03ccf03d188c5fbca2cd14bc74b9d20223 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../components/integration/designdocument.cpp | 83 +++++++++---------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index b572d55f0b4..ea471f530da 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -217,6 +217,7 @@ Utils::FilePath DesignDocument::fileName() const { if (editor()) return editor()->document()->filePath(); + return Utils::FilePath(); } @@ -239,14 +240,11 @@ void DesignDocument::loadDocument(QPlainTextEdit *edit) { Q_CHECK_PTR(edit); - connect(edit, &QPlainTextEdit::undoAvailable, - this, &DesignDocument::undoAvailable); - connect(edit, &QPlainTextEdit::redoAvailable, - this, &DesignDocument::redoAvailable); - connect(edit, &QPlainTextEdit::modificationChanged, - this, &DesignDocument::dirtyStateChanged); + connect(edit, &QPlainTextEdit::undoAvailable, this, &DesignDocument::undoAvailable); + connect(edit, &QPlainTextEdit::redoAvailable, this, &DesignDocument::redoAvailable); + connect(edit, &QPlainTextEdit::modificationChanged, this, &DesignDocument::dirtyStateChanged); - m_documentTextModifier.reset(new BaseTextEditModifier(dynamic_cast(plainTextEdit()))); + m_documentTextModifier.reset(new BaseTextEditModifier(qobject_cast(plainTextEdit()))); connect(m_documentTextModifier.data(), &TextModifier::textChanged, this, &DesignDocument::updateQrcFiles); @@ -266,7 +264,6 @@ void DesignDocument::changeToDocumentModel() viewManager().detachRewriterView(); viewManager().detachViewsExceptRewriterAndComponetView(); - m_inFileComponentModel.reset(); viewManager().attachRewriterView(); @@ -299,7 +296,8 @@ void DesignDocument::updateQrcFiles() ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(fileName()); if (currentProject) { - for (const Utils::FilePath &fileName : currentProject->files(ProjectExplorer::Project::SourceFiles)) { + const auto srcFiles = currentProject->files(ProjectExplorer::Project::SourceFiles); + for (const Utils::FilePath &fileName : srcFiles) { if (fileName.endsWith(".qrc")) QmlJS::ModelManagerInterface::instance()->updateQrcFile(fileName.toString()); } @@ -350,6 +348,7 @@ bool DesignDocument::isUndoAvailable() const { if (plainTextEdit()) return plainTextEdit()->document()->isUndoAvailable(); + return false; } @@ -357,6 +356,7 @@ bool DesignDocument::isRedoAvailable() const { if (plainTextEdit()) return plainTextEdit()->document()->isRedoAvailable(); + return false; } @@ -408,9 +408,8 @@ void DesignDocument::deleteSelected() return; } - rewriterView()->executeInTransaction("DesignDocument::deleteSelected", [this](){ - QList toDelete = view()->selectedModelNodes(); - + rewriterView()->executeInTransaction("DesignDocument::deleteSelected", [this]() { + const QList toDelete = view()->selectedModelNodes(); for (ModelNode node : toDelete) { if (node.isValid() && !node.isRootNode() && QmlObjectNode::isValidQmlObjectNode(node)) QmlObjectNode(node).destroy(); @@ -442,32 +441,33 @@ static void scatterItem(const ModelNode &pastedNode, const ModelNode &targetNode return; bool scatter = false; - foreach (const ModelNode &childNode, targetNode.directSubModelNodes()) { - if ((childNode.variantProperty("x").value() == pastedNode.variantProperty("x").value()) && - (childNode.variantProperty("y").value() == pastedNode.variantProperty("y").value())) + for (const ModelNode &childNode : targetNode.directSubModelNodes()) { + if (childNode.variantProperty("x").value() == pastedNode.variantProperty("x").value() && + childNode.variantProperty("y").value() == pastedNode.variantProperty("y").value()) { scatter = true; + break; + } } if (!scatter) return; - if (offset == -2000) { + if (offset == -2000) { // scatter in range double x = pastedNode.variantProperty("x").value().toDouble(); double y = pastedNode.variantProperty("y").value().toDouble(); - double targetWidth = 20; - double targetHeight = 20; - x = x + double(QRandomGenerator::global()->generate()) / RAND_MAX * targetWidth - - targetWidth / 2; - y = y + double(QRandomGenerator::global()->generate()) / RAND_MAX * targetHeight - - targetHeight / 2; - pastedNode.variantProperty("x").setValue(int(x)); - pastedNode.variantProperty("y").setValue(int(y)); - } else { - double x = pastedNode.variantProperty("x").value().toDouble(); - double y = pastedNode.variantProperty("y").value().toDouble(); - x = x + offset; - y = y + offset; + + const double scatterRange = 20.; + x += QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2; + y += QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2; + pastedNode.variantProperty("x").setValue(int(x)); pastedNode.variantProperty("y").setValue(int(y)); + } else { // offset + int x = pastedNode.variantProperty("x").value().toInt(); + int y = pastedNode.variantProperty("y").value().toInt(); + x += offset; + y += offset; + pastedNode.variantProperty("x").setValue(x); + pastedNode.variantProperty("y").setValue(y); } } @@ -495,7 +495,7 @@ void DesignDocument::paste() if (!view.selectedModelNodes().isEmpty()) targetNode = view.selectedModelNodes().constFirst(); - //In case we copy and paste a selection we paste in the parent item + // in case we copy and paste a selection we paste in the parent item if ((view.selectedModelNodes().count() == selectedNodes.count()) && targetNode.isValid() && targetNode.hasParentProperty()) { targetNode = targetNode.parentProperty().parentModelNode(); } else { @@ -516,19 +516,20 @@ void DesignDocument::paste() if (!targetNode.isValid()) targetNode = view.rootModelNode(); - foreach (const ModelNode &node, selectedNodes) { - foreach (const ModelNode &node2, selectedNodes) { + for (const ModelNode &node : qAsConst(selectedNodes)) { + for (const ModelNode &node2 : qAsConst(selectedNodes)) { if (node.isAncestorOf(node2)) selectedNodes.removeAll(node2); } } - rewriterView()->executeInTransaction("DesignDocument::paste1", [&view, selectedNodes, targetNode](){ + rewriterView()->executeInTransaction("DesignDocument::paste1", [&view, selectedNodes, targetNode]() { QList pastedNodeList; - int offset = double(QRandomGenerator::global()->generate()) / RAND_MAX * 20 - 10; + const double scatterRange = 20.; + int offset = QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2; - foreach (const ModelNode &node, selectedNodes) { + for (const ModelNode &node : qAsConst(selectedNodes)) { PropertyName defaultProperty(targetNode.metaInfo().defaultPropertyName()); ModelNode pastedNode(view.insertModel(node)); pastedNodeList.append(pastedNode); @@ -572,11 +573,11 @@ void DesignDocument::paste() PropertyName defaultProperty(targetNode.metaInfo().defaultPropertyName()); scatterItem(pastedNode, targetNode); - if (targetNode.metaInfo().propertyIsListProperty(defaultProperty)) { + if (targetNode.metaInfo().propertyIsListProperty(defaultProperty)) targetNode.nodeListProperty(defaultProperty).reparentHere(pastedNode); - } else { + else qWarning() << "Cannot reparent to" << targetNode; - } + view.setSelectedModelNodes({pastedNode}); }); view.model()->clearMetaInfoCache(); @@ -591,7 +592,6 @@ void DesignDocument::selectAll() DesignDocumentView view; currentModel()->attachView(&view); - QList allNodesExceptRootNode(view.allModelNodes()); allNodesExceptRootNode.removeOne(view.rootModelNode()); view.setSelectedModelNodes(allNodesExceptRootNode); @@ -607,7 +607,6 @@ void DesignDocument::setEditor(Core::IEditor *editor) m_textEditor = editor; // if the user closed the file explicit we do not want to do anything with it anymore - connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave, this, [this](Core::IDocument *document) { if (m_textEditor && m_textEditor->document() == document) { @@ -622,8 +621,7 @@ void DesignDocument::setEditor(Core::IEditor *editor) m_textEditor.clear(); }); - connect(editor->document(), &Core::IDocument::filePathChanged, - this, &DesignDocument::updateFileName); + connect(editor->document(), &Core::IDocument::filePathChanged, this, &DesignDocument::updateFileName); updateActiveTarget(); updateActiveTarget(); @@ -678,7 +676,6 @@ static Target *getActiveTarget(DesignDocument *designDocument) if (!currentProject) return nullptr; - QObject::connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, designDocument, &DesignDocument::updateActiveTarget, Qt::UniqueConnection); From 28022d8e04303268becd61dd6fb20b506189fe9c Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 23 Oct 2020 12:56:57 +0200 Subject: [PATCH 08/21] QmlDesigner: Remove Quick3D dependencies from ModelNode2DImageView.qml Change-Id: Idf19019dbeebf8f3f09309a724727a4aa643ce25 Reviewed-by: Miikka Heikkinen --- .../qtcreator/qml/qmlpuppet/mockfiles/ModelNode2DImageView.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode2DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode2DImageView.qml index 23025477157..ea0498927fd 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode2DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode2DImageView.qml @@ -24,7 +24,6 @@ ****************************************************************************/ import QtQuick 2.15 -import QtQuick3D 1.15 Item { id: root @@ -33,10 +32,12 @@ Item { property alias contentItem: contentItem + /* View3D { // Dummy view to hold the context in case View3D items are used in the component // TODO remove when QTBUG-87678 is fixed } + */ Item { id: contentItem From 8848eb7d7e11f10291f8fb970e75d03a0b66706b Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Thu, 22 Oct 2020 14:18:13 +0200 Subject: [PATCH 09/21] AssetExport: Use QFontInfo for font properties Task-number: QDS-2867 Change-Id: I7a5d622f4f43cc8a73e29950616595a314bb6ffc Reviewed-by: Thomas Hartmann --- .../assetexporterplugin/parsers/textnodeparser.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/assetexporterplugin/parsers/textnodeparser.cpp b/src/plugins/qmldesigner/assetexporterplugin/parsers/textnodeparser.cpp index 9b797ad77db..dfbc78a75d9 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/parsers/textnodeparser.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/parsers/textnodeparser.cpp @@ -27,6 +27,7 @@ #include "assetexportpluginconstants.h" #include +#include #include namespace { @@ -68,10 +69,14 @@ QJsonObject TextNodeParser::json(Component &component) const QJsonObject textDetails; textDetails.insert(TextContentTag, propertyValue("text").toString()); - textDetails.insert(FontFamilyTag, propertyValue("font.family").toString()); - textDetails.insert(FontStyleTag, propertyValue("font.styleName").toString()); - textDetails.insert(FontSizeTag, propertyValue("font.pixelSize").toInt()); - textDetails.insert(LetterSpacingTag, propertyValue("font.letterSpacing").toFloat()); + + QFont font = propertyValue("font").value(); + QFontInfo fontInfo(font); + textDetails.insert(FontFamilyTag, fontInfo.family()); + textDetails.insert(FontStyleTag, fontInfo.styleName()); + textDetails.insert(FontSizeTag, fontInfo.pixelSize()); + textDetails.insert(LetterSpacingTag, font.letterSpacing()); + QColor fontColor(propertyValue("font.color").toString()); textDetails.insert(TextColorTag, fontColor.name(QColor::HexArgb)); From 916db8e78161c4f840ea5f5f3dea7092f7aa8e81 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 23 Oct 2020 13:58:01 +0200 Subject: [PATCH 10/21] Utils: Use std::stable_sort() in Utils::sort() Potentially makes for a more consistent user experience, and does fix some CppTools test failures on macOS. Change-Id: I5bfd7a2460248450ad92259956598532fb7fb8ee Reviewed-by: Eike Ziller --- src/libs/utils/algorithm.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/algorithm.h b/src/libs/utils/algorithm.h index e5b4396f24b..772c6b1c918 100644 --- a/src/libs/utils/algorithm.h +++ b/src/libs/utils/algorithm.h @@ -997,13 +997,13 @@ Container static_container_cast(const Container &container) template inline void sort(Container &container) { - std::sort(std::begin(container), std::end(container)); + std::stable_sort(std::begin(container), std::end(container)); } template inline void sort(Container &container, Predicate p) { - std::sort(std::begin(container), std::end(container), p); + std::stable_sort(std::begin(container), std::end(container), p); } // pointer to member @@ -1012,7 +1012,7 @@ inline void sort(Container &container, R S::*member) { auto f = std::mem_fn(member); using const_ref = typename Container::const_reference; - std::sort(std::begin(container), std::end(container), + std::stable_sort(std::begin(container), std::end(container), [&f](const_ref a, const_ref b) { return f(a) < f(b); }); @@ -1024,7 +1024,7 @@ inline void sort(Container &container, R (S::*function)() const) { auto f = std::mem_fn(function); using const_ref = typename Container::const_reference; - std::sort(std::begin(container), std::end(container), + std::stable_sort(std::begin(container), std::end(container), [&f](const_ref a, const_ref b) { return f(a) < f(b); }); From 4d8cd5fa03faf0d638827bd2714dbe8bfa6e2b8a Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 7 Oct 2020 13:19:30 +0200 Subject: [PATCH 11/21] Welcome screen: Add "Get Qt" link Change-Id: Ic3a6210a0b1600ae308bbdb43f0c50fc72d910e8 Reviewed-by: Eike Ziller --- src/plugins/welcome/images/download.png | Bin 0 -> 197 bytes src/plugins/welcome/images/download@2x.png | Bin 0 -> 264 bytes src/plugins/welcome/welcome.qrc | 2 ++ src/plugins/welcome/welcomeplugin.cpp | 1 + src/tools/icons/qtcreatoricons.svg | 18 ++++++++++++++++++ 5 files changed, 21 insertions(+) create mode 100644 src/plugins/welcome/images/download.png create mode 100644 src/plugins/welcome/images/download@2x.png diff --git a/src/plugins/welcome/images/download.png b/src/plugins/welcome/images/download.png new file mode 100644 index 0000000000000000000000000000000000000000..7b98258ac34a0ab04d18912469e8c7d67cc6a263 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd7G?$phPQVgfdte8d_r6q7#K7(G<0-ybai!& zjg8C8%j@gwpFMl_{Q2{jFJHcT_3F!)FaQ7lZFMGa!V#TpQT*%-qnyIQ zhW?H0M=WaF9?r1n*l5v~D13PivyHmw7D+$J4*3U>XKoxWNHa`koZiS1@X?c%Rc)E2 x!rRFb5+(1b1|D!D?<_ruBlRaG= zLo|ZVoeb6k+;#enq4#0H63TLwM>~1rgKCnhBM7!efMlnmhE~qtB)T~ ztee1o>yv#!^h4E!)!Pph2v{xKcThz7BTpGG*Uv7up!^w4YXf+#4m((JS~9Xb`5kDS zAY7pEghl4Z%T}I!_X3y;4C>c0@TFC-Jo(JNV#@+Y-uW9E^nO=nZa8E9C*fX{oX^oJ TIq4P#1_lOCS3j3^P6images/expandarrow.png images/expandarrow@2x.png images/border.png + images/download.png + images/download@2x.png diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index f814c9f4702..875cfb7c80f 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -287,6 +287,7 @@ public: auto l = new QVBoxLayout; l->setContentsMargins(0, 0, 0, 0); l->setSpacing(5); + l->addWidget(new IconAndLink("download", tr("Get Qt"), "https://www.qt.io/download", this)); l->addWidget(new IconAndLink("qtaccount", tr("Qt Account"), "https://account.qt.io", this)); l->addWidget(new IconAndLink("community", tr("Online Community"), "https://forum.qt.io", this)); l->addWidget(new IconAndLink("blogs", tr("Blogs"), "https://planet.qt.io", this)); diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index d1fbb86a153..40f2f2e8baf 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -7069,6 +7069,24 @@ id="path5457-0-5" style="display:inline" /> + + + + From 859d2edbb5f4edffd5e041967d2f630b059ad829 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 23 Oct 2020 10:49:37 +0200 Subject: [PATCH 12/21] TextEditor: Always destroy old context when displaying new proposal This makes sure that the old proposal widget is disconnected from the finalizeProposal slot and thus prevents resetting the currently shown proposal. Change-Id: I80d58d9a04831d464bea69697568359990ac5260 Reviewed-by: Christian Stenger Reviewed-by: Christian Kandeler --- .../texteditor/codeassist/codeassistant.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index 05f3c8ae17b..317d5a132b7 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -305,23 +305,17 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR // TODO: The proposal should own the model until someone takes it explicitly away. QScopedPointer proposalCandidate(newProposal); - bool destroyCurrentContext = false; - if (isDisplayingProposal()) { - if (!m_proposal->isFragile()) - return; - destroyCurrentContext = true; - } + if (isDisplayingProposal() && !m_proposal->isFragile()) + return; int basePosition = proposalCandidate->basePosition(); if (m_editorWidget->position() < basePosition) { - if (destroyCurrentContext) - destroyContext(); + destroyContext(); return; } if (m_abortedBasePosition == basePosition && reason != ExplicitlyInvoked) { - if (destroyCurrentContext) - destroyContext(); + destroyContext(); return; } @@ -333,8 +327,7 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR return; } - if (destroyCurrentContext) - destroyContext(); + destroyContext(); clearAbortedPosition(); m_proposal.reset(proposalCandidate.take()); From 62e84f129ab69f58e710f26f6b16f4384b1f3fe3 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sat, 24 Oct 2020 19:41:09 +0300 Subject: [PATCH 13/21] Android: fix "uninstall app first" checkbox placement Change-Id: I2f79e9a5c344e5364fa377422f682f8e0c2927e2 Reviewed-by: Alessandro Portale --- src/plugins/android/androiddeployqtstep.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 3776b55c33a..3d52d70bd9d 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -90,7 +90,8 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Utils::Id id) m_uninstallPreviousPackage = addAspect(); m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey); - m_uninstallPreviousPackage->setLabel(tr("Uninstall the existing app first")); + m_uninstallPreviousPackage->setLabel(tr("Uninstall the existing app first"), + BoolAspect::LabelPlacement::AtCheckBox); m_uninstallPreviousPackage->setValue(false); const QtSupport::BaseQtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); From 5e67bc50555d54dde97682c67cd9c325d9260023 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 23 Oct 2020 19:56:50 +0200 Subject: [PATCH 14/21] Fix build with Qt6 Add missing includes for "incomplete type" issues. Remove usage of QDesktopWidget. Don't compile native WebKit help backend (missing native widget integration). Add SvgWidget dependency. Task-number: QTCREATORBUG-24098 Change-Id: I1b3afb54d385940ff283824870fa7454866212a4 Reviewed-by: Christian Stenger --- src/libs/qmljs/qmljsdialect.h | 1 + src/plugins/cpptools/cppcodestylesettingspage.cpp | 1 + src/plugins/help/CMakeLists.txt | 2 +- src/plugins/imageviewer/CMakeLists.txt | 7 ++++++- .../projectexplorer/editorsettingspropertiespage.cpp | 5 +++++ .../components/previewtooltip/previewtooltipbackend.cpp | 4 +--- src/plugins/qmljstools/qmljscodestylesettingspage.cpp | 1 + src/plugins/texteditor/snippets/snippetssettingspage.cpp | 1 + 8 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/libs/qmljs/qmljsdialect.h b/src/libs/qmljs/qmljsdialect.h index 230642e1454..a2f28225990 100644 --- a/src/libs/qmljs/qmljsdialect.h +++ b/src/libs/qmljs/qmljsdialect.h @@ -29,6 +29,7 @@ #include +#include #include namespace QmlJS { diff --git a/src/plugins/cpptools/cppcodestylesettingspage.cpp b/src/plugins/cpptools/cppcodestylesettingspage.cpp index 1f29bac9f15..0e9d576c46b 100644 --- a/src/plugins/cpptools/cppcodestylesettingspage.cpp +++ b/src/plugins/cpptools/cppcodestylesettingspage.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/help/CMakeLists.txt b/src/plugins/help/CMakeLists.txt index 4d5fd23283e..6ed078497b3 100644 --- a/src/plugins/help/CMakeLists.txt +++ b/src/plugins/help/CMakeLists.txt @@ -32,7 +32,7 @@ extend_qtc_plugin(Help ) extend_qtc_plugin(Help - CONDITION FWWebKit AND FWAppKit + CONDITION FWWebKit AND FWAppKit AND Qt5_VERSION VERSION_LESS 6.0.0 FEATURE_INFO "Native WebKit help viewer" DEPENDS ${FWWebKit} ${FWAppKit} DEFINES QTC_MAC_NATIVE_HELPVIEWER diff --git a/src/plugins/imageviewer/CMakeLists.txt b/src/plugins/imageviewer/CMakeLists.txt index 6bf9c9693c5..5317e9321de 100644 --- a/src/plugins/imageviewer/CMakeLists.txt +++ b/src/plugins/imageviewer/CMakeLists.txt @@ -1,5 +1,10 @@ +find_package(Qt5 COMPONENTS SvgWidgets QUIET) +if (TARGET Qt5::SvgWidgets) + set(SVG_WIDGETS Qt5::SvgWidgets) +endif() + add_qtc_plugin(ImageViewer - DEPENDS OptionalSvg + DEPENDS OptionalSvg ${SVG_WIDGETS} PLUGIN_DEPENDS Core SOURCES exportdialog.cpp exportdialog.h diff --git a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp index ba76cb078eb..1a9ede8c850 100644 --- a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp @@ -26,7 +26,12 @@ #include "editorsettingspropertiespage.h" #include "editorconfiguration.h" #include "project.h" + +#include +#include #include +#include +#include #include diff --git a/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp b/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp index 559cd5c17b9..4fac1432e58 100644 --- a/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp +++ b/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp @@ -31,7 +31,6 @@ #include #include -#include #include namespace QmlDesigner { @@ -65,8 +64,7 @@ void PreviewTooltipBackend::showTooltip() }, [] {}); - auto desktopWidget = QApplication::desktop(); - auto mousePosition = desktopWidget->cursor().pos(); + auto mousePosition = QCursor::pos(); mousePosition += {20, 20}; m_tooltip->move(mousePosition); diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp index 560fce6f706..f99f98f1b36 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp @@ -30,6 +30,7 @@ #include "qmljsindenter.h" #include "qmljsqtstylecodeformatter.h" +#include #include #include #include diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.cpp b/src/plugins/texteditor/snippets/snippetssettingspage.cpp index 802c9e456e7..c69002f6b9f 100644 --- a/src/plugins/texteditor/snippets/snippetssettingspage.cpp +++ b/src/plugins/texteditor/snippets/snippetssettingspage.cpp @@ -32,6 +32,7 @@ #include "ui_snippetssettingspage.h" #include +#include #include #include #include From cc4bd3b7388f889d9fc5a8a86fba9f19c3f14c4c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 23 Oct 2020 09:55:01 +0200 Subject: [PATCH 15/21] TextEditor: Add "F1" hint to tooltip if and only if help is available Note that this does not have performance implications, as we already call HelpItem::isValid() in the same code path. Fixes: QTCREATORBUG-24782 Change-Id: I8495099c97233e4df4b8d2a30579fb6324122e92 Reviewed-by: Eike Ziller --- src/plugins/texteditor/basehoverhandler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp index 34eb326b812..f1a1053e5d9 100644 --- a/src/plugins/texteditor/basehoverhandler.cpp +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -143,9 +143,9 @@ void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos, Re void BaseHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) { - const QVariant helpItem = m_lastHelpItemIdentified.isEmpty() - ? QVariant() - : QVariant::fromValue(m_lastHelpItemIdentified); + const QVariant helpItem = m_lastHelpItemIdentified.isValid() + ? QVariant::fromValue(m_lastHelpItemIdentified) + : QVariant(); const bool extractHelp = m_lastHelpItemIdentified.isValid() && !m_lastHelpItemIdentified.isFuzzyMatch(); const QString helpContents = extractHelp ? m_lastHelpItemIdentified.firstParagraph() From 4a3bd72db8e10e77e8b52769bbfd511bccd5bafb Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 23 Oct 2020 17:45:47 +0300 Subject: [PATCH 16/21] QmlDesigner: Fix duplicate locked item entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: When selecting more than 1 ancestor of a locked item and pressing Delete, the locked item will appear duplicate in the warning message box as many times as the number of selected ancestors. Change-Id: I72c5e35edb2974da3d630a87e236b58e0d7e8ab3 Reviewed-by: Miikka Heikkinen Reviewed-by: Henning Gründl Reviewed-by: Thomas Hartmann --- .../qmldesigner/components/integration/designdocument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index ea471f530da..2b567a8e690 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -380,7 +380,7 @@ void DesignDocument::deleteSelected() QStringList lockedNodes; for (const ModelNode &modelNode : view()->selectedModelNodes()) { for (const ModelNode &node : modelNode.allSubModelNodesAndThisNode()) { - if (node.isValid() && !node.isRootNode() && node.locked()) + if (node.isValid() && !node.isRootNode() && node.locked() && !lockedNodes.contains(node.id())) lockedNodes.push_back(node.id()); } } From 98d7b5b6e5b8d25ad0e869dbeb97f6d004497537 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 23 Oct 2020 22:12:52 +0300 Subject: [PATCH 17/21] QmlDesigner: Optimize deleting nodes - remove unnecessary call to directSubModelNodes() - replace foreach with for (avoid unnecessary copies) Change-Id: I42721a4c4e69f320664af8364f8baa0df0d11459 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../designercore/model/modelnode.cpp | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp index 688dae2d074..d00294b89e0 100644 --- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp @@ -693,35 +693,33 @@ void ModelNode::removeProperty(const PropertyName &name) const model()->d->removeProperty(internalNode()->property(name)); } - /*! \brief removes this node from the node tree */ - -static QList descendantNodes(const ModelNode &parent) +static QList descendantNodes(const ModelNode &node) { - QList descendants(parent.directSubModelNodes()); - foreach (const ModelNode &child, parent.directSubModelNodes()) { + const QList children = node.directSubModelNodes(); + QList descendants = children; + for (const ModelNode &child : children) descendants += descendantNodes(child); - } + return descendants; } static void removeModelNodeFromSelection(const ModelNode &node) { - { // remove nodes from the active selection: - QList selectedList = node.view()->selectedModelNodes(); + // remove nodes from the active selection + QList selectedList = node.view()->selectedModelNodes(); - foreach (const ModelNode &childModelNode, descendantNodes(node)) - selectedList.removeAll(childModelNode); - selectedList.removeAll(node); + const QList descendants = descendantNodes(node); + for (const ModelNode &descendantNode : descendants) + selectedList.removeAll(descendantNode); - node.view()->setSelectedModelNodes(selectedList); - } + selectedList.removeAll(node); + + node.view()->setSelectedModelNodes(selectedList); } - /*! \brief complete removes this ModelNode from the Model - */ void ModelNode::destroy() { From 553929f32276d5a071c1a06d70ade50d3d28b4ad Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 26 Oct 2020 09:22:11 +0100 Subject: [PATCH 18/21] QmlDesigner: Ensure that cache directory exists We write data to the cache directory and it is easier to ensure it at the initialization of the plugin than in multiple different places. Change-Id: I2b6e5d607e1b28b13ee4968842d21d4dad7aaf15 Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/qmldesignerplugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 938a718d7c4..ff6110efb76 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -208,6 +208,8 @@ QmlDesignerPlugin::~QmlDesignerPlugin() //////////////////////////////////////////////////// bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage/* = 0*/) { + QDir{}.mkpath(Core::ICore::cacheResourcePath()); + if (!Utils::HostOsInfo::canCreateOpenGLContext(errorMessage)) return false; d = new QmlDesignerPluginPrivate; From fcb3fabd135be4d6f182b2dceefb80fba102606f Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 22 Oct 2020 09:42:36 +0200 Subject: [PATCH 19/21] QmlDesigner: Update look and feel of navigator Task-number: QDS-2880 Change-Id: I5e54e6c35afe8bd0149f35486ac308ce0ea0d59a Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../navigator/iconcheckboxitemdelegate.cpp | 33 +++-- .../components/navigator/nameitemdelegate.cpp | 140 ++++++++++-------- .../components/navigator/nameitemdelegate.h | 18 ++- .../navigator/navigatortreemodel.cpp | 13 +- .../navigator/navigatortreeview.cpp | 85 +++++++++-- .../components/navigator/navigatorview.cpp | 18 +-- .../components/navigator/navigatorview.h | 5 +- 7 files changed, 203 insertions(+), 109 deletions(-) diff --git a/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp b/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp index 5cd5721812d..9c3aab36870 100644 --- a/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp +++ b/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp @@ -32,7 +32,8 @@ #include "navigatortreemodel.h" #include "qproxystyle.h" -#include "metainfo.h" +#include +#include #include @@ -55,7 +56,7 @@ IconCheckboxItemDelegate::IconCheckboxItemDelegate(QObject *parent, QSize IconCheckboxItemDelegate::sizeHint(const QStyleOptionViewItem & /*option*/, const QModelIndex & /*modelIndex*/) const { - return {15, 20}; + return {15, 20}; } static bool isChecked(const QModelIndex &modelIndex) @@ -63,9 +64,9 @@ static bool isChecked(const QModelIndex &modelIndex) return modelIndex.model()->data(modelIndex, Qt::CheckStateRole) == Qt::Checked; } -static bool isVisible(const QModelIndex &modelIndex) +static bool isThisOrAncestorLocked(const QModelIndex &modelIndex) { - return modelIndex.model()->data(modelIndex, ItemIsVisibleRole).toBool(); + return modelIndex.model()->data(modelIndex, ItemOrAncestorLocked).toBool(); } static ModelNode getModelNode(const QModelIndex &modelIndex) @@ -82,6 +83,13 @@ void IconCheckboxItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &styleOption, const QModelIndex &modelIndex) const { + if (styleOption.state & QStyle::State_MouseOver && !isThisOrAncestorLocked(modelIndex)) + painter->fillRect(styleOption.rect.adjusted(0, delegateMargin, 0, -delegateMargin), + Theme::getColor(Theme::Color::DSsliderHandle)); + + if (styleOption.state & QStyle::State_Selected) + NavigatorTreeView::drawSelectionBackground(painter, styleOption); + bool isVisibilityIcon = modelIndex.column() != NavigatorTreeModel::ColumnType::Visibility; // We need to invert the check status if visibility icon bool checked = isVisibilityIcon ? isChecked(modelIndex) : !isChecked(modelIndex); @@ -89,10 +97,7 @@ void IconCheckboxItemDelegate::paint(QPainter *painter, return; if (rowIsPropertyRole(modelIndex.model(), modelIndex)) - return; //Do not paint icons for property rows - - if (styleOption.state & QStyle::State_Selected) - NavigatorTreeView::drawSelectionBackground(painter, styleOption); + return; // Do not paint icons for property rows if (!getModelNode(modelIndex).isRootNode()) { QWindow *window = dynamic_cast(painter->device())->window()->windowHandle(); @@ -101,17 +106,15 @@ void IconCheckboxItemDelegate::paint(QPainter *painter, const QRect iconRect(styleOption.rect.left() + 2, styleOption.rect.top() + 2, 16, 16); const QIcon &icon = isChecked(modelIndex) ? m_checkedIcon : m_uncheckedIcon; const QPixmap iconPixmap = icon.pixmap(window, iconRect.size()); - const bool visible = isVisible(modelIndex); - if (!visible) { - painter->save(); + painter->save(); + + if (isThisOrAncestorLocked(modelIndex)) painter->setOpacity(0.5); - } - painter->drawPixmap(iconRect.topLeft(), iconPixmap); + painter->drawPixmap(iconRect.topLeft() + QPoint(0, delegateMargin), iconPixmap); - if (!visible) - painter->restore(); + painter->restore(); } } diff --git a/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp b/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp index 4da4a18c05b..34e3c9881ee 100644 --- a/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp +++ b/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,8 @@ namespace QmlDesigner { +int NameItemDelegate::iconOffset = 0; + static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) { QPixmap pixmap; @@ -111,13 +114,15 @@ NameItemDelegate::NameItemDelegate(QObject *parent) static int drawIcon(QPainter *painter, const QStyleOptionViewItem &styleOption, const QModelIndex &modelIndex) { - QIcon icon = modelIndex.data(Qt::DecorationRole).value(); - - const int pixmapSize = icon.isNull() ? 4 : 16; - + const QIcon icon = modelIndex.data(Qt::DecorationRole).value(); + int pixmapSize = icon.isNull() ? 4 : 16; QPixmap pixmap = icon.pixmap(pixmapSize, pixmapSize); - painter->drawPixmap(styleOption.rect.x() + 1 , styleOption.rect.y() + 2, pixmap); + painter->drawPixmap(styleOption.rect.x() + 1 + delegateMargin, + styleOption.rect.y() + 2 + delegateMargin, + pixmap); + + pixmapSize += delegateMargin; return pixmapSize; } @@ -128,19 +133,20 @@ static QRect drawText(QPainter *painter, int iconOffset) { QString displayString = modelIndex.data(Qt::DisplayRole).toString(); - if (displayString.isEmpty()) - displayString = modelIndex.data(Qt::DisplayRole).toString(); QPoint displayStringOffset; int width = 0; // Check text length does not exceed available space - int extraSpace = 12 + iconOffset; + const int extraSpace = 12 + iconOffset; + + displayString = styleOption.fontMetrics.elidedText(displayString, + Qt::ElideMiddle, + styleOption.rect.width() - extraSpace); + displayStringOffset = QPoint(5 + iconOffset, -5 - delegateMargin); - displayString = styleOption.fontMetrics.elidedText(displayString, Qt::ElideMiddle, styleOption.rect.width() - extraSpace); - displayStringOffset = QPoint(5 + iconOffset, -5); width = styleOption.fontMetrics.horizontalAdvance(displayString); - QPoint textPosition = styleOption.rect.bottomLeft() + displayStringOffset; + const QPoint textPosition = styleOption.rect.bottomLeft() + displayStringOffset; painter->drawText(textPosition, displayString); QRect textFrame; @@ -150,9 +156,9 @@ static QRect drawText(QPainter *painter, return textFrame; } -static bool isVisible(const QModelIndex &modelIndex) +static bool isThisOrAncestorLocked(const QModelIndex &modelIndex) { - return modelIndex.model()->data(modelIndex, ItemIsVisibleRole).toBool(); + return modelIndex.model()->data(modelIndex, ItemOrAncestorLocked).toBool(); } static ModelNode getModelNode(const QModelIndex &modelIndex) @@ -175,17 +181,56 @@ static void drawRedWavyUnderLine(QPainter *painter, painter->fillRect(textFrame.x(), 0, qCeil(textFrame.width()), qMin(wave.height(), descent), wave); } +static void setId(const QModelIndex &index, const QString &newId) +{ + ModelNode modelNode = getModelNode(index); + + if (!modelNode.isValid()) + return; + + if (modelNode.id() == newId) + return; + + if (!modelNode.isValidId(newId)) { + Core::AsynchronousMessageBox::warning(NavigatorTreeView::tr("Invalid Id"), + NavigatorTreeView::tr("%1 is an invalid id.").arg(newId)); + } else if (modelNode.view()->hasId(newId)) { + Core::AsynchronousMessageBox::warning(NavigatorTreeView::tr("Invalid Id"), + NavigatorTreeView::tr("%1 already exists.").arg(newId)); + } else { + modelNode.setIdWithRefactoring(newId); + } +} + +static void openContextMenu(const QModelIndex &index, const QPoint &pos) +{ + const ModelNode modelNode = getModelNode(index); + QTC_ASSERT(modelNode.isValid(), return); + ModelNodeContextMenu::showContextMenu(modelNode.view(), pos, QPoint(), false); +} + +QSize NameItemDelegate::sizeHint(const QStyleOptionViewItem & /*option*/, + const QModelIndex & /*modelIndex*/) const +{ + return {15, 20 + (2 * delegateMargin)}; +} + void NameItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &styleOption, const QModelIndex &modelIndex) const { painter->save(); + + if (styleOption.state & QStyle::State_MouseOver && !isThisOrAncestorLocked(modelIndex)) + painter->fillRect(styleOption.rect.adjusted(0, delegateMargin, 0, -delegateMargin), + Theme::getColor(Theme::Color::DSsliderHandle)); + if (styleOption.state & QStyle::State_Selected) NavigatorTreeView::drawSelectionBackground(painter, styleOption); - int iconOffset = drawIcon(painter, styleOption, modelIndex); + iconOffset = drawIcon(painter, styleOption, modelIndex); - if (!isVisible(modelIndex)) + if (isThisOrAncestorLocked(modelIndex)) painter->setOpacity(0.5); QRect textFrame = drawText(painter, styleOption, modelIndex, iconOffset); @@ -196,28 +241,8 @@ void NameItemDelegate::paint(QPainter *painter, painter->restore(); } -static void openContextMenu(const QModelIndex &index, const QPoint &pos) -{ - const ModelNode modelNode = getModelNode(index); - QTC_ASSERT(modelNode.isValid(), return); - ModelNodeContextMenu::showContextMenu(modelNode.view(), pos, QPoint(), false); -} - -bool NameItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *, const QStyleOptionViewItem &, const QModelIndex &index) -{ - if (event->type() == QEvent::MouseButtonRelease) { - auto mouseEvent = static_cast(event); - if (mouseEvent->button() == Qt::RightButton) { - openContextMenu(index, mouseEvent->globalPos()); - mouseEvent->accept(); - return true; - } - } - return false; -} - QWidget *NameItemDelegate::createEditor(QWidget *parent, - const QStyleOptionViewItem & /*option*/, + const QStyleOptionViewItem &/*option*/, const QModelIndex &index) const { if (!getModelNode(index).isValid()) @@ -235,42 +260,35 @@ void NameItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) lineEdit->setText(value); } -static void setId(const QModelIndex &index, const QString &newId) -{ - ModelNode modelNode = getModelNode(index); - - if (!modelNode.isValid()) - return; - - if (modelNode.id() == newId) - return; - - if (!modelNode.isValidId(newId)) { - Core::AsynchronousMessageBox::warning(NavigatorTreeView::tr("Invalid Id"), - NavigatorTreeView::tr("%1 is an invalid id.").arg(newId)); - } else if (modelNode.view()->hasId(newId)) { - Core::AsynchronousMessageBox::warning(NavigatorTreeView::tr("Invalid Id"), - NavigatorTreeView::tr("%1 already exists.").arg(newId)); - } else { - modelNode.setIdWithRefactoring(newId); - } -} - - void NameItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { Q_UNUSED(model) auto lineEdit = static_cast(editor); - setId(index,lineEdit->text()); + setId(index, lineEdit->text()); lineEdit->clearFocus(); } +bool NameItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *, const QStyleOptionViewItem &, const QModelIndex &index) +{ + if (event->type() == QEvent::MouseButtonRelease) { + auto mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::RightButton) { + openContextMenu(index, mouseEvent->globalPos()); + mouseEvent->accept(); + return true; + } + } + return false; +} + void NameItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, - const QModelIndex & /*index*/) const + const QModelIndex &/*index*/) const { auto lineEdit = static_cast(editor); - lineEdit->setGeometry(option.rect); + lineEdit->setTextMargins(0, 0, 0, 2); + // + 2 is shifting the QLineEdit to the left so it will align with the text when activated + lineEdit->setGeometry(option.rect.adjusted(iconOffset + 2, delegateMargin, 0, -delegateMargin)); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/nameitemdelegate.h b/src/plugins/qmldesigner/components/navigator/nameitemdelegate.h index d33cb42ef73..6919dc1ec6e 100644 --- a/src/plugins/qmldesigner/components/navigator/nameitemdelegate.h +++ b/src/plugins/qmldesigner/components/navigator/nameitemdelegate.h @@ -34,18 +34,28 @@ class NavigatorTreeModel; class NameItemDelegate : public QStyledItemDelegate { public: + static int iconOffset; + explicit NameItemDelegate(QObject *parent); - void paint(QPainter *painter, const QStyleOptionViewItem &styleOption, - const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + void paint(QPainter *painter, + const QStyleOptionViewItem &styleOption, + const QModelIndex &index) const override; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; protected: - bool editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index ) override; - void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + bool editorEvent(QEvent *event, + QAbstractItemModel *model, + const QStyleOptionViewItem &option, + const QModelIndex &index) override; + void updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 602a0f73164..f02e41fc863 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -203,6 +203,12 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const if (role == ItemIsVisibleRole) // independent of column return m_view->isNodeInvisible(modelNode) ? Qt::Unchecked : Qt::Checked; + if (role == ItemOrAncestorLocked) + return ModelNode::isThisOrAncestorLocked(modelNode); + + if (role == ModelNodeRole) + return QVariant::fromValue(modelNode); + if (index.column() == ColumnType::Name) { if (role == Qt::DisplayRole) { return modelNode.displayName(); @@ -237,8 +243,6 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const auto op = m_actionManager->modelNodePreviewOperation(modelNode); if (op) return op(modelNode); - } else if (role == ModelNodeRole) { - return QVariant::fromValue(modelNode); } } else if (index.column() == ColumnType::Alias) { // export if (role == Qt::CheckStateRole) @@ -268,7 +272,7 @@ Qt::ItemFlags NavigatorTreeModel::flags(const QModelIndex &index) const if (index.column() == ColumnType::Alias || index.column() == ColumnType::Visibility || index.column() == ColumnType::Lock) - return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren; + return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren; const ModelNode modelNode = modelNodeForIndex(index); if (ModelNode::isThisOrAncestorLocked(modelNode)) @@ -277,8 +281,7 @@ Qt::ItemFlags NavigatorTreeModel::flags(const QModelIndex &index) const if (index.column() == ColumnType::Name) return Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; - return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable - | Qt::ItemNeverHasChildren; + return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren; } void static appendForcedNodes(const NodeListProperty &property, QList &list) diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreeview.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreeview.cpp index 8be526278c6..ad9c2d6dbed 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreeview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreeview.cpp @@ -33,6 +33,7 @@ #include "previewtooltip.h" #include +#include #include #include @@ -63,32 +64,28 @@ public: baseStyle()->setParent(parent); } - void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override + void drawPrimitive(PrimitiveElement element, + const QStyleOption *option, + QPainter *painter, + const QWidget *widget = nullptr) const override { static QRect mouseOverStateSavedFrameRectangle; if (element == QStyle::PE_PanelItemViewRow) { if (option->state & QStyle::State_MouseOver) mouseOverStateSavedFrameRectangle = option->rect; - if (option->state & QStyle::State_Selected) - NavigatorTreeView::drawSelectionBackground(painter, *option); - + painter->fillRect(option->rect.adjusted(0, delegateMargin, 0, -delegateMargin), + Theme::getColor(Theme::Color::QmlDesigner_BorderColor)); } else if (element == PE_IndicatorItemViewItemDrop) { // between elements and on elements we have a width if (option->rect.width() > 0) { m_currentTextColor = option->palette.text().color(); QRect frameRectangle = adjustedRectangleToWidgetWidth(option->rect, widget); painter->save(); - if (option->rect.height() == 0) { bool isNotRootItem = option->rect.top() > 10 && mouseOverStateSavedFrameRectangle.top() > 10; - if (isNotRootItem) { + if (isNotRootItem) drawIndicatorLine(frameRectangle.topLeft(), frameRectangle.topRight(), painter); - // there is only a line in the styleoption object at this moment - // so we need to use the last saved rect from the mouse over state - frameRectangle = adjustedRectangleToWidgetWidth(mouseOverStateSavedFrameRectangle, widget); - drawBackgroundFrame(frameRectangle, painter); - } } else { drawHighlightFrame(frameRectangle, painter); } @@ -96,12 +93,72 @@ public: } } else if (element == PE_FrameFocusRect) { // don't draw + } else if (element == PE_IndicatorBranch) { + painter->save(); + static const int decoration_size = 10; + int mid_h = option->rect.x() + option->rect.width() / 2; + int mid_v = option->rect.y() + option->rect.height() / 2; + int bef_h = mid_h; + int bef_v = mid_v; + int aft_h = mid_h; + int aft_v = mid_v; + QBrush brush(Theme::getColor(Theme::Color::DSsliderHandle), Qt::SolidPattern); + if (option->state & State_Item) { + if (option->direction == Qt::RightToLeft) + painter->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush); + else + painter->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush); + } + if (option->state & State_Sibling) + painter->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush); + if (option->state & (State_Open | State_Children | State_Item | State_Sibling)) + painter->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush); + if (option->state & State_Children) { + int delta = decoration_size / 2; + bef_h -= delta; + bef_v -= delta; + aft_h += delta; + aft_v += delta; + + const QRectF rect(bef_h, bef_v, decoration_size + 1, decoration_size + 1); + painter->fillRect(rect, QBrush(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate))); + + static const QPointF collapsePoints[3] = { + QPointF(0.0, 0.0), + QPointF(4.0, 4.0), + QPointF(0.0, 8.0) + }; + + static const QPointF expandPoints[3] = { + QPointF(0.0, 0.0), + QPointF(8.0, 0.0), + QPointF(4.0, 4.0) + }; + + auto color = Theme::getColor(Theme::Color::IconsBaseColor); + painter->setPen(color); + painter->setBrush(color); + + if (option->state & QStyle::State_Open) { + painter->translate(QPointF(mid_h - 4, mid_v - 2)); + painter->drawConvexPolygon(expandPoints, 3); + } else { + painter->translate(QPointF(mid_h - 2, mid_v - 4)); + painter->drawConvexPolygon(collapsePoints, 3); + } + } + painter->restore(); + } else { QProxyStyle::drawPrimitive(element, option, painter, widget); } } - int styleHint(StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override { + int styleHint(StyleHint hint, + const QStyleOption *option = nullptr, + const QWidget *widget = nullptr, + QStyleHintReturn *returnData = nullptr) const override + { if (hint == SH_ItemView_ShowDecorationSelected) return 0; else @@ -180,7 +237,8 @@ NavigatorTreeView::NavigatorTreeView(QWidget *parent) void NavigatorTreeView::drawSelectionBackground(QPainter *painter, const QStyleOption &option) { painter->save(); - painter->fillRect(option.rect, option.palette.color(QPalette::Highlight)); + painter->fillRect(option.rect.adjusted(0, delegateMargin, 0, -delegateMargin), + Theme::getColor(Theme::Color::QmlDesigner_HighlightColor)); painter->restore(); } @@ -223,5 +281,4 @@ bool NavigatorTreeView::viewportEvent(QEvent *event) return QTreeView::viewportEvent(event); } - } diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index e1702bdac46..c2ed5c72065 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -145,6 +145,7 @@ void NavigatorView::modelAttached(Model *model) treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Visibility, 26); treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Lock, 26); treeView->setIndentation(20); + treeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_currentModelInterface->setFilter(false); @@ -493,7 +494,6 @@ void NavigatorView::changeSelection(const QItemSelection & /*newSelection*/, con QSet nodeSet; for (const QModelIndex &index : treeWidget()->selectionModel()->selectedIndexes()) { - const ModelNode modelNode = modelNodeForIndex(index); if (modelNode.isValid()) nodeSet.insert(modelNode); @@ -539,7 +539,7 @@ void NavigatorView::updateItemSelection() } bool blocked = blockSelectionChangedSignal(true); - treeWidget()->selectionModel()->select(itemSelection, QItemSelectionModel::ClearAndSelect); + treeWidget()->selectionModel()->select(itemSelection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); blockSelectionChangedSignal(blocked); if (!selectedModelNodes().isEmpty()) @@ -586,7 +586,7 @@ void NavigatorView::reparentAndCatch(NodeAbstractProperty property, const ModelN { try { property.reparentHere(modelNode); - } catch (Exception &exception) { + } catch (Exception &exception) { exception.showException(); } } @@ -620,29 +620,29 @@ void NavigatorView::setupWidget() const QIcon visibilityOnIcon = Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(Theme::Icon::visibilityOn), - 28, 28, QColor(Qt::white)); + 20, 20, QColor(Qt::white)); const QIcon visibilityOffIcon = Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(Theme::Icon::visibilityOff), - 28, 28, QColor(Qt::white)); + 20, 20, QColor(Qt::white)); const QIcon aliasOnIcon = Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(Theme::Icon::idAliasOn), - 28, 28, QColor(Qt::red)); + 20, 20, QColor(Qt::red)); const QIcon aliasOffIcon = Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(Theme::Icon::idAliasOff), - 28, 28, QColor(Qt::white)); + 20, 20, QColor(Qt::white)); const QIcon lockOnIcon = Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(Theme::Icon::lockOn), - 28, 28, QColor(Qt::white)); + 20, 20, QColor(Qt::white)); const QIcon lockOffIcon = Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(Theme::Icon::lockOff), - 28, 28, QColor(Qt::white)); + 20, 20, QColor(Qt::white)); auto idDelegate = new NameItemDelegate(this); diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.h b/src/plugins/qmldesigner/components/navigator/navigatorview.h index 6189b24559a..451de3be71c 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.h +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.h @@ -43,6 +43,8 @@ QT_END_NAMESPACE namespace QmlDesigner { +static int delegateMargin = 2; + class NavigatorWidget; class NavigatorTreeModel; @@ -50,7 +52,8 @@ enum NavigatorRoles { ItemIsVisibleRole = Qt::UserRole, RowIsPropertyRole = Qt::UserRole + 1, ModelNodeRole = Qt::UserRole + 2, - ToolTipImageRole = Qt::UserRole + 3 + ToolTipImageRole = Qt::UserRole + 3, + ItemOrAncestorLocked = Qt::UserRole + 4 }; class NavigatorView : public AbstractView From 15db0bb1731880fde25b6e6c70d99c62b0141d2f Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 24 Sep 2020 10:35:22 +0200 Subject: [PATCH 20/21] QmlDesigner: Rework SpinBox dragging functionality * Replace DragHandler with MouseArea due to the DragHandler not being able to accept MouseEvents * Replace TapHandler with MouseArea due to MouseArea stealing press signals from TapHandler, but needed to get press events due to removal of DragHandler * Add functionality to keep cursor in place while dragging * Keep ActionIndicator visible while dragging * Fix qsTr in RectangleSpecifics Change-Id: I6558623287e1864359128d4194c9db78736ee3a4 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../QtQuick/RectangleSpecifics.qml | 2 +- .../imports/HelperWidgets/SpinBox.qml | 7 +- .../StudioControls/ActionIndicator.qml | 3 +- .../imports/StudioControls/RealSpinBox.qml | 2 + .../StudioControls/RealSpinBoxInput.qml | 177 ++++++++++-------- .../imports/StudioTheme/Values.qml | 2 +- .../propertyeditorcontextobject.cpp | 18 +- .../propertyeditorcontextobject.h | 1 + 8 files changed, 133 insertions(+), 79 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml index f743af96e05..deca79ed00a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml @@ -63,7 +63,7 @@ Column { Section { anchors.left: parent.left anchors.right: parent.right - caption: "Rectangle" + caption: qsTr("Rectangle") SectionLayout { rows: 2 diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml index 3f70547692a..916bfc29d96 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml @@ -45,7 +45,10 @@ Item { width: 96 implicitHeight: spinBox.height - onFocusChanged: transaction.end(); + onFocusChanged: { + restoreCursor(); + transaction.end(); + } StudioControls.RealSpinBox { id: spinBox @@ -60,6 +63,8 @@ Item { transaction.end(); } + onDragging: holdCursorInPlace(); + onRealValueModified: { if (transaction.active()) commitValue(); diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml index a055447d967..cde5beedc17 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml @@ -55,7 +55,8 @@ Rectangle { visible: text !== StudioTheme.Constants.actionIcon || actionIndicator.forceVisible || (myControl !== undefined && ((myControl.edit !== undefined && myControl.edit) - || (myControl.hover !== undefined && myControl.hover))) + || (myControl.hover !== undefined && myControl.hover) + || (myControl.drag !== undefined && myControl.drag))) color: StudioTheme.Values.themeTextColor font.family: StudioTheme.Constants.iconFont.family font.pixelSize: StudioTheme.Values.myIconFontSize diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml index 85e21735de9..4170e9289fd 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml @@ -55,6 +55,7 @@ T.SpinBox { property bool dirty: false // user modification flag + // TODO Not used anymore. Will be removed when all dependencies were removed. property real realDragRange: mySpinBox.realTo - mySpinBox.realFrom property alias actionIndicatorVisible: actionIndicator.visible @@ -77,6 +78,7 @@ T.SpinBox { signal compressedRealValueModified signal dragStarted signal dragEnded + signal dragging // Use custom wheel handling due to bugs property bool __wheelEnabled: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml index edeeaf9fd2d..31c2bccf6fc 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml @@ -70,61 +70,25 @@ TextInput { height: StudioTheme.Values.height } - DragHandler { - id: dragHandler - target: null - acceptedDevices: PointerDevice.Mouse - enabled: true - - property real initialValue: myControl.realValue - property real multiplier: 1.0 - - onActiveChanged: { - if (dragHandler.active) { - dragHandler.initialValue = myControl.realValue - mouseArea.cursorShape = Qt.ClosedHandCursor // TODO - myControl.drag = true - myControl.dragStarted() - // Force focus on the non visible component to receive key events - dragModifierWorkaround.forceActiveFocus() - } else { - if (myControl.compressedValueTimer.running) { - myControl.compressedValueTimer.stop() - calcValue(myControl.compressedRealValueModified) - } - mouseArea.cursorShape = Qt.PointingHandCursor // TODO - myControl.drag = false - myControl.dragEnded() - // Avoid active focus on the component after dragging - dragModifierWorkaround.focus = false - textInput.focus = false - myControl.focus = false - } - } - onTranslationChanged: calcValue(myControl.realValueModified) - onMultiplierChanged: calcValue(myControl.realValueModified) - - function calcValue(callback) { - var tmp = myControl.realDragRange / StudioTheme.Values.dragLength - myControl.setRealValue(dragHandler.initialValue + (tmp * dragHandler.translation.x * dragHandler.multiplier)) - callback() - } - } - Item { id: dragModifierWorkaround Keys.onPressed: { event.accepted = true - if (event.modifiers & Qt.ControlModifier) - dragHandler.multiplier = 0.1 + if (event.modifiers & Qt.ControlModifier) { + mouseArea.stepSize = myControl.minStepSize + mouseArea.calcValue(myControl.realValueModified) + } - if (event.modifiers & Qt.ShiftModifier) - dragHandler.multiplier = 10.0 + if (event.modifiers & Qt.ShiftModifier) { + mouseArea.stepSize = myControl.maxStepSize + mouseArea.calcValue(myControl.realValueModified) + } } Keys.onReleased: { event.accepted = true - dragHandler.multiplier = 1.0 + mouseArea.stepSize = myControl.realStepSize + mouseArea.calcValue(myControl.realValueModified) } } @@ -133,21 +97,21 @@ TextInput { event.accepted = (event.key === Qt.Key_Up || event.key === Qt.Key_Down) } - TapHandler { - id: tapHandler - acceptedDevices: PointerDevice.Mouse - enabled: true - onTapped: { - textInput.forceActiveFocus() - textInput.deselect() // QTBUG-75862 - } - } - MouseArea { id: mouseArea property real stepSize: myControl.realStepSize + property bool dragging: false + property bool wasDragging: false + property bool potentialDragStart: false + + property real initialValue: myControl.realValue + + property real pressStartX: 0.0 + property real dragStartX: 0.0 + property real translationX: 0.0 + anchors.fill: parent enabled: true hoverEnabled: true @@ -156,7 +120,90 @@ TextInput { cursorShape: Qt.PointingHandCursor // Sets the global hover onContainsMouseChanged: myControl.hover = containsMouse - onPressed: mouse.accepted = false + + onPositionChanged: { + if (!mouseArea.dragging + && !myControl.edit + && Math.abs(mouseArea.pressStartX - mouse.x) > StudioTheme.Values.dragThreshold + && mouse.buttons === 1 + && mouseArea.potentialDragStart) { + mouseArea.dragging = true + mouseArea.potentialDragStart = false + mouseArea.initialValue = myControl.realValue + mouseArea.cursorShape = Qt.ClosedHandCursor + mouseArea.dragStartX = mouseArea.mouseX + + myControl.drag = true + myControl.dragStarted() + // Force focus on the non visible component to receive key events + dragModifierWorkaround.forceActiveFocus() + textInput.deselect() + } + + if (!mouseArea.dragging) + return + + mouse.accepted = true + + mouseArea.translationX += (mouseArea.mouseX - mouseArea.dragStartX) + mouseArea.calcValue(myControl.realValueModified) + } + + onCanceled: mouseArea.endDrag() + + onClicked: { + if (mouseArea.wasDragging) { + mouseArea.wasDragging = false + return + } + + textInput.forceActiveFocus() + textInput.deselect() // QTBUG-75862 + } + + onPressed: { + mouseArea.potentialDragStart = true + mouseArea.pressStartX = mouseArea.mouseX + } + + onReleased: mouseArea.endDrag() + + function endDrag() { + if (!mouseArea.dragging) + return + + mouseArea.dragging = false + mouseArea.wasDragging = true + + if (myControl.compressedValueTimer.running) { + myControl.compressedValueTimer.stop() + mouseArea.calcValue(myControl.compressedRealValueModified) + } + mouseArea.cursorShape = Qt.PointingHandCursor + myControl.drag = false + myControl.dragEnded() + // Avoid active focus on the component after dragging + dragModifierWorkaround.focus = false + textInput.focus = false + myControl.focus = false + + mouseArea.translationX = 0 + } + + function calcValue(callback) { + var minTranslation = (myControl.realFrom - mouseArea.initialValue) / mouseArea.stepSize + var maxTranslation = (myControl.realTo - mouseArea.initialValue) / mouseArea.stepSize + + mouseArea.translationX = Math.min(Math.max(mouseArea.translationX, minTranslation), maxTranslation) + + myControl.setRealValue(mouseArea.initialValue + (mouseArea.translationX * mouseArea.stepSize)) + + if (mouseArea.dragging) + myControl.dragging() + + callback() + } + onWheel: { if (!myControl.__wheelEnabled) return @@ -187,14 +234,6 @@ TextInput { color: StudioTheme.Values.themeControlBackground border.color: StudioTheme.Values.themeControlOutline } - PropertyChanges { - target: dragHandler - enabled: true - } - PropertyChanges { - target: tapHandler - enabled: true - } PropertyChanges { target: mouseArea cursorShape: Qt.PointingHandCursor @@ -217,14 +256,6 @@ TextInput { color: StudioTheme.Values.themeFocusEdit border.color: StudioTheme.Values.themeInteraction } - PropertyChanges { - target: dragHandler - enabled: false - } - PropertyChanges { - target: tapHandler - enabled: false - } PropertyChanges { target: mouseArea cursorShape: Qt.IBeamCursor diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml index 22f0ff872ef..3d504302a78 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml @@ -50,7 +50,7 @@ QtObject { property real sliderControlSize: 12 property real sliderControlSizeMulti: values.sliderControlSize * values.scaleFactor - property int dragLength: 400 // px + property int dragThreshold: 10 // px property real spinControlIconSize: 8 property real spinControlIconSizeMulti: values.spinControlIconSize * values.scaleFactor diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index 5f17ca77ffa..798274af20a 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -495,7 +496,9 @@ void PropertyEditorContextObject::hideCursor() return; QApplication::setOverrideCursor(QCursor(Qt::BlankCursor)); - m_lastPos = QCursor::pos(); + + if (QWidget *w = QApplication::activeWindow()) + m_lastPos = QCursor::pos(w->screen()); } void PropertyEditorContextObject::restoreCursor() @@ -503,8 +506,19 @@ void PropertyEditorContextObject::restoreCursor() if (!QApplication::overrideCursor()) return; - QCursor::setPos(m_lastPos); QApplication::restoreOverrideCursor(); + + if (QWidget *w = QApplication::activeWindow()) + QCursor::setPos(w->screen(), m_lastPos); +} + +void PropertyEditorContextObject::holdCursorInPlace() +{ + if (!QApplication::overrideCursor()) + return; + + if (QWidget *w = QApplication::activeWindow()) + QCursor::setPos(w->screen(), m_lastPos); } QStringList PropertyEditorContextObject::styleNamesForFamily(const QString &family) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h index 35c909192b0..d4c39306c13 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h @@ -91,6 +91,7 @@ public: Q_INVOKABLE void hideCursor(); Q_INVOKABLE void restoreCursor(); + Q_INVOKABLE void holdCursorInPlace(); Q_INVOKABLE QStringList styleNamesForFamily(const QString &family); From 1f9124c976b6463e1814bdc094f6fbf194c84bd4 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Tue, 6 Oct 2020 16:37:47 +0300 Subject: [PATCH 21/21] CMake: update project templates to work with Android for Qt 6 Qt 6 introduces qt_add_executable() function, which for Android make sure to call few Android specific functions like: * qt_android_generate_deployment_settings() * qt_android_add_apk_target() * qt_android_apply_arch_suffix() Using add_library() only the user would otherwise need to reimplement what's already implemented in add_qt_gui_executable(). Task-number: QTCREATORBUG-24681 Change-Id: Iec3984139844fe1cbac2d9a583b3c40bdaa308a0 Reviewed-by: Alexandru Croitor Reviewed-by: Alessandro Portale --- .../qtquickapplication/CMakeLists.txt | 34 +++++++------ .../qtwidgetsapplication/CMakeLists.txt | 48 ++++++++++--------- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt index 3b479a595c4..95426d9498c 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt @@ -34,22 +34,28 @@ find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick REQUIRED) @endif -if(ANDROID) - add_library(%{ProjectName} SHARED - %{MainCppFileName} - qml.qrc -@if %{HasTranslation} - ${TS_FILES} -@endif +set(PROJECT_SOURCES + %{MainCppFileName} + qml.qrc + @if %{HasTranslation} + ${TS_FILES} + @endif +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(%{ProjectName} + ${PROJECT_SOURCES} ) else() - add_executable(%{ProjectName} - %{MainCppFileName} - qml.qrc -@if %{HasTranslation} - ${TS_FILES} -@endif - ) + if(ANDROID) + add_library(%{ProjectName} SHARED + ${PROJECT_SOURCES} + ) + else() + add_executable(%{ProjectName} + ${PROJECT_SOURCES} + ) + endif() endif() target_compile_definitions(%{ProjectName} diff --git a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt index 21fec5e47b8..391da140528 100644 --- a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt @@ -34,30 +34,32 @@ find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED) @endif -if(ANDROID) - add_library(%{ProjectName} SHARED - %{MainFileName} - %{SrcFileName} - %{HdrFileName} - @if %{GenerateForm} - %{FormFileName} - @endif - @if %{HasTranslation} - ${TS_FILES} - @endif - ) +set(PROJECT_SOURCES + %{MainFileName} + %{SrcFileName} + %{HdrFileName} + @if %{GenerateForm} + %{FormFileName} + @endif + @if %{HasTranslation} + ${TS_FILES} + @endif +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(%{ProjectName} + ${PROJECT_SOURCES} + ) else() - add_executable(%{ProjectName} - %{MainFileName} - %{SrcFileName} - %{HdrFileName} - @if %{GenerateForm} - %{FormFileName} - @endif - @if %{HasTranslation} - ${TS_FILES} - @endif - ) + if(ANDROID) + add_library(%{ProjectName} SHARED + ${PROJECT_SOURCES} + ) + else() + add_executable(%{ProjectName} + ${PROJECT_SOURCES} + ) + endif() endif() target_link_libraries(%{ProjectName} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)