diff --git a/doc/qtcreator/images/qtcreator-options-clangd.png b/doc/qtcreator/images/qtcreator-options-clangd.png new file mode 100644 index 00000000000..a277d076c96 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-options-clangd.png differ diff --git a/doc/qtcreator/images/qtcreator-search-allprojects.png b/doc/qtcreator/images/qtcreator-search-allprojects.png index c48cd50b472..c442572f996 100644 Binary files a/doc/qtcreator/images/qtcreator-search-allprojects.png and b/doc/qtcreator/images/qtcreator-search-allprojects.png differ diff --git a/doc/qtcreator/images/qtcreator-search-filesystem.png b/doc/qtcreator/images/qtcreator-search-filesystem.png index b8a886c9c94..df344a79e33 100644 Binary files a/doc/qtcreator/images/qtcreator-search-filesystem.png and b/doc/qtcreator/images/qtcreator-search-filesystem.png differ diff --git a/doc/qtcreator/images/qtcreator-searchresults.png b/doc/qtcreator/images/qtcreator-searchresults.png index 8c0a0b0ebb9..3e2bc2f5309 100644 Binary files a/doc/qtcreator/images/qtcreator-searchresults.png and b/doc/qtcreator/images/qtcreator-searchresults.png differ diff --git a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc index d190f3c97a4..34f8cc28ba2 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -138,10 +138,6 @@ edit the value for the \uicontrol {Do not index files greater than} check box. To index all files, deselect the check box. - \li To use clangd instead of the built-in code model for features such as - \e {Find References to Symbol}, check the \uicontrol {Use clangd} checkbox. - \note This is an experimental feature, which might not work reliably yet. - \li The \uicontrol {Diagnostic Configuration} field shows the Clang checks to perform. Click the value of the field to open the \uicontrol {Diagnostic Configurations} dialog, where you can @@ -151,6 +147,51 @@ \endlist + \section1 Configuring clangd + + You can use the experimental clangd support instead of libclang to receive + exact and complete results for services such as finding references, + following symbols under cursor, and using the locator, even for complex + constructs that the built-in code model cannot handle correctly. These + improvements are based on clangd's \e index. When you \l{Opening Projects} + {open a project}, clangd scans the source files to generate the index. For + large projects, this can take a while, but the index is persistent and + re-scanning is incremental, so nothing is lost by closing and re-starting + \QC. + + Because clangd considers only the on-disk state of included header files + when parsing a source file, you need to save changes in header files to + have them considered elsewhere for completion, diagnostics, and so on. + Partly for this reason, files that are changed by refactoring actions are + saved automatically. To disable this feature, select \uicontrol Tools > + \uicontrol Options > \uicontrol Environment > \uicontrol System > + \uicontrol {Auto-save files after refactoring}. + + The document outline in the \l{Viewing Defined Types and Symbols} + {Outline} view is backed by clangd's document symbol support, which + makes the results more reliable than before. + + To use clangd for the current project instead of the built-in code model or + Clang: + + \list 1 + \li Select \uicontrol Tools > \uicontrol Options > \uicontrol C++ > + \uicontrol Clang > \uicontrol {Use clangd (EXPERIMENTAL)}. + \image qtcreator-options-clangd.png "clangd options" + \li In \uicontrol {Path to executable}, enter the path to clangd + version 13, or later. + \li For more accurate results during global symbol searches, select + \uicontrol {Enable background indexing}. However, this increases the + CPU load the first time you open the project. + \li Select \uicontrol {Insert header files on completion} to allow + clangd to insert header files as part of symbol completion. + \li By default, clangd attempts to use all unused cores. You can set a + fixed number of cores to use in \uicontrol {Worker thread count}. + \li In \uicontrol {Document update threshold}, specify the amount of + time \QC waits before sending document changes to the server. + If the document changes again while waiting, this timeout is reset. + \endlist + \section1 Clang Checks In addition to using the built-in checks, you can select \uicontrol Copy to diff --git a/doc/qtcreator/src/editors/creator-search.qdoc b/doc/qtcreator/src/editors/creator-search.qdoc index fb11d9c0e01..887ae4cf3b1 100644 --- a/doc/qtcreator/src/editors/creator-search.qdoc +++ b/doc/qtcreator/src/editors/creator-search.qdoc @@ -116,7 +116,8 @@ \section1 Advanced Search - To search through projects, files on a file system or currently open files: + To search through projects, files on a file system, files in all project + directories, or currently open files: \list 1 @@ -136,6 +137,9 @@ \li \uicontrol {Current Project} searches from the project you are currently editing. + \li \uicontrol {Files in All Project Directories} searches from + all project directories. + \li \uicontrol {Files in File System} recursively searches from the selected directory. @@ -206,6 +210,9 @@ To clear the search results, select the \inlineimage clean_pane_small.png (\uicontrol Clear) button. + To expand and collapse the search results, select the + \uicontrol {Expand All} button. + To start a new search, select the \inlineimage qtcreator-new-search-icon.png (\uicontrol {New Search}) button. diff --git a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc index 630c0a1996c..87a62b46171 100644 --- a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc @@ -38,6 +38,9 @@ \uicontrol Design mode: \image qtcreator-filesystem-view-design.png "File System view in the Design mode" + \else + \image qtcreator-filesystem-view.png "File System view in the sidebar" + \endif To move to the root directory of the file system, select \uicontrol Computer in the menu (1). Select \uicontrol Home to move to the user's home @@ -89,14 +92,19 @@ \li Collapse all open folders. \endlist - \section1 File System View in Sidebar - \endif + \section1 File System View Toolbar + \if defined(qtdesignstudio) In the \uicontrol Edit and \uicontrol Debug mode, the \uicontrol {File System} view is displayed in the \l{Working with Sidebars} - {sidebar}. It has a toolbar with additional options: + {sidebar}. It has a toolbar with additional options. \image qtcreator-filesystem-view.png "File System view in the sidebar" + \else + The toolbar in the \uicontrol {File System} view contains additional + options. + \endif + To manage view contents, select \inlineimage filtericon.png (\uicontrol Options): diff --git a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc index cc9f5cbcfe4..558296a0bb8 100644 --- a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc @@ -45,6 +45,9 @@ \uicontrol Design mode: \image qtcreator-projects-view-design.png "Projects view in the Design mode" + \else + \image qtcreator-projects-view-edit.png "Projects view in the sidebar" + \endif You can use the project tree in the following ways: @@ -97,23 +100,29 @@ \li Expand or collapse the tree view to show or hide all files and folders. \li Close all files in a project. - \li Close projects. By default, all files in the project are also + \li Close the selected project or all projects except the selected + one. By default, all files in the projects are also closed. To keep them open, deselect the \uicontrol Tools > \uicontrol Options > \uicontrol {Build & Run} > \uicontrol General > \uicontrol {Close source files along with project} check box. \endlist For managing files and directories, the same functions are available as in - the \l {File System} view. + the \l {File System} view. To view a project in it, select + \uicontrol {Show in File System View}. - \section1 Projects View in Sidebar - \endif + \section1 Projects View Toolbar + \if defined(qtdesignstudio) In the \uicontrol Edit and \uicontrol Debug mode, the \uicontrol Projects view is displayed in the \l{Working with Sidebars}{sidebar}. It has a - toolbar with additional options: + toolbar with additional options. \image qtcreator-projects-view-edit.png "Projects view in the sidebar" + \else + The toolbar in the \uicontrol Projects view contains additional options. + \endif + To filter view contents, select \inlineimage filtericon.png (\uicontrol {Filter Tree}): @@ -141,9 +150,7 @@ (currently qmake and Qbs). The faithful display of the project structure allows to specify exactly where a new file should be placed in the build system. - \endif - \if defined(qtcreator) If the project is under version control, information from the version control system might be displayed in brackets after the project name. This is currently implemented for Git (the branch name or a tag is diff --git a/doc/qtdesignstudio/images/studio-shapes-arc-outline-properties.png b/doc/qtdesignstudio/images/studio-shapes-arc-outline-properties.png index ead21b05a60..d2987ec7900 100644 Binary files a/doc/qtdesignstudio/images/studio-shapes-arc-outline-properties.png and b/doc/qtdesignstudio/images/studio-shapes-arc-outline-properties.png differ diff --git a/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc b/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc index a174a52ab1c..c87f7af0e90 100644 --- a/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc @@ -200,12 +200,7 @@ To create an arc with an outline, select the \uicontrol {Full outline} check box. The \uicontrol {Outline width} field sets the width of - the arc outline, including the stroke. The \uicontrol {Outline start} - and \uicontrol {Outline end} fields set the width of the start and - end points of the outline separately. The width of the outline between - them is calculated automatically. You can adjust the inner and outer - curves of the outline in the \uicontrol {Inner radius} and - \uicontrol {Outer radius} fields. + the arc outline, including the stroke. The \uicontrol {Round outline}, \uicontrol {Round start}, and \uicontrol {Round end} properties specify whether the end points of the diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp index ae94ed79812..211fe6d54bd 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp @@ -33,9 +33,18 @@ namespace QmlDesigner { View3DActionCommand::View3DActionCommand(Type type, bool enable) : m_type(type) , m_enabled(enable) + , m_position(0) { } +View3DActionCommand::View3DActionCommand(int pos) + : m_type(ParticlesSeek) + , m_enabled(true) + , m_position(pos) +{ + +} + bool View3DActionCommand::isEnabled() const { return m_enabled; @@ -46,10 +55,16 @@ View3DActionCommand::Type View3DActionCommand::type() const return m_type; } +int View3DActionCommand::position() const +{ + return m_position; +} + QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command) { out << qint32(command.isEnabled()); out << qint32(command.type()); + out << qint32(command.position()); return out; } @@ -58,10 +73,13 @@ QDataStream &operator>>(QDataStream &in, View3DActionCommand &command) { qint32 enabled; qint32 type; + qint32 pos; in >> enabled; in >> type; + in >> pos; command.m_enabled = bool(enabled); command.m_type = View3DActionCommand::Type(type); + command.m_position = pos; return in; } diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index 332b6006c39..c564bb2ec59 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -44,18 +44,34 @@ public: CameraToggle, OrientationToggle, EditLightToggle, - ShowGrid + ShowGrid, + Edit3DParticleModeToggle, + ParticlesPlay, + ParticlesRestart, + ParticlesSeek, }; explicit View3DActionCommand(Type type, bool enable); + View3DActionCommand() = default; bool isEnabled() const; Type type() const; + int position() const; private: Type m_type = Empty; bool m_enabled = false; + int m_position = 0; + +protected: + View3DActionCommand(int pos); +}; + +class View3DSeekActionCommand : public View3DActionCommand +{ +public: + View3DSeekActionCommand(int pos) : View3DActionCommand(pos) {} }; QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.cpp new file mode 100644 index 00000000000..4f32513b7ec --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. 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. +** +** 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. +** +****************************************************************************/ + +#include "animationdriver.h" +#include "private/qabstractanimation_p.h" + +AnimationDriver::AnimationDriver(QObject *parent) + : QAnimationDriver(parent) +{ + setProperty("allowNegativeDelta", true); + install(); + connect(this, SIGNAL(started()), this, SLOT(startTimer())); + connect(this, SIGNAL(stopped()), this, SLOT(stopTimer())); +} + +AnimationDriver::~AnimationDriver() +{ + +} + +void AnimationDriver::timerEvent(QTimerEvent *e) +{ + Q_ASSERT(e->timerId() == m_timer.timerId()); + Q_UNUSED(e); + + quint32 old = elapsed(); + // Provide same time for all users + if (m_seekerEnabled) { + m_seekerElapsed += (m_seekerPos * 100) / 30; + if (m_seekerElapsed + m_elapsed < -100) // -100 to allow small negative value + m_seekerElapsed = -m_elapsed - 100; + } else { + m_elapsed = QAnimationDriver::elapsed(); + } + m_delta = elapsed() - old; + advance(); + Q_EMIT advanced(); +} + +void AnimationDriver::startTimer() +{ + m_timer.start(m_interval, Qt::PreciseTimer, this); +} + +void AnimationDriver::stopTimer() +{ + m_timer.stop(); +} + +void AnimationDriver::setSeekerPosition(int position) +{ + if (!m_seekerEnabled) + return; + + if (!m_timer.isActive()) + restart(); + + m_seekerPos = position; +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.h new file mode 100644 index 00000000000..f4f50f0afcd --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. 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. +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +class AnimationDriver : public QAnimationDriver +{ + Q_OBJECT +public: + AnimationDriver(QObject *parent = nullptr); + ~AnimationDriver(); + void timerEvent(QTimerEvent *e) override; + void setInterval(int interval) + { + m_interval = qBound(1, interval, 60); + } + int interval() const + { + return m_interval; + } + void reset() + { + stop(); + stopTimer(); + } + void restart() + { + start(); + startTimer(); + } + qint64 elapsed() const override + { + return m_elapsed + m_seekerElapsed; + } + void setSeekerPosition(int position); + void setSeekerEnabled(bool enable) + { + m_seekerEnabled = enable; + } + bool isSeekerEnabled() const + { + return m_seekerEnabled; + } + bool isAnimating() const + { + return (!m_seekerEnabled && m_timer.isActive()) || (m_seekerEnabled && m_delta && m_seekerPos); + } +Q_SIGNALS: + void advanced(); + +private: + Q_SLOT void startTimer(); + Q_SLOT void stopTimer(); + + QBasicTimer m_timer; + int m_interval = 16; + int m_seekerPos = 0; + bool m_seekerEnabled = false; + qint64 m_elapsed = 0; + qint64 m_seekerElapsed = 0; + qint64 m_delta = 0; +}; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri index ff3ee9394b9..59ac62420c9 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri @@ -44,6 +44,8 @@ HEADERS += $$PWD/qt5nodeinstanceserver.h \ $$PWD/qt3dpresentationnodeinstance.h \ $$PWD/quick3dnodeinstance.h \ $$PWD/quick3dtexturenodeinstance.h \ + $$PWD/viewconfig.h \ + $$PWD/animationdriver.h SOURCES += $$PWD/qt5nodeinstanceserver.cpp \ @@ -74,4 +76,6 @@ SOURCES += $$PWD/qt5nodeinstanceserver.cpp \ $$PWD/layoutnodeinstance.cpp \ $$PWD/qt3dpresentationnodeinstance.cpp \ $$PWD/quick3dnodeinstance.cpp \ - $$PWD/quick3dtexturenodeinstance.cpp + $$PWD/quick3dtexturenodeinstance.cpp \ + $$PWD/viewconfig.cpp \ + $$PWD/animationdriver.cpp diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index bd3994400ba..c1c086c58d6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -332,7 +332,8 @@ void NodeInstanceServer::createScene(const CreateSceneCommand &command) registerFonts(command.resourceUrl); setTranslationLanguage(command.language); - Internal::QmlPrivateGate::stopUnifiedTimer(); + if (!ViewConfig::isParticleViewMode()) + Internal::QmlPrivateGate::stopUnifiedTimer(); setupScene(command); setupState(command.stateInstanceId); @@ -783,6 +784,15 @@ QList NodeInstanceServer::allSubContextsForObject(QObject *object return contextList; } +QList NodeInstanceServer::allSubObjectsForObject(QObject *object) +{ + QList subChildren; + if (object) + subChildren = object->findChildren(); + + return subChildren; +} + void NodeInstanceServer::removeAllInstanceRelationships() { for (ServerNodeInstance &instance : m_objectInstanceHash) { @@ -1563,4 +1573,39 @@ bool NodeInstanceServer::isInformationServer() const return false; } +static QString baseProperty(const QString &property) +{ + int index = property.indexOf('.'); + if (index > 0) + return property.left(index); + return property; +} + +void NodeInstanceServer::addAnimation(QQuickAbstractAnimation *animation) +{ + if (!m_animations.contains(animation)) { + m_animations.push_back(animation); + + QQuickPropertyAnimation *panim = qobject_cast(animation); + if (panim) { + QObject *target = panim->target(); + QString property = panim->property(); + QVariant value = target->property(qPrintable(baseProperty(property))); + m_defaultValues.push_back(value); + } else { + m_defaultValues.push_back({}); + } + } +} + +QVector NodeInstanceServer::animations() const +{ + return m_animations; +} + +QVariant NodeInstanceServer::animationDefaultValue(int index) const +{ + return m_defaultValues.at(index); +} + } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index 47dfd6c0b50..f2255bd891d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -43,6 +43,20 @@ #include #include "servernodeinstance.h" #include "debugoutputcommand.h" +#include "viewconfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include namespace QtHelpers { template @@ -217,6 +231,9 @@ public: virtual QImage grabItem(QQuickItem *item) = 0; virtual bool isInformationServer() const; + void addAnimation(QQuickAbstractAnimation *animation); + QVector animations() const; + QVariant animationDefaultValue(int index) const; public slots: void refreshLocalFileProperty(const QString &path); @@ -291,7 +308,8 @@ protected: void setupDefaultDummyData(); QList setupInstances(const CreateSceneCommand &command); - QList allSubContextsForObject(QObject *object); + QList allSubContextsForObject(QObject *object); + static QList allSubObjectsForObject(QObject *object); virtual void resizeCanvasToRootItem() = 0; void setupState(qint32 stateInstanceId); @@ -322,6 +340,8 @@ private: std::unique_ptr multilanguageLink; int m_needsExtraRenderCount = 0; int m_extraRenderCurrentPass = 0; + QVector m_animations; + QVector m_defaultValues; }; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index ee20e5636c4..419e75cfa04 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -87,6 +87,7 @@ #include #include #include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include @@ -103,10 +104,6 @@ #endif #endif -#ifdef QUICK3D_PARTICLES_MODULE -#include -#endif - #ifdef IMPORT_QUICK3D_ASSETS #include #endif @@ -216,7 +213,7 @@ void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url, void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet &instances) { - if (!isQuick3DMode()) + if (!ViewConfig::isQuick3DMode()) return; // We only want to update the topmost parents in the set @@ -406,9 +403,83 @@ void Qt5InformationNodeInstanceServer::createEditView3D() #endif } +#ifdef QUICK3D_PARTICLES_MODULE +void Qt5InformationNodeInstanceServer::resetParticleSystem() +{ + if (!m_targetParticleSystem) + return; + m_targetParticleSystem->reset(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 2) + m_targetParticleSystem->setEditorTime(0); +#endif + if (m_particleAnimationDriver) + m_particleAnimationDriver->reset(); +} + +void Qt5InformationNodeInstanceServer::handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem) +{ + if (!m_particleAnimationDriver) + return; + + m_particleAnimationDriver->reset(); + // stop the previously selected from animating + resetParticleSystem(); + + m_targetParticleSystem = targetParticleSystem; + + resetParticleSystem(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 2) + QObject::disconnect(m_particleAnimationConnection); + m_particleAnimationConnection = connect(m_particleAnimationDriver, &AnimationDriver::advanced, [this] () { + if (m_targetParticleSystem) + m_targetParticleSystem->setEditorTime(m_particleAnimationDriver->elapsed()); + }); +#endif + if (m_particleAnimationPlaying && m_targetParticleSystem->visible()) + m_particleAnimationDriver->restart(); + QObject::connect(m_targetParticleSystem, &QQuick3DNode::visibleChanged, [this] () { + if (m_particleAnimationPlaying && m_targetParticleSystem->visible()) { + m_particleAnimationDriver->restart(); + } else { + m_particleAnimationDriver->reset(); + resetParticleSystem(); + } + }); + + const auto anim = animations(); + for (auto a : anim) + a->restart(); +} + +static QString baseProperty(const QString &property) +{ + int index = property.indexOf('.'); + if (index > 0) + return property.left(index); + return property; +} + +void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected() +{ + m_targetParticleSystem = nullptr; + const auto anim = animations(); + int i = 0; + for (auto a : anim) { + a->stop(); + QQuickPropertyAnimation *panim = qobject_cast(a); + if (panim) + panim->target()->setProperty(qPrintable(baseProperty(panim->property())), animationDefaultValue(i)); + i++; + } +} +#endif + // The selection has changed in the edit view 3D. Empty list indicates selection is cleared. void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs) { +#ifdef QUICK3D_PARTICLES_MODULE + resetParticleSystem(); +#endif QList instanceList; const QVariantList varObjs = objs.value(); for (const auto &object : varObjs) { @@ -829,6 +900,12 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView() m_render3DEditViewTimer.start(0); --m_need3DEditViewRender; } +#ifdef QUICK3D_PARTICLES_MODULE + if (ViewConfig::isParticleViewMode() + && m_particleAnimationDriver && m_particleAnimationDriver->isAnimating()) { + m_need3DEditViewRender++; + } +#endif #ifdef FPS_COUNTER // Force constant rendering for accurate fps count if (!m_render3DEditViewTimer.isActive()) @@ -1084,6 +1161,12 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC _fpsTimer->start(); } #endif +#ifdef QUICK3D_PARTICLES_MODULE + if (ViewConfig::isParticleViewMode()) { + m_particleAnimationDriver = new AnimationDriver(this); + m_particleAnimationDriver->setInterval(17); + } +#endif } Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer() @@ -1205,7 +1288,7 @@ QList Qt5InformationNodeInstanceServer::createInstances( void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews() { #ifdef QUICK3D_MODULE - if (isQuick3DMode()) + if (ViewConfig::isQuick3DMode()) createEditView3D(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml"), @@ -1665,7 +1748,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com sendChildrenChangedCommand(instanceList); nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList)); - if (isQuick3DMode()) { + if (ViewConfig::isQuick3DMode()) { setup3DEditView(instanceList, command.edit3dToolStates); updateRotationBlocks(command.auxiliaryChanges); } @@ -1735,7 +1818,9 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm { if (!m_editView3DSetupDone) return; - +#ifdef QUICK3D_PARTICLES_MODULE + resetParticleSystem(); +#endif m_lastSelectionChangeCommand = command; if (m_selectionChangeTimer.isActive()) { // If selection was recently changed by puppet, hold updating the selection for a bit to @@ -1762,13 +1847,17 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm if (firstSceneRoot && sceneRoot == firstSceneRoot && instance.isSubclassOf("QQuick3DNode")) object = instance.internalObject(); +#ifdef QUICK3D_PARTICLES_MODULE + auto particlesystem = qobject_cast(instance.internalObject()); + if (particlesystem) + handleParticleSystemSelected(particlesystem); + else + handleParticleSystemDeselected(); +#endif auto isSelectableAsRoot = [&]() -> bool { #ifdef QUICK3D_MODULE if (qobject_cast(object) || qobject_cast(object) -#ifdef QUICK3D_PARTICLES_MODULE - || qobject_cast(object) -#endif || qobject_cast(object)) { return true; } @@ -1900,6 +1989,33 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c case View3DActionCommand::ShowGrid: updatedState.insert("showGrid", command.isEnabled()); break; +#ifdef QUICK3D_PARTICLES_MODULE + case View3DActionCommand::Edit3DParticleModeToggle: + updatedState.insert("enableParticleViewMode", command.isEnabled()); + break; + case View3DActionCommand::ParticlesPlay: + m_particleAnimationPlaying = command.isEnabled(); + if (m_particleAnimationPlaying) { + m_particleAnimationDriver->reset(); + m_particleAnimationDriver->restart(); + m_particleAnimationDriver->setSeekerEnabled(false); + m_particleAnimationDriver->setSeekerPosition(0); + } else { + m_particleAnimationDriver->reset(); + m_particleAnimationDriver->setSeekerEnabled(true); + } + break; + case View3DActionCommand::ParticlesRestart: + resetParticleSystem(); + m_particleAnimationPlaying = true; + m_particleAnimationDriver->restart(); + m_particleAnimationDriver->setSeekerEnabled(false); + m_particleAnimationDriver->setSeekerPosition(0); + break; + case View3DActionCommand::ParticlesSeek: + m_particleAnimationDriver->setSeekerPosition(static_cast(command).position()); + break; +#endif default: break; } @@ -1977,7 +2093,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInst bool enable, bool checkAncestors) { #ifdef QUICK3D_MODULE - if (!isQuick3DMode()) + if (!ViewConfig::isQuick3DMode()) return; bool edit3dLocked = enable; @@ -2015,7 +2131,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst bool enable, bool checkAncestors) { #ifdef QUICK3D_MODULE - if (!isQuick3DMode()) + if (!ViewConfig::isQuick3DMode()) return; bool edit3dHidden = enable; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index d827075c452..25a4b900ce8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -32,8 +32,14 @@ #include "requestmodelnodepreviewimagecommand.h" #include "propertybindingcontainer.h" #include "propertyabstractcontainer.h" +#include "animationdriver.h" + +#ifdef QUICK3D_PARTICLES_MODULE +#include +#endif #include +#include #include #include #include @@ -140,6 +146,11 @@ private: void removeRotationBlocks(const QVector &instanceIds); void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData); +#ifdef QUICK3D_PARTICLES_MODULE + void handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem); + void resetParticleSystem(); + void handleParticleSystemDeselected(); +#endif RenderViewData m_editView3DData; RenderViewData m_modelNode3DImageViewData; @@ -161,6 +172,12 @@ private: QTimer m_render3DEditViewTimer; QTimer m_renderModelNodeImageViewTimer; QTimer m_inputEventTimer; +#ifdef QUICK3D_PARTICLES_MODULE + bool m_particleAnimationPlaying = true; + AnimationDriver *m_particleAnimationDriver = nullptr; + QMetaObject::Connection m_particleAnimationConnection; + QQuick3DParticleSystem* m_targetParticleSystem = nullptr; +#endif QObjectList m_changedNodes; QList m_changedProperties; ChangeSelectionCommand m_lastSelectionChangeCommand; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp index 44eaab88d22..8b1221a4f44 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp @@ -82,6 +82,7 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) : setNodeInstanceServer(std::make_unique(this)); initializeSocket(); } else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) { + ViewConfig::enableParticleView(true); setNodeInstanceServer(std::make_unique(this)); initializeSocket(); } else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 9f8f5caf528..dbffe2f4fbe 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -60,7 +60,8 @@ namespace QmlDesigner { Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : NodeInstanceServer(nodeInstanceClient) { - DesignerSupport::activateDesignerMode(); + if (!ViewConfig::isParticleViewMode()) + DesignerSupport::activateDesignerMode(); } Qt5NodeInstanceServer::~Qt5NodeInstanceServer() diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.cpp new file mode 100644 index 00000000000..4a20bfcc406 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. 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. +** +** 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. +** +****************************************************************************/ + +#include "viewconfig.h" +#include + +bool ViewConfig::isQuick3DMode() +{ + static bool mode3D = qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE"); + return mode3D; +} + +static bool particleViewEnabled = false; +void ViewConfig::enableParticleView(bool enable) +{ + particleViewEnabled = enable; +} + +bool ViewConfig::isParticleViewMode() +{ + static bool particleviewmode = !qEnvironmentVariableIsSet("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS"); + return particleviewmode && particleViewEnabled; +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.h new file mode 100644 index 00000000000..dcb51551d74 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.h @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. 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. +** +** 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. +** +****************************************************************************/ + +#pragma once + +class ViewConfig +{ +public: + static bool isQuick3DMode(); + static void enableParticleView(bool enable); + static bool isParticleViewMode(); +}; diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp index e920263e1bd..195fd805f47 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,19 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + namespace QmlDesigner { namespace Internal { @@ -382,8 +396,15 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta static_cast(item)->componentComplete(); } else { QQmlParserStatus *qmlParserStatus = dynamic_cast(object); - if (qmlParserStatus) + if (qmlParserStatus) { qmlParserStatus->componentComplete(); + auto *anim = dynamic_cast(object); + if (anim && ViewConfig::isParticleViewMode()) { + nodeInstanceServer->addAnimation(anim); + anim->setEnableUserControl(); + anim->stop(); + } + } } } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index cbd9e5ed504..034d460d8fd 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -116,7 +116,7 @@ Item { text: qsTr("Remove Module") visible: itemsView.currentCategory === null height: visible ? implicitHeight : 0 - enabled: itemsView.importToRemove !== "" + enabled: itemsView.importToRemove !== "" && !rootView.subCompEditMode onTriggered: rootView.removeImport(itemsView.importToRemove) } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml index 8eaa7bbcc75..f5ad0eae3f2 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml @@ -93,8 +93,10 @@ Item { anchors.topMargin: 1 width: 24 height: 24 - color: mouseArea.containsMouse ? StudioTheme.Values.themeControlBackgroundHover - : StudioTheme.Values.themeControlBackground + color: mouseArea.containsMouse && enabled + ? StudioTheme.Values.themeControlBackgroundHover + : StudioTheme.Values.themeControlBackground + enabled: index !== 0 || !rootView.subCompEditMode Label { // + sign text: StudioTheme.Constants.plus diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml index 66f973e1f49..0dff2cba8ba 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml @@ -162,10 +162,17 @@ QtObject { readonly property string visibilityOff: "\u009D" // visibilityOff2 readonly property string visibilityOn: "\u009E" readonly property string wildcard: "\u009F" - readonly property string zoomAll: "\u00A0" - readonly property string zoomIn: "\u00A1" - readonly property string zoomOut: "\u00A2" - readonly property string zoomSelection: "\u00A3" + readonly property string wizardsAutomotive: "\u00A0" + readonly property string wizardsDesktop: "\u00A1" + readonly property string wizardsGeneric: "\u00A2" + readonly property string wizardsMcuEmpty: "\u00A3" + readonly property string wizardsMcuGraph: "\u00A4" + readonly property string wizardsMobile: "\u00A5" + readonly property string wizardsUnknown: "\u00A6" + readonly property string zoomAll: "\u00A7" + readonly property string zoomIn: "\u00A8" + readonly property string zoomOut: "\u00A9" + readonly property string zoomSelection: "\u00AA" 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 da54c6b6030..403bb7205ad 100644 Binary files a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf and b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf differ diff --git a/src/libs/clangsupport/diagnosticcontainer.cpp b/src/libs/clangsupport/diagnosticcontainer.cpp index 889e51d650c..1f7c013f0b5 100644 --- a/src/libs/clangsupport/diagnosticcontainer.cpp +++ b/src/libs/clangsupport/diagnosticcontainer.cpp @@ -47,5 +47,17 @@ QDebug operator<<(QDebug debug, const DiagnosticContainer &container) return debug; } +QDebug operator<<(QDebug debug, const QVector &containers) +{ + debug.nospace() << "{"; + for (int i = 0; i < containers.size(); i++) { + debug.nospace() << containers[i]; + if (i < containers.size() - 1) + debug.nospace() << ", "; + } + debug.nospace() << "}"; + return debug; +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/diagnosticcontainer.h b/src/libs/clangsupport/diagnosticcontainer.h index f8344ccf767..65306bf8a6b 100644 --- a/src/libs/clangsupport/diagnosticcontainer.h +++ b/src/libs/clangsupport/diagnosticcontainer.h @@ -123,5 +123,8 @@ public: }; CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const DiagnosticContainer &container); +CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector &container); + + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/fixitcontainer.cpp b/src/libs/clangsupport/fixitcontainer.cpp index 29caaf71018..7b1404ac9ec 100644 --- a/src/libs/clangsupport/fixitcontainer.cpp +++ b/src/libs/clangsupport/fixitcontainer.cpp @@ -39,5 +39,17 @@ QDebug operator<<(QDebug debug, const FixItContainer &container) return debug; } +QDebug operator<<(QDebug debug, const QVector &containers) +{ + debug.nospace() << "{"; + for (int i = 0; i < containers.size(); i++) { + debug.nospace() << containers[i]; + if (i < containers.size() - 1) + debug.nospace() << ", "; + } + debug.nospace() << "}"; + return debug; +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/fixitcontainer.h b/src/libs/clangsupport/fixitcontainer.h index e13199712ef..81667fe76e0 100644 --- a/src/libs/clangsupport/fixitcontainer.h +++ b/src/libs/clangsupport/fixitcontainer.h @@ -69,5 +69,6 @@ public: }; CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FixItContainer &container); +CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector &container); } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/sourcerangecontainer.cpp b/src/libs/clangsupport/sourcerangecontainer.cpp index 81348356285..d9146d0ff33 100644 --- a/src/libs/clangsupport/sourcerangecontainer.cpp +++ b/src/libs/clangsupport/sourcerangecontainer.cpp @@ -39,4 +39,16 @@ QDebug operator<<(QDebug debug, const SourceRangeContainer &container) return debug; } +QDebug operator<<(QDebug debug, const QVector &containers) +{ + debug.nospace() << "{"; + for (int i = 0; i < containers.size(); i++) { + debug.nospace() << containers[i]; + if (i < containers.size() - 1) + debug.nospace() << ", "; + } + debug.nospace() << "}"; + return debug; +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/sourcerangecontainer.h b/src/libs/clangsupport/sourcerangecontainer.h index 603143e210a..39a0e6cb210 100644 --- a/src/libs/clangsupport/sourcerangecontainer.h +++ b/src/libs/clangsupport/sourcerangecontainer.h @@ -85,5 +85,6 @@ public: }; CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const SourceRangeContainer &container); +CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector &container); } // namespace ClangBackEnd diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml index e6fcc8ddb4e..4931b7aa30f 160000 --- a/src/libs/qlitehtml +++ b/src/libs/qlitehtml @@ -1 +1 @@ -Subproject commit e6fcc8ddb4e435160cca6a94bd7b011fd1698656 +Subproject commit 4931b7aa30f256c20573d283561aa432fecf8f38 diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 38595a8b363..bd5d25834ed 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -1275,6 +1275,9 @@ static bool isIntegerValue(const Value *value) static bool strictCompareConstant(const Value *lhs, const Value *rhs) { + // attached properties and working at runtime cases may be undefined at evaluation time + if (lhs->asUndefinedValue() || rhs->asUndefinedValue()) + return false; if (lhs->asUnknownValue() || rhs->asUnknownValue()) return false; if (lhs->asFunctionValue() || rhs->asFunctionValue()) // function evaluation not implemented @@ -1283,12 +1286,11 @@ static bool strictCompareConstant(const Value *lhs, const Value *rhs) return false; if (lhs->asBooleanValue() && !rhs->asBooleanValue()) return true; - // attached properties and working at runtime cases may be undefined at evaluation time - if (lhs->asNumberValue() && (!rhs->asNumberValue() && !rhs->asUndefinedValue())) + if (lhs->asNumberValue() && !rhs->asNumberValue()) return true; if (lhs->asStringValue() && !rhs->asStringValue()) return true; - if (lhs->asObjectValue() && (!rhs->asObjectValue() || !rhs->asNullValue() || !rhs->asUndefinedValue())) + if (lhs->asObjectValue() && (!rhs->asObjectValue() || !rhs->asNullValue())) return true; return false; } diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index fc7b865e676..1dc3b45e328 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -30,7 +30,6 @@ #include "qtcassert.h" #include -#include #include #include @@ -542,14 +541,11 @@ bool CallerHandle::isCalledFromLaunchersThread() const bool LauncherHandle::waitForSignal(int msecs, CallerHandle::SignalType newSignal) { QTC_ASSERT(!isCalledFromLaunchersThread(), return false); - QElapsedTimer timer; - timer.start(); + QDeadlineTimer deadline(msecs); while (true) { - const int remainingMsecs = msecs - timer.elapsed(); - if (remainingMsecs <= 0) + if (deadline.hasExpired()) break; - const bool timedOut = !doWaitForSignal(qMax(remainingMsecs, 0), newSignal); - if (timedOut) + if (!doWaitForSignal(deadline, newSignal)) break; m_awaitingShouldContinue = true; // TODO: make it recursive? const QList flushedSignals = m_callerHandle->flushFor(newSignal); @@ -563,14 +559,12 @@ bool LauncherHandle::waitForSignal(int msecs, CallerHandle::SignalType newSignal return true; if (wasCanceled) return true; // or false? is false only in case of timeout? - if (timer.hasExpired(msecs)) - break; } return false; } // Called from caller's thread exclusively. -bool LauncherHandle::doWaitForSignal(int msecs, CallerHandle::SignalType newSignal) +bool LauncherHandle::doWaitForSignal(QDeadlineTimer deadline, CallerHandle::SignalType newSignal) { QMutexLocker locker(&m_mutex); QTC_ASSERT(isCalledFromCallersThread(), return false); @@ -585,7 +579,7 @@ bool LauncherHandle::doWaitForSignal(int msecs, CallerHandle::SignalType newSign return true; m_waitingFor = newSignal; - const bool ret = m_waitCondition.wait(&m_mutex, msecs); + const bool ret = m_waitCondition.wait(&m_mutex, deadline); m_waitingFor = CallerHandle::SignalType::NoSignal; return ret; } diff --git a/src/libs/utils/launchersocket.h b/src/libs/utils/launchersocket.h index 9708cf0430c..42b5fa757e8 100644 --- a/src/libs/utils/launchersocket.h +++ b/src/libs/utils/launchersocket.h @@ -28,6 +28,7 @@ #include "launcherpackets.h" #include "processutils.h" +#include #include #include #include @@ -213,7 +214,7 @@ public: private: // Called from caller's thread exclusively. - bool doWaitForSignal(int msecs, CallerHandle::SignalType newSignal); + bool doWaitForSignal(QDeadlineTimer deadline, CallerHandle::SignalType newSignal); // Called from launcher's thread exclusively. Call me with mutex locked. void wakeUpIfWaitingFor(CallerHandle::SignalType newSignal); diff --git a/src/libs/utils/multitextcursor.cpp b/src/libs/utils/multitextcursor.cpp index 7225de9344a..a73c58bbb1d 100644 --- a/src/libs/utils/multitextcursor.cpp +++ b/src/libs/utils/multitextcursor.cpp @@ -294,7 +294,7 @@ static QTextLine currentTextLine(const QTextCursor &cursor) return layout->lineForTextPosition(relativePos); } -bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey) +bool MultiTextCursor::multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey) { uint searchkey = (e->modifiers() | e->key()) & ~(Qt::KeypadModifier diff --git a/src/libs/utils/multitextcursor.h b/src/libs/utils/multitextcursor.h index 90938848e8b..8fdf041faa0 100644 --- a/src/libs/utils/multitextcursor.h +++ b/src/libs/utils/multitextcursor.h @@ -27,6 +27,7 @@ #include "utils_global.h" +#include #include QT_BEGIN_NAMESPACE @@ -99,6 +100,8 @@ public: const_iterator constBegin() const { return m_cursors.constBegin(); } const_iterator constEnd() const { return m_cursors.constEnd(); } + static bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey); + private: QList m_cursors; }; diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 5313cb1ccab..b0859ae6a05 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -847,7 +847,7 @@ bool AndroidConfig::isValidNdk(const QString &ndkLocation) const return false; const QVersionNumber version = ndkVersion(ndkPath); - if (ndkVersion(ndkPath).isNull()) + if (version.isNull()) return false; const FilePath ndkPlatformsDir = ndkPath.pathAppended("platforms"); diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 16ff0dc5139..b1a1f15fdee 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -81,12 +81,12 @@ using namespace Android::Internal; namespace Android { -const QLatin1String AndroidManifestName("AndroidManifest.xml"); -const QLatin1String AndroidDeviceSn("AndroidDeviceSerialNumber"); -const QLatin1String AndroidDeviceAbis("AndroidDeviceAbis"); -const QLatin1String ApiLevelKey("AndroidVersion.ApiLevel"); -const char qtcSignature[] = "This file is generated by QtCreator to be read by androiddeployqt " - "and should not be modified by hand."; +const char AndroidManifestName[] = "AndroidManifest.xml"; +const char AndroidDeviceSn[] = "AndroidDeviceSerialNumber"; +const char AndroidDeviceAbis[] = "AndroidDeviceAbis"; +const char ApiLevelKey[] = "AndroidVersion.ApiLevel"; +const char qtcSignature[] = "This file is generated by QtCreator to be read by " + "androiddeployqt and should not be modified by hand."; static Q_LOGGING_CATEGORY(androidManagerLog, "qtc.android.androidManager", QtWarningMsg) @@ -132,7 +132,8 @@ QString AndroidManager::activityName(const Target *target) QDomDocument doc; if (!openManifest(target, doc)) return QString(); - QDomElement activityElem = doc.documentElement().firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")); + QDomElement activityElem = doc.documentElement().firstChildElement( + QLatin1String("application")).firstChildElement(QLatin1String("activity")); return activityElem.attribute(QLatin1String("android:name")); } @@ -418,17 +419,18 @@ static QString preferredAbi(const QStringList &appAbis, const Target *target) QString AndroidManager::apkDevicePreferredAbi(const Target *target) { - auto libsPath = androidBuildDirectory(target).pathAppended("libs"); + const FilePath libsPath = androidBuildDirectory(target).pathAppended("libs"); if (!libsPath.exists()) { if (const ProjectNode *node = currentProjectNode(target)) return preferredAbi(node->data(Android::Constants::AndroidAbis).toStringList(), target); } QStringList apkAbis; - const auto libsPaths = QDir{libsPath.toString()}.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - for (const auto &abi : libsPaths) - if (!QDir{libsPath.pathAppended(abi).toString()}.entryList(QStringList("*.so"), QDir::Files | QDir::NoDotAndDotDot).isEmpty()) - apkAbis << abi; + const FilePaths libsPaths = libsPath.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot); + for (const FilePath &abiDir : libsPaths) { + if (!abiDir.dirEntries(QStringList("*.so"), QDir::Files | QDir::NoDotAndDotDot).isEmpty()) + apkAbis << abiDir.fileName(); + } return preferredAbi(apkAbis, target); } diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index aa88fdc903c..e2edfdd8065 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -195,7 +195,9 @@ static FilePath debugServer(bool useLldb, const Target *target) const QString abiNeedle = lldbServerArch2(preferredAbi); // The new, built-in LLDB. - QDirIterator it(prebuilt.toString(), QDir::Files|QDir::Executable, QDirIterator::Subdirectories); + const QDir::Filters dirFilter = HostOsInfo::isWindowsHost() ? QDir::Files + : QDir::Files|QDir::Executable; + QDirIterator it(prebuilt.toString(), dirFilter, QDirIterator::Subdirectories); while (it.hasNext()) { it.next(); const QString filePath = it.filePath(); diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 7efc37a5728..17fe2775074 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -928,6 +928,7 @@ public: m_started = false; qCDebug(clangdLogTiming).noquote().nospace() << m_task << ": took " << m_elapsedMs << " ms in UI thread"; + m_elapsedMs = 0; } void startSubtask() { diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 3de996bd4da..601ed3a1e70 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -168,7 +168,7 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config) "project(qmake-probe LANGUAGES NONE)\n" "\n" "# Bypass Qt6's usage of find_dependency, which would require compiler\n" -"# and source code probing, which slows things unnecessarily" +"# and source code probing, which slows things unnecessarily\n" "file(WRITE \"${CMAKE_SOURCE_DIR}/CMakeFindDependencyMacro.cmake\"\n" "[=[" " macro(find_dependency dep)\n" diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 3e899ae01f6..022d4cf6fbf 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -255,15 +255,16 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD layout->addLayout(formLayout); layout->addStretch(1); - const auto toggleEnabled = [=](const bool checked) { - chooserLabel->setEnabled(checked); - d->clangdChooser.setEnabled(checked); - indexingLabel->setEnabled(checked); - d->indexingCheckBox.setEnabled(checked); - autoIncludeHeadersLabel->setEnabled(checked); - d->autoIncludeHeadersCheckBox.setEnabled(checked); - d->threadLimitSpinBox.setEnabled(checked); - d->versionWarningLabel.setEnabled(checked); + static const auto setWidgetsEnabled = [](QLayout *layout, bool enabled, const auto &f) -> void { + for (int i = 0; i < layout->count(); ++i) { + if (QWidget * const w = layout->itemAt(i)->widget()) + w->setEnabled(enabled); + else if (QLayout * const l = layout->itemAt(i)->layout()) + f(l, enabled, f); + } + }; + const auto toggleEnabled = [formLayout](const bool checked) { + setWidgetsEnabled(formLayout, checked, setWidgetsEnabled); }; connect(&d->useClangdCheckBox, &QCheckBox::toggled, toggleEnabled); toggleEnabled(d->useClangdCheckBox.isChecked()); diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 200579b6dd5..a5440edb7fd 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -213,7 +213,15 @@ void LldbEngine::setupEngine() showMessage("STARTING LLDB: " + lldbCmd.toUserOutput()); Environment environment = runParameters().debugger.environment; environment.appendOrSet("PYTHONUNBUFFERED", "1"); // avoid flushing problem on macOS + if (lldbCmd.path().contains("/ndk-bundle/")) { + FilePath androidPythonDir = lldbCmd.parentDir().parentDir().pathAppended("python3"); + if (HostOsInfo::isAnyUnixHost()) + androidPythonDir = androidPythonDir.pathAppended("bin"); + if (androidPythonDir.exists()) + environment.prependOrSetPath(androidPythonDir.path()); + } m_lldbProc.setEnvironment(environment); + if (runParameters().debugger.workingDirectory.isDir()) m_lldbProc.setWorkingDirectory(runParameters().debugger.workingDirectory); diff --git a/src/plugins/help/CMakeLists.txt b/src/plugins/help/CMakeLists.txt index e63599eb07e..09050db7b96 100644 --- a/src/plugins/help/CMakeLists.txt +++ b/src/plugins/help/CMakeLists.txt @@ -49,12 +49,7 @@ extend_qtc_plugin(Help macwebkithelpviewer.mm ) -set(BUILD_HELPVIEWERBACKEND_QTWEBENGINE_DEFAULT YES) -if (Qt6_FOUND) - set(BUILD_HELPVIEWERBACKEND_QTWEBENGINE_DEFAULT NO) -endif () - -option(BUILD_HELPVIEWERBACKEND_QTWEBENGINE "Build QtWebEngine based help viewer backend." ${BUILD_HELPVIEWERBACKEND_QTWEBENGINE_DEFAULT}) +option(BUILD_HELPVIEWERBACKEND_QTWEBENGINE "Build QtWebEngine based help viewer backend." YES) find_package(Qt5 COMPONENTS WebEngineWidgets QUIET) extend_qtc_plugin(Help CONDITION BUILD_HELPVIEWERBACKEND_QTWEBENGINE AND TARGET Qt5::WebEngineWidgets diff --git a/src/plugins/help/webenginehelpviewer.cpp b/src/plugins/help/webenginehelpviewer.cpp index 65d80c4d30c..7ece25833ff 100644 --- a/src/plugins/help/webenginehelpviewer.cpp +++ b/src/plugins/help/webenginehelpviewer.cpp @@ -37,7 +37,11 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) +#include +#else #include +#endif #include #include #include @@ -335,7 +339,11 @@ bool WebView::eventFilter(QObject *src, QEvent *e) void WebView::contextMenuEvent(QContextMenuEvent *event) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) + QMenu *menu = createStandardContextMenu(); +#else QMenu *menu = page()->createStandardContextMenu(); +#endif // insert Open as New Page etc if OpenLinkInThisWindow is also there const QList actions = menu->actions(); auto it = std::find(actions.cbegin(), actions.cend(), @@ -344,7 +352,11 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) // insert after ++it; QAction *before = (it == actions.cend() ? 0 : *it); +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) + QUrl url = lastContextMenuRequest()->linkUrl(); +#else QUrl url = page()->contextMenuData().linkUrl(); +#endif if (m_viewer->isActionVisible(HelpViewer::Action::NewPage)) { auto openLink = new QAction(QCoreApplication::translate("HelpViewer", Constants::TR_OPEN_LINK_AS_NEW_PAGE), menu); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index 31155c276c0..d460995aa81 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -494,6 +494,11 @@ void JsonWizardFactory::addWizardPath(const FilePath &path) searchPaths().append(path); } +void JsonWizardFactory::clearWizardPaths() +{ + searchPaths().clear(); +} + void JsonWizardFactory::setVerbose(int level) { m_verbose = level; diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h index d69aaa00f0b..2ecabe6bc3d 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h @@ -51,6 +51,7 @@ class PROJECTEXPLORER_EXPORT JsonWizardFactory : public Core::IWizardFactory public: // Add search paths for wizard.json files. All subdirs are going to be checked. static void addWizardPath(const Utils::FilePath &path); + static void clearWizardPaths(); // actual interface of the wizard factory: class Generator { diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 48cdb6f123d..901a631a421 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -4,7 +4,7 @@ if (APPLE) endif() add_qtc_plugin(QmlDesigner - CONDITION TARGET Qt5::QuickWidgets + CONDITION TARGET Qt5::QuickWidgets AND TARGET Qt5::Svg DEPENDS QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem Qt5::QuickWidgets Qt5::CorePrivate Sqlite Qt5::Xml Qt5::Svg @@ -27,6 +27,7 @@ add_qtc_plugin(QmlDesigner designmodewidget.cpp designmodewidget.h documentmanager.cpp documentmanager.h documentwarningwidget.cpp documentwarningwidget.h + cmakegeneratordialog.h cmakegeneratordialog.cpp generateresource.cpp generateresource.h generatecmakelists.cpp generatecmakelists.h openuiqmlfiledialog.cpp openuiqmlfiledialog.h openuiqmlfiledialog.ui @@ -201,6 +202,7 @@ extend_qtc_plugin(QmlDesigner rubberbandselectionmanipulator.cpp rubberbandselectionmanipulator.h scaleitem.cpp scaleitem.h scalemanipulator.cpp scalemanipulator.h + seekerslider.cpp seekerslider.h selectionindicator.cpp selectionindicator.h selectionrectangle.cpp selectionrectangle.h selectiontool.cpp selectiontool.h diff --git a/src/plugins/qmldesigner/cmakegeneratordialog.cpp b/src/plugins/qmldesigner/cmakegeneratordialog.cpp new file mode 100644 index 00000000000..59625c6035f --- /dev/null +++ b/src/plugins/qmldesigner/cmakegeneratordialog.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** 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. 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. +** +** 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. +** +****************************************************************************/ + + +#include "cmakegeneratordialog.h" + +#include +#include +#include +#include +#include + +using namespace Utils; + +namespace QmlDesigner { +namespace GenerateCmake { + +CmakeGeneratorDialog::CmakeGeneratorDialog(const FilePath &rootDir, const FilePaths &files) + : QDialog() +{ + QVBoxLayout *layout = new QVBoxLayout(this); + setLayout(layout); + + QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); + + auto *okButton = buttons->button(QDialogButtonBox::Ok); + okButton->setDefault(true); + + connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); + + model = new CheckableFileListModel(rootDir, files, this); + + QListView *list = new QListView(this); + list->setModel(model); + + layout->addWidget(list); + layout->addWidget(buttons); +} + +FilePaths CmakeGeneratorDialog::getFilePaths() +{ + FilePaths paths; + + QList items = model->checkedItems(); + for (CheckableStandardItem *item: items) { + paths.append(FilePath::fromString(item->text())); + } + + return paths; +} + +CheckableFileListModel::CheckableFileListModel(const FilePath &rootDir, const FilePaths &files, QObject *parent) + :QStandardItemModel(parent), + rootDir(rootDir) +{ + for (const FilePath &file: files) { + appendRow(new CheckableStandardItem(file.toString(), true)); + } +} + +QList CheckableFileListModel::checkedItems() const +{ +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + QList allItems = findItems("*", Qt::MatchWildcard); +#else + QList allItems = findItems(".*", Qt::MatchRegularExpression); +#endif + QList checkedItems; + for (QStandardItem *standardItem : allItems) { + CheckableStandardItem *item = static_cast(standardItem); + if (item->isChecked()) + checkedItems.append(item); + } + + return checkedItems; +} + +CheckableStandardItem::CheckableStandardItem(const QString &text, bool checked) + :QStandardItem(text), + checked(checked) +{ + setFlags(flags() |= Qt::ItemIsUserCheckable); +} + +void CheckableStandardItem::setChecked(bool checked) +{ + this->checked = checked; +} + +bool CheckableStandardItem::isChecked() const +{ + return this->checked; +} + +int CheckableStandardItem::type() const +{ + return QStandardItem::UserType + 0x74d4f1; +} + +QVariant CheckableFileListModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid()) { + if (role == Qt::CheckStateRole) { + CheckableStandardItem *item = static_cast(QStandardItemModel::item(index.row())); + return item->isChecked() ? Qt::Checked : Qt::Unchecked; + } + else if (role == Qt::DisplayRole) { + QVariant data = QStandardItemModel::data(index, role); + QString relativePath = data.toString().remove(rootDir.toString()); + return QVariant(relativePath); + } + } + + return QStandardItemModel::data(index, role); +} + +bool CheckableFileListModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::CheckStateRole) + { + CheckableStandardItem *item = static_cast(QStandardItemModel::item(index.row())); + item->setChecked(value.value()); + + return true; + } + + return QStandardItemModel::setData(index, value, role); +} + +} +} diff --git a/src/plugins/qmldesigner/cmakegeneratordialog.h b/src/plugins/qmldesigner/cmakegeneratordialog.h new file mode 100644 index 00000000000..34201365100 --- /dev/null +++ b/src/plugins/qmldesigner/cmakegeneratordialog.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** 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. 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. +** +** 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. +** +****************************************************************************/ + + +#ifndef CMAKEGENERATORDIALOG_H +#define CMAKEGENERATORDIALOG_H + +#include + +#include +#include + +namespace QmlDesigner { +namespace GenerateCmake { + +class CheckableStandardItem : public QStandardItem +{ +public: + explicit CheckableStandardItem(const QString &text = QString(), bool checked = false); + bool isChecked() const; + void setChecked(bool checked); + int type() const; + +private: + bool checked; +}; + +class CheckableFileListModel : public QStandardItemModel +{ +public: + CheckableFileListModel(const Utils::FilePath &rootDir, const Utils::FilePaths &files, QObject *parent = nullptr); + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + QList checkedItems() const; + +private: + Utils::FilePath rootDir; +}; + +class CmakeGeneratorDialog : public QDialog +{ +public: + CmakeGeneratorDialog(const Utils::FilePath &rootDir, const Utils::FilePaths &files); + Utils::FilePaths getFilePaths(); + +private: + CheckableFileListModel *model; +}; + +} +} + +Q_DECLARE_METATYPE(QmlDesigner::GenerateCmake::CheckableStandardItem) + +#endif // CMAKEGENERATORDIALOG_H diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h index fcaf45e18e5..2ef1f82cbb6 100644 --- a/src/plugins/qmldesigner/components/componentcore/theme.h +++ b/src/plugins/qmldesigner/components/componentcore/theme.h @@ -170,6 +170,13 @@ public: visibilityOff, // visibilityOff2 visibilityOn, wildcard, + wizardsAutomotive, + wizardsDesktop, + wizardsGeneric, + wizardsMcuEmpty, + wizardsMcuGraph, + wizardsMobile, + wizardsUnknown, zoomAll, zoomIn, zoomOut, diff --git a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc index 69e7113f023..13ac3b0a499 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc +++ b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc @@ -34,5 +34,15 @@ images/select_item@2x.png images/orthographic_camera.png images/orthographic_camera@2x.png - + images/particles_off.png + images/particles_off@2x.png + images/particles_on.png + images/particles_on@2x.png + images/particles_play.png + images/particles_play@2x.png + images/particles_pause.png + images/particles_pause@2x.png + images/particles_restart.png + images/particles_restart@2x.png + diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index e5a8c1747aa..c6fa4a0bdb5 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -209,6 +210,11 @@ QSize Edit3DView::canvasSize() const return {}; } +void Edit3DView::setSeeker(SeekerSlider *slider) +{ + m_seeker = slider; +} + void Edit3DView::createEdit3DActions() { m_selectionModeAction @@ -272,9 +278,59 @@ void Edit3DView::createEdit3DActions() Icons::EDIT3D_GRID_ON.icon()); SelectionContextOperation resetTrigger = [this](const SelectionContext &) { + m_particlesPlayAction->action()->setEnabled(particlemode); + m_particlesRestartAction->action()->setEnabled(particlemode); + if (particlemode) + m_particlesPlayAction->action()->setChecked(true); + if (m_seeker) + m_seeker->setEnabled(false); setCurrentStateNode(rootModelNode()); resetPuppet(); }; + + SelectionContextOperation particlesTrigger = [this](const SelectionContext &) { + particlemode = !particlemode; + m_particlesPlayAction->action()->setEnabled(particlemode); + m_particlesRestartAction->action()->setEnabled(particlemode); + if (m_seeker) + m_seeker->setEnabled(false); + QmlDesigner::DesignerSettings::setValue("particleMode", particlemode); + setCurrentStateNode(rootModelNode()); + resetPuppet(); + }; + + SelectionContextOperation particlesRestartTrigger = [this](const SelectionContext &) { + m_particlesPlayAction->action()->setChecked(true); + if (m_seeker) + m_seeker->setEnabled(false); + }; + + SelectionContextOperation particlesPlayTrigger = [this](const SelectionContext &) { + if (m_seeker) + m_seeker->setEnabled(!m_particlesPlayAction->action()->isChecked()); + }; + + m_particleViewModeAction + = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_PARTICLE_MODE, View3DActionCommand::Edit3DParticleModeToggle, + QCoreApplication::translate("ParticleViewModeAction", "Toggle particle animation On/Off"), + QKeySequence(Qt::Key_V), true, false, Icons::EDIT3D_PARTICLE_OFF.icon(), + Icons::EDIT3D_PARTICLE_ON.icon(), particlesTrigger); + particlemode = false; + m_particlesPlayAction + = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_PARTICLES_PLAY, View3DActionCommand::ParticlesPlay, + QCoreApplication::translate("ParticlesPlayAction", "Play Particles"), + QKeySequence(Qt::Key_W), true, true, Icons::EDIT3D_PARTICLE_PLAY.icon(), + Icons::EDIT3D_PARTICLE_PAUSE.icon(), particlesPlayTrigger); + m_particlesRestartAction + = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_PARTICLES_RESTART, View3DActionCommand::ParticlesRestart, + QCoreApplication::translate("ParticlesRestartAction", "Restart Particles"), + QKeySequence(Qt::Key_E), false, false, Icons::EDIT3D_PARTICLE_RESTART.icon(), + Icons::EDIT3D_PARTICLE_RESTART.icon(), particlesRestartTrigger); + m_particlesPlayAction->action()->setEnabled(particlemode); + m_particlesRestartAction->action()->setEnabled(particlemode); m_resetAction = new Edit3DAction( QmlDesigner::Constants::EDIT3D_RESET_VIEW, View3DActionCommand::Empty, @@ -296,6 +352,10 @@ void Edit3DView::createEdit3DActions() m_leftActions << m_editLightAction; m_leftActions << m_showGridAction; + m_rightActions << m_particleViewModeAction; + m_rightActions << m_particlesPlayAction; + m_rightActions << m_particlesRestartAction; + m_rightActions << nullptr; m_rightActions << m_resetAction; } @@ -311,7 +371,8 @@ QVector Edit3DView::rightActions() const void Edit3DView::addQuick3DImport() { - if (model()) { + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + if (document && !document->inFileComponentModelActive() && model()) { const QList imports = model()->possibleImports(); for (const auto &import : imports) { if (import.url() == "QtQuick3D") { diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index 6c3ae892a91..2001dbbcf4d 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -25,6 +25,7 @@ #pragma once #include "view3dactioncommand.h" +#include "seekerslider.h" #include #include @@ -68,6 +69,7 @@ public: void createEdit3DActions(); QVector leftActions() const; QVector rightActions() const; + void setSeeker(SeekerSlider *slider); void addQuick3DImport(); @@ -90,6 +92,11 @@ private: Edit3DAction *m_editLightAction = nullptr; Edit3DAction *m_showGridAction = nullptr; Edit3DAction *m_resetAction = nullptr; + Edit3DAction *m_particleViewModeAction = nullptr; + Edit3DAction *m_particlesPlayAction = nullptr; + Edit3DAction *m_particlesRestartAction = nullptr; + SeekerSlider *m_seeker = nullptr; + int particlemode; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 968cab58466..57a4877301d 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -33,6 +33,8 @@ #include "qmldesignerplugin.h" #include "qmlvisualnode.h" #include "viewmanager.h" +#include +#include #include #include @@ -64,8 +66,11 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : fillLayout->setSpacing(0); setLayout(fillLayout); + SeekerSlider *seeker = new SeekerSlider(this); + seeker->setEnabled(false); + // Initialize toolbar - m_toolBox = new ToolBox(this); + m_toolBox = new ToolBox(seeker, this); fillLayout->addWidget(m_toolBox.data()); // Iterate through view actions. A null action indicates a separator and a second null action @@ -100,7 +105,10 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : auto separator = new QAction(this); separator->setSeparator(true); addAction(separator); - m_toolBox->addLeftSideAction(separator); + if (left) + m_toolBox->addLeftSideAction(separator); + else + m_toolBox->addRightSideAction(separator); previousWasSeparator = true; } } @@ -109,6 +117,14 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : addActionsToToolBox(view->leftActions(), true); addActionsToToolBox(view->rightActions(), false); + view->setSeeker(seeker); + seeker->setToolTip(QLatin1String("Seek particle system time when paused.")); + + QObject::connect(seeker, &SeekerSlider::positionChanged, [this, seeker](){ + QmlDesignerPlugin::instance()->viewManager().nodeInstanceView() + ->view3DAction(View3DSeekActionCommand(seeker->position())); + }); + // Onboarding label contains instructions for new users how to get 3D content into the project m_onboardingLabel = new QLabel(this); QString labelText = diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_off.png b/src/plugins/qmldesigner/components/edit3d/images/particles_off.png new file mode 100644 index 00000000000..8f5c8355414 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_off.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_off@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_off@2x.png new file mode 100644 index 00000000000..b77feeee014 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_off@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_on.png b/src/plugins/qmldesigner/components/edit3d/images/particles_on.png new file mode 100644 index 00000000000..c01b374040d Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_on.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_on@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_on@2x.png new file mode 100644 index 00000000000..9a0e06578d5 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_on@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_pause.png b/src/plugins/qmldesigner/components/edit3d/images/particles_pause.png new file mode 100644 index 00000000000..89d6fd8211c Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_pause.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_pause@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_pause@2x.png new file mode 100644 index 00000000000..94276bf81e6 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_pause@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_play.png b/src/plugins/qmldesigner/components/edit3d/images/particles_play.png new file mode 100644 index 00000000000..d0c2c58d2b8 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_play.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_play@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_play@2x.png new file mode 100644 index 00000000000..07dedc164ee Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_play@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_restart.png b/src/plugins/qmldesigner/components/edit3d/images/particles_restart.png new file mode 100644 index 00000000000..e427433e4e7 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_restart.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_restart@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_restart@2x.png new file mode 100644 index 00000000000..90981337b17 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_restart@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/playpause.png b/src/plugins/qmldesigner/components/edit3d/images/playpause.png new file mode 100644 index 00000000000..c86b8068181 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/playpause.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/playpause@2x.png b/src/plugins/qmldesigner/components/edit3d/images/playpause@2x.png new file mode 100644 index 00000000000..4b92db41cca Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/playpause@2x.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.pri b/src/plugins/qmldesigner/components/formeditor/formeditor.pri index 833260dd1a0..df905d377db 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditor.pri +++ b/src/plugins/qmldesigner/components/formeditor/formeditor.pri @@ -42,7 +42,8 @@ SOURCES += formeditoritem.cpp \ backgroundaction.cpp \ formeditortoolbutton.cpp \ formeditorannotationicon.cpp \ - transitiontool.cpp + transitiontool.cpp \ + seekerslider.cpp HEADERS += formeditorscene.h \ formeditorwidget.h \ @@ -87,6 +88,7 @@ HEADERS += formeditorscene.h \ backgroundaction.h \ formeditortoolbutton.h \ formeditorannotationicon.h \ - transitiontool.h + transitiontool.h \ + seekerslider.h RESOURCES += formeditor.qrc diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.qrc b/src/plugins/qmldesigner/components/formeditor/formeditor.qrc index 45170bde01d..23a15d7effa 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditor.qrc +++ b/src/plugins/qmldesigner/components/formeditor/formeditor.qrc @@ -8,5 +8,11 @@ snapping_and_anchoring@2x.png annotationsIcon.png annotationsIconActive.png + scrubbg.png + scrubbg@2x.png + scrubhandle-24.png + scrubhandle-48.png + scrubhandle-disabled-24.png + scrubhandle-disabled-48.png diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 187bc4ca17f..a72fcb1387c 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -326,13 +326,15 @@ void FormEditorView::propertiesAboutToBeRemoved(const QList& p m_currentTool->itemsAboutToRemoved(removedItems); } -static inline bool hasNodeSourceParent(const ModelNode &node) +static inline bool hasNodeSourceOrNonItemParent(const ModelNode &node) { if (node.hasParentProperty() && node.parentProperty().parentModelNode().isValid()) { ModelNode parent = node.parentProperty().parentModelNode(); - if (parent.nodeSourceType() != ModelNode::NodeWithoutSource) + if (parent.nodeSourceType() != ModelNode::NodeWithoutSource + || !QmlItemNode::isItemOrWindow(parent)) { return true; - return hasNodeSourceParent(parent); + } + return hasNodeSourceOrNonItemParent(parent); } return false; } @@ -867,7 +869,7 @@ void FormEditorView::addOrRemoveFormEditorItem(const ModelNode &node) removeNodeFromScene(itemNode); } }; - if (hasNodeSourceParent(node)) { + if (hasNodeSourceOrNonItemParent(node)) { removeItemFromScene(); } else if (itemNode.isValid()) { if (node.nodeSourceType() == ModelNode::NodeWithoutSource) { diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index 842dee7e130..31aa8a4de69 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -139,7 +139,7 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) addAction(m_rootHeightAction.data()); upperActions.append(m_rootHeightAction.data()); - m_toolBox = new ToolBox(this); + m_toolBox = new ToolBox(nullptr, this); fillLayout->addWidget(m_toolBox.data()); m_toolBox->setLeftSideActions(upperActions); @@ -246,14 +246,14 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) }; m_zoomInAction = new QAction(zoomInIcon, tr("Zoom In"), this); - m_zoomInAction->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Plus)); + m_zoomInAction->setShortcut(QKeySequence(QKeySequence::ZoomIn)); addAction(m_zoomInAction.data()); upperActions.append(m_zoomInAction.data()); m_toolBox->addRightSideAction(m_zoomInAction.data()); connect(m_zoomInAction.data(), &QAction::triggered, zoomIn); m_zoomOutAction = new QAction(zoomOutIcon, tr("Zoom Out"), this); - m_zoomOutAction->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Minus)); + m_zoomOutAction->setShortcut(QKeySequence(QKeySequence::ZoomOut)); addAction(m_zoomOutAction.data()); upperActions.append(m_zoomOutAction.data()); m_toolBox->addRightSideAction(m_zoomOutAction.data()); @@ -266,7 +266,8 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) connect(m_zoomAction.data(), &ZoomAction::zoomLevelChanged, setZoomLevel); m_zoomAllAction = new QAction(zoomAllIcon, tr("Zoom screen to fit all content."), this); - m_zoomAllAction->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_0)); + m_zoomAllAction->setShortcut(QKeySequence(tr("Ctrl+Alt+0"))); + addAction(m_zoomAllAction.data()); upperActions.append(m_zoomAllAction.data()); m_toolBox->addRightSideAction(m_zoomAllAction.data()); @@ -275,7 +276,7 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) m_zoomSelectionAction = new QAction(zoomSelectionIcon, tr("Zoom screen to fit current selection."), this); - m_zoomSelectionAction->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_I)); + m_zoomSelectionAction->setShortcut(QKeySequence(tr("Ctrl+Alt+i"))); addAction(m_zoomSelectionAction.data()); upperActions.append(m_zoomSelectionAction.data()); m_toolBox->addRightSideAction(m_zoomSelectionAction.data()); diff --git a/src/plugins/qmldesigner/components/formeditor/scrubbg.png b/src/plugins/qmldesigner/components/formeditor/scrubbg.png new file mode 100644 index 00000000000..ca3237983ac Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubbg.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubbg@2x.png b/src/plugins/qmldesigner/components/formeditor/scrubbg@2x.png new file mode 100644 index 00000000000..c8ff06eb3cb Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubbg@2x.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubhandle-24.png b/src/plugins/qmldesigner/components/formeditor/scrubhandle-24.png new file mode 100644 index 00000000000..60fef1546a6 Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubhandle-24.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubhandle-48.png b/src/plugins/qmldesigner/components/formeditor/scrubhandle-48.png new file mode 100644 index 00000000000..1613f758ba5 Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubhandle-48.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-24.png b/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-24.png new file mode 100644 index 00000000000..403e5d655a9 Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-24.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-48.png b/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-48.png new file mode 100644 index 00000000000..1f9c10d733f Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-48.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp new file mode 100644 index 00000000000..c4659dcd651 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. 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. +** +** 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. +** +****************************************************************************/ + +#include "seekerslider.h" +#include + +#include +#include +#include +#include + +namespace QmlDesigner { + +SeekerSlider::SeekerSlider(QWidget *parentWidget) + : QWidget(parentWidget), + m_bgIcon(QLatin1String(":/icon/layout/scrubbg.png")) +{ + m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-24.png"), QSize(24, 24)); + m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-48.png"), QSize(48, 48)); + m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-disabled-24.png"), QSize(24, 24), QIcon::Disabled); + m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-disabled-48.png"), QSize(48, 48), QIcon::Disabled); + const Utils::Icon bg({{":/icon/layout/scrubbg.png", Utils::Theme::IconsBaseColor}}); + m_bgWidth = bg.pixmap().width(); + m_bgHeight = bg.pixmap().height(); + m_handleWidth = m_bgHeight; + m_handleHeight = m_bgHeight; + int width = m_bgWidth + m_handleWidth * 2; + m_sliderHalfWidth = m_bgWidth / 2; + setMinimumWidth(width); + setMaximumWidth(width); + setProperty("panelwidget", true); + setProperty("panelwidget_singlerow", true); +} + +void SeekerSlider::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + QPainter painter(this); + { + QStyleOptionToolBar option; + option.rect = rect(); + option.state = QStyle::State_Horizontal; + style()->drawControl(QStyle::CE_ToolBar, &option, &painter, this); + } + + int x = rect().width() / 2; + int y = rect().height() / 2; + + const QPixmap bg = m_bgIcon.pixmap(QSize(m_bgWidth, m_bgHeight), isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On); + painter.drawPixmap(x - m_bgWidth / 2, y - m_bgHeight / 2, bg); + + if (m_moving) { + const QPixmap handle = m_handleIcon.pixmap(QSize(m_handleWidth, m_handleHeight), QIcon::Active, QIcon::On); + painter.drawPixmap(x - m_handleWidth / 2 + m_sliderPos, y - m_handleHeight / 2, handle); + } else { + const QPixmap handle = m_handleIcon.pixmap(QSize(m_handleWidth, m_handleHeight), isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On); + painter.drawPixmap(x - m_handleWidth / 2, y - m_handleHeight / 2, handle); + } +} + +void SeekerSlider::mousePressEvent(QMouseEvent *event) +{ + if (event->button() != Qt::LeftButton) { + QWidget::mousePressEvent(event); + return; + } + + int x = rect().width() / 2; + int y = rect().height() / 2; + auto pos = event->localPos(); + if (pos.x() >= x - m_handleWidth / 2 && pos.x() <= x + m_handleWidth / 2 + && pos.y() >= y - m_handleHeight / 2 && pos.y() <= y + m_handleHeight / 2) { + m_moving = true; + m_startPos = pos.x(); + } +} + +void SeekerSlider::mouseMoveEvent(QMouseEvent *event) +{ + if (!m_moving) { + QWidget::mouseMoveEvent(event); + return; + } + + auto pos = event->localPos(); + int delta = pos.x() - m_startPos; + m_sliderPos = qBound(-m_sliderHalfWidth, delta, m_sliderHalfWidth); + delta = m_maxPosition * m_sliderPos / m_sliderHalfWidth; + if (delta != m_position) { + m_position = delta; + Q_EMIT positionChanged(); + update(); + } +} + +void SeekerSlider::mouseReleaseEvent(QMouseEvent *event) +{ + if (!m_moving) { + QWidget::mouseReleaseEvent(event); + return; + } + + m_moving = false; + m_position = 0; + m_startPos = 0; + m_sliderPos = 0; + Q_EMIT positionChanged(); + update(); +} + +int SeekerSlider::position() const +{ + return m_position; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.h b/src/plugins/qmldesigner/components/formeditor/seekerslider.h new file mode 100644 index 00000000000..79b320d6507 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. 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. +** +** 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. +** +****************************************************************************/ +#pragma once + +#include +#include +#include + +namespace QmlDesigner { + +class SeekerSlider : public QWidget +{ + Q_OBJECT +public: + SeekerSlider(QWidget *parentWidget); + int position() const; + int maxPosition() const + { + return m_maxPosition; + } + + void setMaxPosition(int pos) + { + m_maxPosition = qMax(0, pos); + } + +Q_SIGNALS: + void positionChanged(); + +protected: + void paintEvent(QPaintEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + +private: + int m_position = 0; + int m_startPos = 0; + int m_sliderPos = 0; + int m_sliderHalfWidth = 0; + int m_maxPosition = 30; + bool m_moving = false; + int m_bgWidth; + int m_bgHeight; + int m_handleWidth; + int m_handleHeight; + QIcon m_bgIcon; + QIcon m_handleIcon; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp index c72db4c37c2..433ddc661b7 100644 --- a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp +++ b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp @@ -33,10 +33,11 @@ namespace QmlDesigner { -ToolBox::ToolBox(QWidget *parentWidget) +ToolBox::ToolBox(SeekerSlider *seeker, QWidget *parentWidget) : Utils::StyledBar(parentWidget), m_leftToolBar(new QToolBar(QLatin1String("LeftSidebar"), this)), - m_rightToolBar(new QToolBar(QLatin1String("RightSidebar"), this)) + m_rightToolBar(new QToolBar(QLatin1String("RightSidebar"), this)), + m_seeker(seeker) { m_leftToolBar->setFloatable(true); m_leftToolBar->setMovable(true); @@ -62,6 +63,8 @@ ToolBox::ToolBox(QWidget *parentWidget) m_rightToolBar->setOrientation(Qt::Horizontal); horizontalLayout->addWidget(m_leftToolBar); horizontalLayout->addWidget(stretchToolbar); + if (seeker) + horizontalLayout->addWidget(m_seeker); horizontalLayout->addWidget(m_rightToolBar); } @@ -94,4 +97,9 @@ QList ToolBox::actions() const return m_leftToolBar->actions() + m_rightToolBar->actions(); } +SeekerSlider *ToolBox::seeker() const +{ + return m_seeker; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.h b/src/plugins/qmldesigner/components/formeditor/toolbox.h index 72bd0ffb8b5..d1d5676f957 100644 --- a/src/plugins/qmldesigner/components/formeditor/toolbox.h +++ b/src/plugins/qmldesigner/components/formeditor/toolbox.h @@ -25,6 +25,7 @@ #pragma once #include +#include QT_BEGIN_NAMESPACE class QToolBar; @@ -37,16 +38,18 @@ namespace QmlDesigner { class ToolBox : public Utils::StyledBar { public: - ToolBox(QWidget *parentWidget); + ToolBox(SeekerSlider *seeker, QWidget *parentWidget); void setLeftSideActions(const QList &actions); void setRightSideActions(const QList &actions); void addLeftSideAction(QAction *action); void addRightSideAction(QAction *action); QList actions() const; + SeekerSlider *seeker() const; private: QToolBar *m_leftToolBar; QToolBar *m_rightToolBar; + SeekerSlider *m_seeker; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index 4b5e2170972..0c0268f4ca5 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -210,6 +210,11 @@ bool DesignDocument::pasteSVG() return true; } +bool DesignDocument::inFileComponentModelActive() const +{ + return !m_inFileComponentModel.isNull(); +} + QList DesignDocument::qmlParseWarnings() const { return m_rewriterView->warnings(); diff --git a/src/plugins/qmldesigner/components/integration/designdocument.h b/src/plugins/qmldesigner/components/integration/designdocument.h index ed2ef9ed112..13c258958bd 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.h +++ b/src/plugins/qmldesigner/components/integration/designdocument.h @@ -76,6 +76,7 @@ public: Model *currentModel() const; Model *documentModel() const; + bool inFileComponentModelActive() const; void contextHelp(const Core::IContext::HelpCallback &callback) const; QList qmlParseWarnings() const; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index b571cc4981d..9c856c99289 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -354,7 +354,8 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) beginResetModel(); clearSections(); - Utils::FilePath qmlFileName = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName(); + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + Utils::FilePath qmlFileName = document->fileName(); ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile(qmlFileName); QString projectName = project ? project->displayName() : ""; @@ -398,6 +399,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) itemLibImport->setImportExpanded(loadExpandedState(itemLibImport->importUrl())); } + const bool blockNewImports = document->inFileComponentModelActive(); const QList itemLibEntries = itemLibraryInfo->entries(); for (const ItemLibraryEntry &entry : itemLibEntries) { NodeMetaInfo metaInfo = model->metaInfo(entry.typeName()); @@ -429,7 +431,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) bool hasImport = model->hasImport(import, true, true); bool isImportPossible = false; if (!hasImport) - isImportPossible = model->isImportPossible(import, true, true); + isImportPossible = !blockNewImports && model->isImportPossible(import, true, true); bool isUsable = (valid && (isItem || forceVisibility)) && (entry.requiredImport().isEmpty() || hasImport); if (!blocked && (isUsable || isImportPossible)) { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index fb4de1d84b7..03547fcee77 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -400,6 +400,17 @@ void ItemLibraryWidget::setModel(Model *model) return; setItemLibraryInfo(model->metaInfo().itemLibraryInfo()); + + if (DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument()) { + const bool subCompEditMode = document->inFileComponentModelActive(); + if (m_subCompEditMode != subCompEditMode) { + m_subCompEditMode = subCompEditMode; + // Switch out of module add panel if it's active + if (m_subCompEditMode && m_stackedWidget->currentIndex() == 2) + m_stackedWidget->setCurrentIndex(0); + emit subCompEditModeChanged(); + } + } } void ItemLibraryWidget::handleTabChanged(int index) @@ -545,6 +556,11 @@ QPair ItemLibraryWidget::getAssetTypeAndData(const QString return {}; } +bool ItemLibraryWidget::subCompEditMode() const +{ + return m_subCompEditMode; +} + void ItemLibraryWidget::setFlowMode(bool b) { m_itemLibraryModel->setFlowMode(b); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index 5f631ae2434..cd00a18fc23 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -71,6 +71,8 @@ class ItemLibraryWidget : public QFrame Q_OBJECT public: + Q_PROPERTY(bool subCompEditMode READ subCompEditMode NOTIFY subCompEditModeChanged) + ItemLibraryWidget(AsynchronousImageCache &imageCache, AsynchronousImageCache &asynchronousFontImageCache, SynchronousImageCache &synchronousFontImageCache); @@ -94,6 +96,8 @@ public: inline static bool isHorizontalLayout = false; + bool subCompEditMode() const; + Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); Q_INVOKABLE void removeImport(const QString &importUrl); @@ -108,7 +112,8 @@ public: Q_INVOKABLE QSet supportedDropSuffixes(); signals: - void itemActivated(const QString& itemName); + void itemActivated(const QString &itemName); + void subCompEditModeChanged(); protected: bool eventFilter(QObject *obj, QEvent *event) override; @@ -152,6 +157,7 @@ private: bool m_updateRetry = false; QString m_filterText; QPoint m_dragStartPoint; + bool m_subCompEditMode = false; inline static int HORIZONTAL_LAYOUT_WIDTH_LIMIT = 600; }; diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 03386b38f1a..cb98389b171 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -551,20 +551,24 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, QList addedNodes; ModelNode currNode; - QSet neededImports; - for (const QString &assetPath : assetsPaths) { - QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first; - if (assetType == "application/vnd.bauhaus.libraryresource.shader") - neededImports.insert("QtQuick3D"); - else if (assetType == "application/vnd.bauhaus.libraryresource.sound") - neededImports.insert("QtMultimedia"); + // Adding required imports is skipped if we are editing in-file subcomponent + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + if (document && !document->inFileComponentModelActive()) { + QSet neededImports; + for (const QString &assetPath : assetsPaths) { + QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first; + if (assetType == "application/vnd.bauhaus.libraryresource.shader") + neededImports.insert("QtQuick3D"); + else if (assetType == "application/vnd.bauhaus.libraryresource.sound") + neededImports.insert("QtMultimedia"); - if (neededImports.size() == 2) - break; - }; + if (neededImports.size() == 2) + break; + }; - for (const QString &import : std::as_const(neededImports)) - addImport(import); + for (const QString &import : std::as_const(neededImports)) + addImport(import); + } m_view->executeInTransaction("NavigatorTreeModel::dropMimeData", [&] { for (const QString &assetPath : assetsPaths) { diff --git a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon-16px.png b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon-16px.png index 1113e8148b8..8d963e2bab5 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon-16px.png and b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon-16px.png differ diff --git a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon.png b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon.png index df4b60327e0..0cd116d13cd 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon.png and b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon.png differ diff --git a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon@2x.png b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon@2x.png index ffef790cdc0..3247384285d 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon@2x.png and b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon@2x.png differ diff --git a/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon-16px.png b/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon-16px.png index 706194278ea..430d7d250f7 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon-16px.png and b/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon-16px.png differ diff --git a/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon.png b/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon.png index dd6ecb46324..27bb59e93c1 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon.png and b/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon.png differ diff --git a/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon@2x.png b/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon@2x.png index 3fca41167ae..95b49e13b0c 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon@2x.png and b/src/plugins/qmldesigner/componentsplugin/images/grid-layouts-icon@2x.png differ diff --git a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon-16px.png b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon-16px.png index 9e17cc85bf8..1c5be822459 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon-16px.png and b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon-16px.png differ diff --git a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon.png b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon.png index a75ee209d5c..a7e654c9183 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon.png and b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon.png differ diff --git a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon@2x.png b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon@2x.png index c70f845e708..48c99f8c0e0 100644 Binary files a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon@2x.png and b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon@2x.png differ diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index 41563efd417..23014b7ce92 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -533,10 +533,20 @@ QProcessEnvironment PuppetCreator::processEnvironment() const QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick3D", "1.0"); if (m_model->hasImport(import, true, true)) environment.set("QMLDESIGNER_QUICK3D_MODE", "true"); + + import = QmlDesigner::Import::createLibraryImport("QtQuick3D.Particles3D", "1.0"); + if (m_model->hasImport(import, true, true)) + environment.set("QMLDESIGNER_QUICK3D_PARTICLES3D_MODE", "true"); + import = QmlDesigner::Import::createLibraryImport("QtCharts", "2.0"); if (m_model->hasImport(import, true, true)) environment.set("QMLDESIGNER_FORCE_QAPPLICATION", "true"); - environment.set("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS", "1"); + + bool particlemode = QmlDesigner::DesignerSettings::getValue("particleMode").toBool(); + if (!particlemode) + environment.set("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS", "1"); + else + environment.set("QT_QUICK3D_EDITOR_PARTICLE_SYSTEMS", "1"); #endif QStringList importPaths = m_model->importPaths(); diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp index fdadd059277..feeaa2fe19e 100644 --- a/src/plugins/qmldesigner/generatecmakelists.cpp +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "generatecmakelists.h" +#include "cmakegeneratordialog.h" #include #include @@ -39,6 +40,7 @@ #include #include +#include #include #include #include @@ -49,6 +51,13 @@ namespace QmlDesigner { namespace GenerateCmake { +bool operator==(const GeneratableFile &left, const GeneratableFile &right) +{ + return (left.filePath == right.filePath && left.content == right.content); +} + +QVector queuedFiles; + void generateMenuEntry() { Core::ActionContainer *buildMenu = @@ -67,19 +76,65 @@ void generateMenuEntry() void onGenerateCmakeLists() { + queuedFiles.clear(); FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory(); GenerateCmakeLists::generateMainCmake(rootDir); GenerateEntryPoints::generateMainCpp(rootDir); GenerateEntryPoints::generateMainQml(rootDir); + if (showConfirmationDialog(rootDir)) + writeQueuedFiles(); } -bool writeFile(const FilePath &filePath, const QString &fileContent) +void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles) { - QFile file(filePath.toString()); - file.open(QIODevice::WriteOnly); - QTextStream stream(&file); - stream << fileContent; - file.close(); + QtConcurrent::blockingFilter(queuedFiles, [confirmedFiles](const GeneratableFile &qf) { + return confirmedFiles.contains(qf.filePath); + }); +} + +bool showConfirmationDialog(const Utils::FilePath &rootDir) +{ + Utils::FilePaths files; + for (GeneratableFile &file: queuedFiles) + files.append(file.filePath); + + CmakeGeneratorDialog dialog(rootDir, files); + if (dialog.exec()) { + Utils::FilePaths confirmedFiles = dialog.getFilePaths(); + removeUnconfirmedQueuedFiles(confirmedFiles); + + return true; + } + + return false; +} + +bool queueFile(const FilePath &filePath, const QString &fileContent) +{ + GeneratableFile file; + file.filePath = filePath; + file.content = fileContent; + queuedFiles.append(file); + + return true; +} + +bool writeQueuedFiles() +{ + for (GeneratableFile &file: queuedFiles) + if (!writeFile(file)) + return false; + + return true; +} + +bool writeFile(const GeneratableFile &file) +{ + QFile fileHandle(file.filePath.toString()); + fileHandle.open(QIODevice::WriteOnly); + QTextStream stream(&fileHandle); + stream << file.content; + fileHandle.close(); return true; } @@ -295,7 +350,7 @@ QStringList getDirectoryTreeResources(const FilePath &dir) void createCmakeFile(const FilePath &dir, const QString &content) { FilePath filePath = dir.pathAppended(CMAKEFILENAME); - GenerateCmake::writeFile(filePath, content); + GenerateCmake::queueFile(filePath, content); } bool isFileBlacklisted(const QString &fileName) @@ -327,7 +382,7 @@ bool generateMainCpp(const FilePath &dir) templatefile.close(); FilePath filePath = dir.pathAppended(MAIN_CPPFILE_NAME); - return GenerateCmake::writeFile(filePath, content); + return GenerateCmake::queueFile(filePath, content); } const char MAIN_QMLFILE_CONTENT[] = "import %1Qml\n\n%2 {\n}\n"; @@ -343,7 +398,7 @@ bool generateMainQml(const FilePath &dir) if (const auto aspect = runConfiguration->aspect()) mainClass = FilePath::fromString(aspect->mainScript()).baseName(); - return GenerateCmake::writeFile(filePath, QString(MAIN_QMLFILE_CONTENT).arg(projectName).arg(mainClass)); + return GenerateCmake::queueFile(filePath, QString(MAIN_QMLFILE_CONTENT).arg(projectName).arg(mainClass)); } } diff --git a/src/plugins/qmldesigner/generatecmakelists.h b/src/plugins/qmldesigner/generatecmakelists.h index 18b28f88d58..d1603a1860b 100644 --- a/src/plugins/qmldesigner/generatecmakelists.h +++ b/src/plugins/qmldesigner/generatecmakelists.h @@ -31,9 +31,20 @@ namespace QmlDesigner { namespace GenerateCmake { +struct GeneratableFile { + Utils::FilePath filePath; + QString content; +}; + +bool operator==(const GeneratableFile &left, const GeneratableFile &right); + void generateMenuEntry(); void onGenerateCmakeLists(); -bool writeFile(const Utils::FilePath &filePath, const QString &fileContent); +void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles); +bool showConfirmationDialog(const Utils::FilePath &rootDir); +bool queueFile(const Utils::FilePath &filePath, const QString &fileContent); +bool writeFile(const GeneratableFile &file); +bool writeQueuedFiles(); } namespace GenerateCmakeLists { void generateMainCmake(const Utils::FilePath &rootDir); diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 937cfc8005f..2ed1daeb883 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -64,6 +64,10 @@ const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle"; const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle"; const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid"; const char EDIT3D_RESET_VIEW[] = "QmlDesigner.Editor3D.ResetView"; +const char EDIT3D_PARTICLE_MODE[] = "QmlDesigner.Editor3D.ParticleViewModeToggle"; +const char EDIT3D_PARTICLES_PLAY[] = "QmlDesigner.Editor3D.ParticlesPlay"; +const char EDIT3D_PARTICLES_RESTART[] = "QmlDesigner.Editor3D.ParticlesRestart"; + const char QML_DESIGNER_SUBFOLDER[] = "/designer/"; const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets"; diff --git a/src/plugins/qmldesigner/qmldesignericons.h b/src/plugins/qmldesigner/qmldesignericons.h index b4a97d8fae8..50e4ea1dd03 100644 --- a/src/plugins/qmldesigner/qmldesignericons.h +++ b/src/plugins/qmldesigner/qmldesignericons.h @@ -51,6 +51,16 @@ const Utils::Icon EDIT3D_LIGHT_ON({ {":/edit3d/images/edit_light_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); const Utils::Icon EDIT3D_LIGHT_OFF({ {":/edit3d/images/edit_light_off.png", Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_PARTICLE_ON({ + {":/edit3d/images/particles_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); +const Utils::Icon EDIT3D_PARTICLE_OFF({ + {":/edit3d/images/particles_off.png", Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_PARTICLE_PLAY({ + {":/edit3d/images/particles_play.png", Utils::Theme::QmlDesigner_HighlightColor}}); +const Utils::Icon EDIT3D_PARTICLE_PAUSE({ + {":/edit3d/images/particles_pause.png", Utils::Theme::QmlDesigner_HighlightColor}}); +const Utils::Icon EDIT3D_PARTICLE_RESTART({ + {":/edit3d/images/particles_restart.png", Utils::Theme::QmlDesigner_HighlightColor}}); const Utils::Icon EDIT3D_GRID_ON({ {":/edit3d/images/grid_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); const Utils::Icon EDIT3D_GRID_OFF({ diff --git a/src/plugins/qmldesigner/qmldesignerplugin.pri b/src/plugins/qmldesigner/qmldesignerplugin.pri index 4cf7edf4ba1..cc249ece07a 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.pri +++ b/src/plugins/qmldesigner/qmldesignerplugin.pri @@ -6,6 +6,7 @@ HEADERS += $$PWD/qmldesignerconstants.h \ $$PWD/editorproxy.h \ $$PWD/generateresource.h \ $$PWD/generatecmakelists.h \ + $$PWD/cmakegeneratordialog.h \ $$PWD/settingspage.h \ $$PWD/designmodecontext.h \ $$PWD/documentmanager.h \ @@ -22,6 +23,7 @@ SOURCES += $$PWD/qmldesignerplugin.cpp \ $$PWD/editorproxy.cpp \ $$PWD/generateresource.cpp \ $$PWD/generatecmakelists.cpp \ + $$PWD/cmakegeneratordialog.cpp \ $$PWD/settingspage.cpp \ $$PWD/designmodecontext.cpp \ $$PWD/documentmanager.cpp \ diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 80b54747a6e..4e20e2b52ed 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -577,6 +577,8 @@ Project { "formeditor/scaleitem.h", "formeditor/scalemanipulator.cpp", "formeditor/scalemanipulator.h", + "formeditor/seekerslider.cpp", + "formeditor/seekerslider.h", "formeditor/selectionindicator.cpp", "formeditor/selectionindicator.h", "formeditor/selectionrectangle.cpp", @@ -1009,6 +1011,8 @@ Project { "generateresource.h", "generatecmakelists.cpp", "generatecmakelists.h", + "cmakegeneratordialog.cpp", + "cmakegeneratordialog.h", "designersettings.cpp", "designersettings.h", "designmodecontext.cpp", diff --git a/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon-16px.png b/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon-16px.png index 1113e8148b8..8d963e2bab5 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon-16px.png and b/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon-16px.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon.png index df4b60327e0..0cd116d13cd 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon.png and b/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon@2x.png index 68db302e96a..3247384285d 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon@2x.png and b/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon@2x.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon-16px.png b/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon-16px.png index 099def3f5b2..67be7b474d6 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon-16px.png and b/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon-16px.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon.png index 5bb3e91da33..f8fa80970eb 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon.png and b/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon@2x.png index b2714d34b08..fc3deff8499 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon@2x.png and b/src/plugins/qmldesigner/qtquickplugin/images/flow-positioner-icon@2x.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon-16px.png b/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon-16px.png index 038a02ed86b..47b34f9d14b 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon-16px.png and b/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon-16px.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon.png index 7457fbd7e19..10d0b69a7bc 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon.png and b/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon@2x.png index af233a0df3c..4374b60e7a6 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon@2x.png and b/src/plugins/qmldesigner/qtquickplugin/images/grid-positioner-icon@2x.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon-16px.png b/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon-16px.png index 9e17cc85bf8..1c5be822459 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon-16px.png and b/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon-16px.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon.png index a75ee209d5c..a7e654c9183 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon.png and b/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon.png differ diff --git a/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon@2x.png index c70f845e708..48c99f8c0e0 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon@2x.png and b/src/plugins/qmldesigner/qtquickplugin/images/row-positioner-icon@2x.png differ diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 876fa4e1882..0dc6f5c5a18 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -347,6 +347,12 @@ QStringList QmlBuildSystem::supportedLanguages() const return {}; } +void QmlBuildSystem::setSupportedLanguages(QStringList languages) +{ + if (m_projectItem) + m_projectItem.data()->setSupportedLanguages(languages); +} + QString QmlBuildSystem::primaryLanguage() const { if (m_projectItem) @@ -354,6 +360,12 @@ QString QmlBuildSystem::primaryLanguage() const return {}; } +void QmlBuildSystem::setPrimaryLanguage(QString language) +{ + if (m_projectItem) + m_projectItem.data()->setPrimaryLanguage(language); +} + void QmlBuildSystem::refreshProjectFile() { refresh(QmlBuildSystem::ProjectFile | Files); diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index 64c0cc90ecb..4f347d07e1d 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -89,7 +89,9 @@ public: QStringList customImportPaths() const; QStringList customFileSelectors() const; QStringList supportedLanguages() const; + void setSupportedLanguages(QStringList languages); QString primaryLanguage() const; + void setPrimaryLanguage(QString language); bool forceFreeType() const; bool addFiles(const QStringList &filePaths); diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index c61a0b3fb33..c363815572f 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -204,6 +204,11 @@ int TabSettings::columnAt(const QString &text, int position) const return column; } +int TabSettings::columnAtCursorPosition(const QTextCursor &cursor) const +{ + return columnAt(cursor.block().text(), cursor.positionInBlock()); +} + int TabSettings::positionAtColumn(const QString &text, int column, int *offset, bool allowOverstep) const { int col = 0; diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h index e73d81b3651..c6446046a81 100644 --- a/src/plugins/texteditor/tabsettings.h +++ b/src/plugins/texteditor/tabsettings.h @@ -66,6 +66,7 @@ public: int lineIndentPosition(const QString &text) const; int columnAt(const QString &text, int position) const; + int columnAtCursorPosition(const QTextCursor &cursor) const; int positionAtColumn(const QString &text, int column, int *offset = nullptr, bool allowOverstep = false) const; int columnCountForText(const QString &text, int startColumn = 0) const; int indentedColumn(int column, bool doIndent = true) const; diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 59ac0bba32c..499897522db 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -768,6 +768,7 @@ public: bool m_markDragging = false; QCursor m_markDragCursor; TextMark* m_dragMark = nullptr; + QTextCursor m_dndCursor; QScopedPointer m_clipboardAssistProvider; @@ -781,6 +782,18 @@ public: bool m_scrollBarUpdateScheduled = false; const MultiTextCursor m_cursors; + struct BlockSelection + { + int blockNumber = -1; + int column = -1; + int anchorBlockNumber = -1; + int anchorColumn = -1; + }; + QList m_blockSelections; + QList generateCursorsForBlockSelection(const BlockSelection &blockSelection); + void initBlockSelection(); + void clearBlockSelection(); + void handleMoveBlockSelection(QTextCursor::MoveOperation op); class UndoCursor { @@ -1347,6 +1360,81 @@ void TextEditorWidgetPrivate::updateAutoCompleteHighlight() q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); } +QList TextEditorWidgetPrivate::generateCursorsForBlockSelection( + const BlockSelection &blockSelection) +{ + const TabSettings tabSettings = m_document->tabSettings(); + + QList result; + QTextBlock block = m_document->document()->findBlockByNumber(blockSelection.anchorBlockNumber); + QTextCursor cursor(block); + cursor.setPosition(block.position() + + tabSettings.positionAtColumn(block.text(), blockSelection.anchorColumn)); + + const bool forward = blockSelection.blockNumber > blockSelection.anchorBlockNumber + || (blockSelection.blockNumber == blockSelection.anchorBlockNumber + && blockSelection.column == blockSelection.anchorColumn); + + while (block.isValid()) { + const QString &blockText = block.text(); + cursor.setPosition(block.position() + + tabSettings.positionAtColumn(blockText, blockSelection.anchorColumn)); + cursor.setPosition(block.position() + + tabSettings.positionAtColumn(blockText, blockSelection.column), + QTextCursor::KeepAnchor); + result.append(cursor); + if (block.blockNumber() == blockSelection.blockNumber) + break; + block = forward ? block.next() : block.previous(); + } + return result; +} + +void TextEditorWidgetPrivate::initBlockSelection() +{ + const TabSettings tabSettings = m_document->tabSettings(); + for (const QTextCursor &cursor : m_cursors) { + const int column = tabSettings.columnAtCursorPosition(cursor); + QTextCursor anchor = cursor; + anchor.setPosition(anchor.anchor()); + const int anchorColumn = tabSettings.columnAtCursorPosition(anchor); + m_blockSelections.append({cursor.blockNumber(), column, anchor.blockNumber(), anchorColumn}); + } +} + +void TextEditorWidgetPrivate::clearBlockSelection() +{ + m_blockSelections.clear(); +} + +void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperation op) +{ + if (m_blockSelections.isEmpty()) + initBlockSelection(); + QList cursors; + for (BlockSelection &blockSelection : m_blockSelections) { + switch (op) { + case QTextCursor::Up: + blockSelection.blockNumber = qMax(0, blockSelection.blockNumber - 1); + break; + case QTextCursor::Down: + blockSelection.blockNumber = qMin(m_document->document()->blockCount() - 1, + blockSelection.blockNumber + 1); + break; + case QTextCursor::NextCharacter: + ++blockSelection.column; + break; + case QTextCursor::PreviousCharacter: + blockSelection.column = qMax(0, blockSelection.column - 1); + break; + default: + return; + } + cursors.append(generateCursorsForBlockSelection(blockSelection)); + } + q->setMultiTextCursor(MultiTextCursor(cursors)); +} + void TextEditorWidget::selectEncoding() { TextDocument *doc = d->m_document.data(); @@ -2180,6 +2268,8 @@ static inline bool isPrintableText(const QString &text) void TextEditorWidget::keyPressEvent(QKeyEvent *e) { + ExecuteOnDestruction eod([&]() { d->clearBlockSelection(); }); + if (!isModifier(e) && mouseHidingEnabled()) viewport()->setCursor(Qt::BlankCursor); ToolTip::hide(); @@ -2419,7 +2509,23 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) } if (ro || !isPrintableText(eventText)) { - if (!d->cursorMoveKeyEvent(e)) { + QTextCursor::MoveOperation blockSelectionOperation = QTextCursor::NoMove; + if (e->modifiers() & Qt::AltModifier && !Utils::HostOsInfo::isMacHost()) { + if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextLine)) + blockSelectionOperation = QTextCursor::Down; + else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousLine)) + blockSelectionOperation = QTextCursor::Up; + else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextChar)) + blockSelectionOperation = QTextCursor::NextCharacter; + else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousChar)) + blockSelectionOperation = QTextCursor::PreviousCharacter; + } + + if (blockSelectionOperation != QTextCursor::NoMove) { + auto doNothing = [](){}; + eod.reset(doNothing); + d->handleMoveBlockSelection(blockSelectionOperation); + } else if (!d->cursorMoveKeyEvent(e)) { QTextCursor cursor = textCursor(); bool cursorWithinSnippet = false; if (d->m_snippetOverlay->isVisible() @@ -4298,9 +4404,18 @@ void TextEditorWidgetPrivate::addCursorsPosition(PaintEventData &data, QPainter &painter, const PaintEventBlockData &blockData) const { - for (const QTextCursor &cursor : m_cursors) { - if (blockContainsCursor(blockData, cursor)) - data.cursors.append(generateCursorData(cursor.positionInBlock(), data, blockData, painter)); + if (!m_dndCursor.isNull()) { + if (blockContainsCursor(blockData, m_dndCursor)) { + data.cursors.append( + generateCursorData(m_dndCursor.positionInBlock(), data, blockData, painter)); + } + } else { + for (const QTextCursor &cursor : m_cursors) { + if (blockContainsCursor(blockData, cursor)) { + data.cursors.append( + generateCursorData(cursor.positionInBlock(), data, blockData, painter)); + } + } } } @@ -4377,13 +4492,17 @@ void TextEditorWidget::paintEvent(QPaintEvent *e) d->paintCurrentLineHighlight(data, painter); - bool drawCursor = d->m_cursorVisible - && Utils::anyOf(d->m_cursors, - [&](const QTextCursor &cursor) { - return blockContainsCursor(blockData, cursor); - }); - - bool drawCursorAsBlock = drawCursor && overwriteMode(); + bool drawCursor = false; + bool drawCursorAsBlock = false; + if (d->m_dndCursor.isNull()) { + drawCursor = d->m_cursorVisible + && Utils::anyOf(d->m_cursors, [&](const QTextCursor &cursor) { + return blockContainsCursor(blockData, cursor); + }); + drawCursorAsBlock = drawCursor && overwriteMode(); + } else { + drawCursor = blockContainsCursor(blockData, d->m_dndCursor); + } if (drawCursorAsBlock) { for (const QTextCursor &cursor : multiTextCursor()) { @@ -5120,7 +5239,7 @@ void TextEditorWidget::mouseMoveEvent(QMouseEvent *e) cursor.addCursor(c); } cursor.mergeCursors(); - if (!cursor.isNull() && cursor != multiTextCursor()) + if (!cursor.isNull()) setMultiTextCursor(cursor); } else { if (startMouseMoveCursor.has_value()) @@ -7375,24 +7494,49 @@ void TextEditorWidget::insertFromMimeData(const QMimeData *source) setMultiTextCursor(cursor); } +void TextEditorWidget::dragLeaveEvent(QDragLeaveEvent *) +{ + const QRect rect = cursorRect(d->m_dndCursor); + d->m_dndCursor = QTextCursor(); + if (!rect.isNull()) + viewport()->update(rect); +} + +void TextEditorWidget::dragMoveEvent(QDragMoveEvent *e) +{ + const QRect rect = cursorRect(d->m_dndCursor); + d->m_dndCursor = cursorForPosition(e->pos()); + if (!rect.isNull()) + viewport()->update(rect); + viewport()->update(cursorRect(d->m_dndCursor)); +} + void TextEditorWidget::dropEvent(QDropEvent *e) { + const QRect rect = cursorRect(d->m_dndCursor); + d->m_dndCursor = QTextCursor(); + if (!rect.isNull()) + viewport()->update(rect); const QMimeData *mime = e->mimeData(); + if (!canInsertFromMimeData(mime)) + return; + // Update multi text cursor before inserting data + MultiTextCursor cursor = multiTextCursor(); + cursor.beginEditBlock(); + const QTextCursor eventCursor = cursorForPosition(e->pos()); + if (e->dropAction() == Qt::MoveAction) + cursor.removeSelectedText(); + cursor.setCursors({eventCursor}); + setMultiTextCursor(cursor); + QMimeData *mimeOverwrite = nullptr; if (mime && (mime->hasText() || mime->hasHtml())) { - QMimeData *mimeOverwrite = duplicateMimeData(mime); + mimeOverwrite = duplicateMimeData(mime); mimeOverwrite->setProperty(dropProperty, true); - auto dropOverwrite = new QDropEvent(e->pos(), - e->possibleActions(), - mimeOverwrite, - e->mouseButtons(), - e->keyboardModifiers()); - QPlainTextEdit::dropEvent(dropOverwrite); - e->setAccepted(dropOverwrite->isAccepted()); - delete dropOverwrite; - delete mimeOverwrite; - } else { - QPlainTextEdit::dropEvent(e); + mime = mimeOverwrite; } + insertFromMimeData(mime); + delete mimeOverwrite; + cursor.endEditBlock(); } QMimeData *TextEditorWidget::duplicateMimeData(const QMimeData *source) diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 5811f466e43..9d71130e742 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -531,6 +531,8 @@ protected: QMimeData *createMimeDataFromSelection() const override; bool canInsertFromMimeData(const QMimeData *source) const override; void insertFromMimeData(const QMimeData *source) override; + void dragLeaveEvent(QDragLeaveEvent *e) override; + void dragMoveEvent(QDragMoveEvent *e) override; void dropEvent(QDropEvent *e) override; virtual QString plainTextFromSelection(const QTextCursor &cursor) const; diff --git a/src/share/3rdparty/package-manager/auto-setup.cmake b/src/share/3rdparty/package-manager/auto-setup.cmake index 3380596f10e..601d95f9dd0 100644 --- a/src/share/3rdparty/package-manager/auto-setup.cmake +++ b/src/share/3rdparty/package-manager/auto-setup.cmake @@ -29,6 +29,7 @@ macro(qtc_auto_setup_conan) if (conanfile_txt AND NOT QT_CREATOR_SKIP_CONAN_SETUP) option(QT_CREATOR_SKIP_CONAN_SETUP "Skip Qt Creator's conan package manager auto-setup" OFF) + set(QT_CREATOR_CONAN_BUILD_POLICY "missing" CACHE STRING "Qt Creator's conan package manager auto-setup build policy. This is used for the BUILD property of cmake_conan_run") # Get conan from Qt SDK set(qt_creator_ini "${CMAKE_CURRENT_LIST_DIR}/../QtProject/QtCreator.ini") @@ -73,6 +74,14 @@ macro(qtc_auto_setup_conan) endif() endif() + set(conanfile_build_policy_file "${CMAKE_BINARY_DIR}/conan-dependencies/conanfile.buildpolicy") + if (EXISTS "${conanfile_build_policy_file}") + file(READ "${conanfile_build_policy_file}" build_policy) + if (NOT "${build_policy}" STREQUAL "${QT_CREATOR_CONAN_BUILD_POLICY}") + set(do_conan_installation ON) + endif() + endif() + if (do_conan_installation) message(STATUS "Qt Creator: conan package manager auto-setup. " "Skip this step by setting QT_CREATOR_SKIP_CONAN_SETUP to ON.") @@ -93,7 +102,7 @@ macro(qtc_auto_setup_conan) CONANFILE \"${conanfile_txt}\" INSTALL_FOLDER \"${CMAKE_BINARY_DIR}/conan-dependencies\" GENERATORS cmake_paths json - BUILD missing + BUILD ${QT_CREATOR_CONAN_BUILD_POLICY} ENV CONAN_CMAKE_TOOLCHAIN_FILE=\"${CMAKE_BINARY_DIR}/conan-dependencies/toolchain.cmake\" )") @@ -108,6 +117,7 @@ macro(qtc_auto_setup_conan) ) if (result EQUAL 0) file(WRITE "${conanfile_timestamp_file}" "${conanfile_timestamp}") + file(WRITE "${conanfile_build_policy_file}" ${QT_CREATOR_CONAN_BUILD_POLICY}) else() message(WARNING "Qt Creator's conan package manager auto-setup failed. Consider setting " "QT_CREATOR_SKIP_CONAN_SETUP to ON and reconfigure to skip this step.") diff --git a/src/shared/qbs b/src/shared/qbs index ae937f07673..c0f2da3065f 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit ae937f07673aa95b67218e4be36a38e4438c0171 +Subproject commit c0f2da3065fd00b4d4193786865f7603e07c4515 diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 4606ee57082..60aaee4a528 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -221,6 +221,8 @@ extend_qtc_executable(qml2puppet nodeinstanceserverdispatcher.cpp nodeinstanceserverdispatcher.h capturenodeinstanceserverdispatcher.cpp capturenodeinstanceserverdispatcher.h qt5captureimagenodeinstanceserver.cpp qt5captureimagenodeinstanceserver.h + viewconfig.cpp viewconfig.h + animationdriver.cpp animationdriver.h ) extend_qtc_executable(qml2puppet diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index 83acc77ba36..626aed22255 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -16,7 +16,6 @@ QtcTool { ] } Depends { name: "Qt.quick3d-private"; required: false } - Depends { name: "Qt.quick3dparticles-private"; required: false } property bool useQuick3d: Utilities.versionCompare(Qt.core.version, "5.15") >= 0 && Qt["quick3d-private"].present property bool useParticle3d: Utilities.versionCompare(Qt.core.version, "6.2") >= 0 @@ -249,6 +248,10 @@ QtcTool { "instances/nodeinstanceserverdispatcher.h", "instances/capturenodeinstanceserverdispatcher.cpp", "instances/capturenodeinstanceserverdispatcher.h", + "instances/viewconfig.cpp", + "instances/viewconfig.h", + "instances/animationdriver.cpp", + "instances/animationdriver.h", "editor3d/generalhelper.cpp", "editor3d/mousearea3d.cpp", "editor3d/geometrybase.cpp", diff --git a/tests/auto/qml/codemodel/check/equality-checks.qml b/tests/auto/qml/codemodel/check/equality-checks.qml index 0a24cccce9a..1a2c1f7580b 100644 --- a/tests/auto/qml/codemodel/check/equality-checks.qml +++ b/tests/auto/qml/codemodel/check/equality-checks.qml @@ -71,14 +71,14 @@ Rectangle { if (s === s) {} if (s === n) {} // 325 15 17 if (s === N) {} // 325 15 17 - if (s === u) {} // 325 15 17 + if (s === u) {} if (s === b) {} // 325 15 17 if (s === o) {} // 325 15 17 if (s === k) {} if (s !== s) {} if (s !== n) {} // 325 15 17 if (s !== N) {} // 325 15 17 - if (s !== u) {} // 325 15 17 + if (s !== u) {} if (s !== b) {} // 325 15 17 if (s !== o) {} // 325 15 17 if (s !== k) {} @@ -100,19 +100,19 @@ Rectangle { if (N === o) {} // 325 15 17 if (N === k) {} - if (u === s) {} // 325 15 17 + if (u === s) {} if (u === n) {} if (u === N) {} if (u === u) {} - if (u === b) {} // 325 15 17 - if (u === o) {} // 325 15 17 + if (u === b) {} + if (u === o) {} if (u === k) {} if (b === s) {} // 325 15 17 if (b === n) {} // 325 15 17 if (b === N) {} // 325 15 17 - if (b === u) {} // 325 15 17 + if (b === u) {} if (b === b) {} if (b === o) {} // 325 15 17 if (b === k) {} @@ -120,7 +120,7 @@ Rectangle { if (o === s) {} // 325 15 17 if (o === n) {} // 325 15 17 if (o === N) {} // 325 15 17 - if (o === u) {} // 325 15 17 + if (o === u) {} if (o === b) {} // 325 15 17 if (o === o) {} // 325 15 17 if (o === k) {}