From f071a3301b844a4b5af71b5bc4fbf0e5ae8e62bf Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 26 Feb 2021 12:34:11 +0200 Subject: [PATCH 01/42] QmlDesigner: Hold import progress while application inactive Creator's global filesystem watcher doesn't trigger while the application is inactive, so changes to file system are not detected it that is the case. Hold the import process while we are waiting for filesystem update if the application is inactive. Fixes: QDS-3809 Change-Id: If55a5ce45ddf06095d7ea51c5dec4f882e83d81f Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../components/itemlibrary/itemlibraryassetimporter.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index b78dcb6eece..f434788dda7 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -664,7 +664,12 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() timer->callOnTimeout([this, timer, progressTitle, model, doc]() { if (!isCancelled()) { notifyProgress(++counter * 5, progressTitle); - if (counter == 10) { + if (counter < 10) { + // Do not proceed while application isn't active as the filesystem + // watcher qmljs uses won't trigger unless application is active + if (QApplication::applicationState() != Qt::ApplicationActive) + --counter; + } else if (counter == 10) { model->rewriterView()->textModifier()->replace(0, 0, {}); } else if (counter == 19) { try { From c1f05d58b8402ce3a96c524d960ecbf260b8d74a Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 Feb 2021 10:16:26 +0100 Subject: [PATCH 02/42] CppTools: Clear outdated "semantic parentheses" For instance, if the user types "template<", then the next operator> in the source code will be temporarily classified as the closing angle bracket for that template. Therefore, we have to clear out any previous information of that kind. Change-Id: Ib6d64415b2f6294661e2b8ec48cbaea5893d8fd0 Reviewed-by: David Schulz --- src/plugins/cpptools/semantichighlighter.cpp | 48 ++++++++++++++++++-- src/plugins/texteditor/textdocumentlayout.h | 3 ++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/plugins/cpptools/semantichighlighter.cpp b/src/plugins/cpptools/semantichighlighter.cpp index df40dce813d..d4d250166ca 100644 --- a/src/plugins/cpptools/semantichighlighter.cpp +++ b/src/plugins/cpptools/semantichighlighter.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -45,6 +46,8 @@ static Q_LOGGING_CATEGORY(log, "qtc.cpptools.semantichighlighter", QtWarningMsg) namespace CppTools { +static Utils::Id parenSource() { return "CppTools"; } + static const QList> splitRawStringLiteral(const HighlightingResult &result, const QTextBlock &startBlock) { @@ -147,6 +150,13 @@ void SemanticHighlighter::run() m_watcher->setFuture(m_highlightingRunner()); } +static Parentheses getClearedParentheses(const QTextBlock &block) +{ + return Utils::filtered(TextDocumentLayout::parentheses(block), [](const Parenthesis &p) { + return p.source != parenSource(); + }); +} + void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) { if (documentRevision() != m_revision) @@ -169,6 +179,9 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) const HighlightingResult &result = m_watcher->future().resultAt(i); if (result.kind != AngleBracketOpen && result.kind != AngleBracketClose && result.kind != TernaryIf && result.kind != TernaryElse) { + const QTextBlock block = + m_baseTextDocument->document()->findBlockByNumber(result.line - 1); + TextDocumentLayout::setParentheses(block, getClearedParentheses(block)); continue; } if (parentheses.first.isValid() && result.line - 1 > parentheses.first.blockNumber()) { @@ -177,16 +190,20 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) } if (!parentheses.first.isValid()) { parentheses.first = m_baseTextDocument->document()->findBlockByNumber(result.line - 1); - parentheses.second = TextDocumentLayout::parentheses(parentheses.first); + parentheses.second = getClearedParentheses(parentheses.first); } + Parenthesis paren; if (result.kind == AngleBracketOpen) - parentheses.second << Parenthesis(Parenthesis::Opened, '<', result.column - 1); + paren = {Parenthesis::Opened, '<', result.column - 1}; else if (result.kind == AngleBracketClose) - parentheses.second << Parenthesis(Parenthesis::Closed, '>', result.column - 1); + paren = {Parenthesis::Closed, '>', result.column - 1}; else if (result.kind == TernaryIf) - parentheses.second << Parenthesis(Parenthesis::Opened, '?', result.column - 1); + paren = {Parenthesis::Opened, '?', result.column - 1}; else if (result.kind == TernaryElse) - parentheses.second << Parenthesis(Parenthesis::Closed, ':', result.column - 1); + paren = {Parenthesis::Closed, ':', result.column - 1}; + QTC_ASSERT(paren.pos != -1, continue); + paren.source = parenSource(); + parentheses.second << paren; } if (parentheses.first.isValid()) TextDocumentLayout::setParentheses(parentheses.first, parentheses.second); @@ -202,6 +219,27 @@ void SemanticHighlighter::onHighlighterFinished() clearExtraAdditionalFormatsUntilEnd(highlighter, m_watcher->future()); } } + + // Clear out previous "semantic parentheses". + QTextBlock firstResultBlock; + QTextBlock lastResultBlock; + if (m_watcher->future().resultCount() == 0) { + firstResultBlock = lastResultBlock = m_baseTextDocument->document()->lastBlock(); + } else { + firstResultBlock = m_baseTextDocument->document()->findBlockByNumber( + m_watcher->resultAt(0).line - 1); + lastResultBlock = m_baseTextDocument->document()->findBlockByNumber( + m_watcher->future().resultAt(m_watcher->future().resultCount() - 1).line - 1); + } + for (QTextBlock currentBlock = m_baseTextDocument->document()->firstBlock(); + currentBlock != firstResultBlock; currentBlock = currentBlock.next()) { + TextDocumentLayout::setParentheses(currentBlock, getClearedParentheses(currentBlock)); + } + for (QTextBlock currentBlock = lastResultBlock.next(); currentBlock.isValid(); + currentBlock = currentBlock.next()) { + TextDocumentLayout::setParentheses(currentBlock, getClearedParentheses(currentBlock)); + } + m_watcher.reset(); } diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 7097d684c3b..776552a7efd 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -30,6 +30,8 @@ #include "textmark.h" #include "textdocument.h" +#include + #include #include @@ -48,6 +50,7 @@ struct TEXTEDITOR_EXPORT Parenthesis : pos(position), chr(c), type(t) {} int pos = -1; QChar chr; + Utils::Id source; Type type = Opened; }; From 1b9349d328ef7068f1a69545616b6b6a3db728e7 Mon Sep 17 00:00:00 2001 From: Ivan Komissarov Date: Mon, 1 Mar 2021 14:14:24 +0300 Subject: [PATCH 03/42] cmake build: Fix setting WITH_PROJECT_FILE_UPDATES This amends 13f466c. Change-Id: Ib555d8ac9598c25e9f526a21ff0324f334eb6594 Reviewed-by: Eike Ziller --- src/shared/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt index 6101e2a46c0..ec0069078d8 100644 --- a/src/shared/CMakeLists.txt +++ b/src/shared/CMakeLists.txt @@ -37,7 +37,7 @@ if (ENABLE_BUILD_QBS) set(INSTALL_PUBLIC_HEADERS OFF CACHE BOOL "") set(WITH_TESTS OFF) - set(WITH_PROJECT_FILE_UPDATES ON) + set(WITH_PROJECT_FILE_UPDATES ON CACHE BOOL "") set(QBS_INSTALL_QCH_DOCS ${WITH_DOCS} CACHE BOOL "") add_subdirectory(qbs) endif() From 131dc3df4b622458ef9f3def5aa3e7dd22a3184f Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 1 Mar 2021 11:20:49 +0100 Subject: [PATCH 04/42] CMake build: Do not install valgrind-fake and cplusplus-keywordgen These are Qt Creator developer tools Change-Id: I9bad103d9139dde2b7bed7fd2117b5e1455daa92 Reviewed-by: hjk Reviewed-by: Christian Stenger --- src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt | 1 + src/tools/valgrindfake/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt b/src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt index d1e10e73448..ec08ef50ec0 100644 --- a/src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt +++ b/src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_executable(cplusplus-keywordgen + SKIP_INSTALL DEPENDS CPlusPlus Utils SOURCES cplusplus-keywordgen.cpp PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/tools/valgrindfake/CMakeLists.txt b/src/tools/valgrindfake/CMakeLists.txt index 6c2c709c4c1..e62913674c3 100644 --- a/src/tools/valgrindfake/CMakeLists.txt +++ b/src/tools/valgrindfake/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_executable(valgrind-fake + SKIP_INSTALL DEPENDS Qt5::Network Qt5::Xml SOURCES main.cpp outputgenerator.cpp outputgenerator.h PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} From 4caca8fbfb5480ca442b87ba9a7e05808e846258 Mon Sep 17 00:00:00 2001 From: Christophe Giboudeaux Date: Sat, 19 Dec 2020 21:58:02 +0100 Subject: [PATCH 05/42] Fix a link error when building the qmldesigner plugin Fixes: QTCREATORBUG-25152 Change-Id: I36e51f3f552b3639d77342ee56e7efe5b44497e5 Reviewed-by: Eike Ziller --- src/plugins/qmldesigner/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 0d07029bf9c..d875a58f11b 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -6,7 +6,7 @@ endif() add_qtc_plugin(QmlDesigner DEPENDS QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem - Qt5::QuickWidgets Qt5::CorePrivate Sqlite + Qt5::QuickWidgets Qt5::CorePrivate Sqlite Threads::Threads DEFINES DESIGNER_CORE_LIBRARY IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\" From 88ef74d0f9fa0342be1cbf9524d5dc072b29cf45 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 1 Mar 2021 15:58:10 +0100 Subject: [PATCH 06/42] LLDB: Fixup filtering out function signatures Amends 2f67d75ca411ab5d4c95dde59e2f0d77a1f80e41. Task-number: QTCREATORBUG-25185 Task-number: QTCREATORBUG-25217 Change-Id: Ic22d67d742273f9a8944c64df4c8a0647c4157f4 Reviewed-by: hjk --- share/qtcreator/debugger/lldbbridge.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index d68c6928bf6..c6e42983b88 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -787,8 +787,6 @@ class Dumper(DumperBase): def removeTypePrefix(self, name): return re.sub('^(struct|class|union|enum|typedef) ', '', name) - __funcSignature_Regex__ = re.compile(r'^.+\(.*\)') - def lookupNativeType(self, name): #DumperBase.warn('LOOKUP TYPE NAME: %s' % name) typeobj = self.typeCache.get(name) @@ -809,7 +807,7 @@ class Dumper(DumperBase): # Note that specifying a prefix like enum or typedef or class will make the call fail to # find the type, thus the prefix is stripped. nonPrefixedName = self.canonicalTypeName(self.removeTypePrefix(name)) - if __funcSignature_Regex__.match(nonPrefixedName) is not None: + if re.match(r'^.+\(.*\)', nonPrefixedName) is not None: return lldb.SBType() typeobjlist = self.target.FindTypes(nonPrefixedName) From bf0154e50f0ca4c6ce0bc62a65ae094b901dbee0 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 1 Mar 2021 16:01:23 +0100 Subject: [PATCH 07/42] LLDB: Do not print warnings to Locals Change-Id: I552f75ebbb57c4af30582aa764fec75aa08df340 Reviewed-by: hjk --- share/qtcreator/debugger/lldbbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index c6e42983b88..ababe4a362c 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -849,7 +849,7 @@ class Dumper(DumperBase): def lookupNativeTypeInAllModules(self, name): needle = self.canonicalTypeName(name) #DumperBase.warn('NEEDLE: %s ' % needle) - self.warn('Searching for type %s across all target modules, this could be very slow' % name) + DumperBase.warn('Searching for type %s across all target modules, this could be very slow' % name) for i in range(self.target.GetNumModules()): module = self.target.GetModuleAtIndex(i) # SBModule.GetType is new somewhere after early 300.x From a1561d97e93b745c3ea3c2cb40e3e0ae58f46347 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 1 Mar 2021 13:00:26 +0100 Subject: [PATCH 08/42] Doc: Describe buttons and fields in Transition Editor Task-number: QDS-3771 Change-Id: I48b5a87f88552efdb2c1fef89d94d5f98047010a Reviewed-by: Thomas Hartmann --- .../qmldesigner-transition-editor-startup.png | Bin 0 -> 3840 bytes .../qtquick-transition-editor-settings.png | Bin 8446 -> 6812 bytes .../images/qtquick-transition-editor-view.png | Bin 8771 -> 6750 bytes doc/qtcreator/src/qtcreator-toc.qdoc | 1 + .../src/qtquick/qtquick-designer.qdoc | 2 +- doc/qtcreator/src/qtquick/qtquick-states.qdoc | 4 +- .../qtquick/qtquick-transition-editor.qdoc | 143 ++++++++++++++++++ .../qtquick/qtquick-transition-editor.qdocinc | 73 --------- .../src/qtdesignstudio-toc.qdoc | 1 + 9 files changed, 148 insertions(+), 76 deletions(-) create mode 100644 doc/qtcreator/images/qmldesigner-transition-editor-startup.png create mode 100644 doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc delete mode 100644 doc/qtcreator/src/qtquick/qtquick-transition-editor.qdocinc diff --git a/doc/qtcreator/images/qmldesigner-transition-editor-startup.png b/doc/qtcreator/images/qmldesigner-transition-editor-startup.png new file mode 100644 index 0000000000000000000000000000000000000000..d269470e0d00a4e8cc086a40c9b2d10d8b270324 GIT binary patch literal 3840 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 Ib4q9e0LyTc!~g&Q literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtquick-transition-editor-settings.png b/doc/qtcreator/images/qtquick-transition-editor-settings.png index 6fb417161277a717ccbf0e569d148c0a277df078..a0fef65a51abd1effde41c87077acc76515bc078 100644 GIT binary patch literal 6812 zcmeAS@N?(olHy`uVBq!ia0y~yVB%z8V2tKqVqjpnu&(PI1A|nur;B4q#jUq@U-!qP zCm#Q(+a$JCNc2^Ake29C&o>wDD6VRLTwQbfu1eqWLZS5^*9kW#PMc90ty=0Kc%5{4_PAmWZw!Zv-LM)%0O+~Ktn_FA6|Ni>A z_Pl%=U-y=+on_@O-|c>XZ$skYn)jDVug6~h^~bvW-JKnU$*(`JkKV2~{q)wY-u!ky z9(=tXZ(qN=M?_Og*(ZpXtm>07s!`pz~x`&v)d zqTsHInSW1}{wot(BRlKA$@~+kCrGy8nu*I!*=$CUXXc zSDb6#&J)!Rt59ZONOhXsD9yldhk@Y%8v}zm1H-fXyz}>b=(qhoKST9i07HaWUPdg> z9R`Nehj{yIzdpTo^Z+lzhLRUAUsis-8ZLdjePZIJId?u-@9x`Edw#iJY}MD^`Tz3` zr|2j;>68)xvxJ36=sfAGXC;SI?CTa^Lp0 zZTq@?>Q8R&pKbBq|Nh@z=J~(BEH86D z{&`im_nkM(H&;ooJC?HL)(ShXRh!NI=j}0hyzSY`f@R{)OAqyGJ-oE~itWnVS0k@p zmE6;wyVslh?=+^i3scQwDqj9Mvi<%=>p$1-&foR*#>@Qw$IqA7JiBwGy#CKg z?&1&Fc(! z_WxI&|L+|C|JC1(#pNuGKfbsBeN@~2$Ir>)di!51pWphXE#t?9g_l|job6p~o}YBy z`d4u(-&E(R+?Q6(n|x`ORJwk6*UHsvU-GV$kKBCrRjzE-rn_phJ+2A+Yxk|Qo+GyE zY}?N)v#|Y(c2#Zj;`E*KT6O5z zYTsbTUhjK4yvLl+-r~LduJUTYp2ig4w;`n~umANtys)**IhB={-Sn>X?G3k!EBVuZ zd0)*-owZ-NVd<+jS>^eBc{@@+_#gUkd)u?>ca^W6Esp=UUHhG`F@Ba8zKec{*F2wBWn}VQdE#ocHw@RE-cbl?bebeiE z_ifqz!;<$mzT7_PUpdPLmETkDZGC*OSa|)P!~5(0-`&ezUwxZ-f9dZF>+2HEyZism zEjTQ1^UXYW_rjuo%gYvA4{gHnSzYotWdT6lvH?MD=&5}JE ziwm7ot?w}CC>k!=cjf@^QT`2e@0b7o+?&65-@gkR%k%F2Uz+dp_q4PwbN$83_ikiXRY%qHUk~YD^X5~|uPG}SXRMaEb;;Q~FT>FP z&(rYRZ-TY%ck`GppB?V-)qIWi=PAof_KMrq=KecAi z{4Hhj;mpokd<$p2e!HdmqVK=G3*Rl6wSS}L?z{i0BR1zheR=WhpKIGDeJW?U!1npa z{`|Gw4};@vp6g#syM7@iY-@n&vh1>iNTEFw8l^iHo~={d&70u)*m~FVzpHjL+b_Pq za5rxQN~yAgkzvD;y9JBQnHUc6GBD&ZFl>3 zWnd^^W%%U}TsuQF`5uM_u3dJh$C{`(cYS2m7P- zd<>F16t64~k1f4=tXKN?uV25cr)~KBP~cGGj=x~Jn7sC=($mv)-@h+7q}amD*)IG= zpyhk@T~`aGTg)2@@;LSyK3w$sZ>*!mgaV83xXP!qOtZJ;-QBe|n&Y@opN5RMEklHb zd5hi5cLmNMB@3nQZb&@*^{%VMqJo&b6$}v<$`1eD)s(bbF(x(ses9ZTuDRY_rVM#A zdZnGzeZqGs%7~jYJYdUvz{YUr0Ph_Jo!oD4Z-4*wdVTwRFn__3$^Ldfk4fjZ%)c|i zbmzv+>F#L~hk5TX6gaEzNPP0pS1J%~d})$I|BTjG5t^CQCOgJ#*l| zfyIW;&&}n|x;gim^(C&Wa50{V6AAT_YVs)=deGm5*yXnOK;|FwN-Uv(J|e_4j;mTCx7{`A4T0E?juVJkY&u_KF<~r>>94 z*zLbEWM{aPs977|WHmh>)S$~b!RC|q7pj1vo=(e|Q0qXB{x|CL3;}`#3 zS|-MMxqEAA$m{tl&>b4O?h)GpA|+pLgoX!-A-+J z9A8Viq_vu#F3i;WQglCX<)io~WzJpFhh7x?l)rd|xA1wu6=M_2nOl@E-3i!z&FSi# zI}9ad&x3X_8dzAI;0@JnxwQ82t}^GE*_B30d!78Bt;{tyS!eL7M(eD_;r%g%6mvd-NNm7kxzD>!^>Yxd!dUziSTQt>t~ z37#*+pcB1=5tjMSES8R{c_(eoaKNb0`O6*iJO+lm3m^j82tlYUU}jjLeP@F7O4aGR zE1$f1^5o{mnAz5Gaam#A&x@3k)0K}MJ7jkzYd6CI-pHMaIw5N(Pi~!&@#4*iHFpKV z47|-cdHCLY6JPQE%n@eDo1tGc zQ}1epaDv~}@=M1$?PrI4cGL-DIKX@Q>;FZQZ}T2KuldrM>B8Tck^EF!e77V&zTVD$&iU`(S5@vz zymy;-XUv}qXHNcjI8)MwQN8k3v8z$;y3KoXOakt#%=oW%+n8sEqVD14>Ta{c*If4R ztu?R{oTpe}6+g)(B(mRc&N+8xP3~vMxgQ@s`QzWtcMkVIe7yMZ1n=Uvrb!FY6O=S1YZ5>+|tZV(#RNi!C0{?9yIyX8IcK z)KJa56QRe%PB6aRz0iJFQUAKv?uS#W-@iEGlDMd(_x|*lAN|u-y`Q!6=&l`ESspX~ zS6pyVXxMrl#zBI)~g=EWsMnY(O#n^6-OziVB;-kHxQP3tmiR%9G+ z55MO7wtLzdNsq~nXHP$xbJ6N>)uY$H4AicCU0C#fb*AK*LiVN)ec9#(hqvTKSnB7k zSXuMX$r^ZPPzLN#F9k?ZWEI*Y7X6thR2J zd-kel_m)^|2s+fd-nqiNu**NsG9>o8JMZ+z3)NR`nZ#43u%<@o?Y*`F=Y*qOqMzTl z1<1Ca{@<}Iufw{1(Y%ExPcD(2_^j>LRy&xO z#*b_7PFZC+>6FV)yJGLRZLdB)baVE~4+>d$zLb5^*AmVR3Mg>~wxXQ!^ba&!3G-g+zB{K{Fg<+2KFc@b7` z+kTjRPI0Mfop&bqcAkfuc=g;#(!xt6(=Yf;mF8+a*>Y)5p66m+bC>JSE-o#Pz~5=8Jc`oe~$h z#O`+4kr;P}p`>!RV~g|-#ybm=gz_G+HAsUv57-{EA=$gpGKG2Y$VikTS-n(b6UEg5iIEx~h# zqIuc2LpM5}8!mnRyE`#wlR>4~ zu18(%hp+rldXw|fWwl)JirH*Bp5`WE$qmwJWzLC4i8)K&6|MG?S$c4mu-?q|2lWpK z6*(sxvh7GTd)v0;-1@67ic-(mN@ht1br~MuEiP;>W8Naoke5;5d?(mi^6rt@IXl=M zvz2s6OLZF_;QjZVmjM(`4bmWAH%c?W8Ax5_9gGYYZsu7OJvnjN;kXdjhM-*t<{;hEr+5!?+p_b?L>QQ_iQ1~Q=6Iya9feI(?h5R=Q2gP+LDu5K z^K7e^En6m6`D9||xkdN>ym;B!aryD%pZj|5-QQQI>LYfM*K2FZH0dVsDn41OEe3fN z@2l@u|NHavL%|f^*=DA;-Jc$}etdZE(&?m&@^-d{w{Cywon4o;WzwG?E(-%J=7yh0 znRsVGi1+fHiWLjh=bzW_kv`PswD{r5<@07e(|IL3cZK%5#4|36yKY(8-jdgw@@eto zj|DG%R?n1*_2iXbKTAsJnf<)?`7vuxH0^X;IjyhQdBwWww)XbtCwZ&CzuWt4R(986 z^SdRN&G-L2J3X%I<+SL$neVt(=bKn*AIiKCUd%i7{cHWXW{C=>w ziutU+-^A8zbB(K)GC=`X`C?)Fv%|a#cdxqP#qoXq;nT^-`&y?fD=X{X*~+bc^2Nss zDf1-GFW<8M@#c&z&vah-M!h?^@>2btEo(M=OgphRV`-GtNl-}3|Nn9P`C(r3I|YYl z8mD*JMeHui-NF6+>-ze?x3bsg{uP!DJZ+T~e0`33VhE^;SU$(~;veC{+csU=I+0!T zgM(HrRlXyz#~?nBV@=%NUq{8`=Xgm-NMwB1>FTcA5wmKJ`qIgYTh@E02c~9~^!0x8 z->o(AXnAvx?%aoMuj=NVdGDHkZ_iGRw)HhnwU3@#I@9i=Vbq^F@qZfkUwSDR8!r0( z^ik)NS2`cpZVg^+tR=T@Z{c&DNk{+9nG~ce`>gFj>(5f>gzM{K7v|*O-gdU0v$L$3 z!#w21rqu4u9y=VDOui$qkKtPR+s@1WE5-6Og!fF?EA6uDJg?H71H6yE1g~n9{-W7= z*?<0|g2Oet55`&->PNLm&vD(f=I(=)Du;NvAGYP}e`#0a>-#5{W?#r~~S z@!EQ5=bt+h-kRTS*Eg4w?K`*V;*0w}pHIz9dE4e%q173*wm{F>JmsJ7_oprTiWc{l z&+$B#7cph|B#o?9>3r8=HV`* zaC4oNAk}v^_}DL>a@G8<`s=_GDeLkgto&62SM5xU+@1LDe#v{0Njbl#Ogj|pIVG#L zShCJf^K$;K{$G{ct(`*q-ozR06yJLSq+ZnT|8KQTCicspfIM|a;SShy`?CG#)Ol?! zXny}f?4#`6L%g8o1b%W+K~Xb@c?YQRfk}V@yhVD4;|@^a3njr8Fq?N=?gtgZjx7X8 zmxoW-1oH$QVkOcig6y^EZjpA`(I^cekGxzS!fjsAZ1HzW)QdQf#CmnhS|em&S4I61&lm%k5@YyRKd7R>z8IC9DtDE9eKf6 z_)GID$nSpk;NWxt*TZ;7k#l~XQ`{)KJb&v*L&s~_z9%l=;ePe8buOq9ieed=*{K5X3ofQ@0s%mT;S=kNCJes_C+ z=I_|pIRy<54GteHVrDqw^CEv|{(a`z+wR`{%GoZ-H%*#hfvWkP-v`;v^LB53EzCDr znqfhz`J3v5$JeZP*?rG4XK;wlyRqSG-#UJC1_$dr35yMh-u2hjWz@_W99HMuFgDmy z=N&)I^23pn-0`z_)%^U^x_<7TBkkAaEB^gyRX4il@|&~$Brn5-P14`^*6!b{zuTtp z->0XOotIAkedzqc=gXU_s&!`I=C?{`5Uh+w{KUm_`Ld* z6&7Eef6LYWi}^a^5zl$K+tVNF9fcYEPCjOPrF&ZCmq%ANvu7XUu{AG!`0>(#E5*Ot z_})oZ{ke1HsJq$w8{gkNH7K@u_F&&9o~z6^Rbf7;z5n2rueH(Xi`~J?`L6Xy_S^|D zfBBGm`h3Ydh6S&RW|$aMY}oT==i;MF`Rt5KKR)F7o^`peV8$H=hPAsB|KIYxZG8G- zck2n3&}6T?8*)Ac?=mu<92Vy~`mk|vzkTt;M^{2jG=q*_Ia(~tM_Bs12^#1Ua)`q;d7xS)p3?{$TT_-T3(BbadIBt&jWeyxKZ@x5Yz- z#fNKtrRFg-%#57=|Iape{g$fF>+aM(Jhe+(m`_*c!8ZSxnEw~kL8&naF3=9mM1s;*b3=DinK$vl= zHlH*D0|R@Br>`sf6Ao@3N#pKaeDfF>6c{{R978JRyuDi=6Y_oT`;XrhGNx?tyf)j5 z%|Lcyj_Is#VJ2Ffw{P6e@%`hNY;^DG#}`-cn$60|mH55G>DKDEWu?2D>J3r~qjSpF z-;;k+x+r!LoBZ3w3wJL`YT7ZIE&IK*qC_L-wW{2@29CC!^=Eka3=W(zIDAGt?z~M+ zi)Hb-?={a3JhZ+4{^z`dM)~(_`WYA+3MZ+qT)I^CUMT}ZgF#Aas;1^WR|bZL69SJI z7$mv`*clE4v{*1Ov?(27WH1m>g;o>d^c7_BQ9kK3n^K7jjeNI0=Z|cz`&edlpIQ`i_|F`|C{WsTF zPkMjp+s^1O{oJQZUL2ghrTm|tZN>9+70=DV?=G&ZynpFn>r<;88)9}ptM%R-{7!P? z*~!tmnxMJ!(P8M=dF+_m+7q=Z858E)R)=X9$pAH~@1FR-@~;1)eritLe6M?JFFgC)dh7eU`>zl8 z+e>Xcdv&T@rHx#rjp?mLQ;Xuh*x7|z*sl>6*z~j2>Zzq_{%7^ArUoMHw&JX3pPs69 zTJ`Zq+~cFIy9~0f@vc2DT~LC$IgSyM6n2 znMrZ7*R5st8-C+uDBPBEQfRK-*VT!R@AyAlUS79U)q7gY)wC1WkEAaw|sxwXKpV2dd&3hi+7ivp3dD>b9C*Jx|jE++}ves85+BN*Olw_ z+HaKDK7U)WE$^(XM4Oz+7rQOj!}pn<2>A0rG5WpQzj?PjbGO?T|D6>ryCtz7suM|SZ(!z_*r`|W#d5_TsXSK$#qzq-zQ zU)%GyHMSd8#H|ZI-F!v%$FBIPtLwTyx%0evc>nvuJmauJuLpWxBK2+H%;x{@D^WwbA*d#w? zig#Vm(X3t=CRd@f$+PIJc!?jQ?XjP&w{|X#d#>NN@qFU5)gPwV+tfJTt8sk(XRm9w z>oj$~75~Z(CrT`Ad&X_G{gUSY;LqIUS>5%MH};+6*n6)r{PTfD9Is>+{oCVKzm@U+ z_ltd3JM8%xoqpKy{gPyE;1sfGk$WRmY2n28QM%Ur%enUVuO9mAUQB;?GA!$q&f4v^ z3;$pLy)Vjc#}aS(xNC=Y%LlyrUH;cA~9sac12@KFjb|4qNwk=r*ghvA)kdzN{~>zw>=%e(co4?PoWOXFY9vrLdUq zY}M7J8<`9LP2RNLX2Gis`@|jlLRIYf873&S#WBlgZi-&v#8=pF^Xuf#|4X^+GcNMW z>s~!SujJ*#EvZ(&&K1VK-ns67;lZWb>+1b}%j;g$j<;B`H}d|)zuS#Uw?CbnC~oTU zKxN~z@TaTzYcKz7U0!l=XVCMe@~Q4OUNGtgIovRro_)UY;<~47g_~>=ZfuKOzw6c3 zqQq|wx2uy(TdV#tM}@qekP<7ka5M?X1d%RnVPczyYzL>TlZR+#1(;G9=IgFn_ zUtREAOtvEFgmlNVqN(iM-zN5juCV97_`{CLL8RBDGuOsZ?waYx)wb8aJes}x>y3@; zGv1zD|LT+b+h0wl;hQI=zg)ae?`_VHXxp+k+NY{h=U$ulXI0&`PqXAaBgMiT53jkW zxLoGcwuqFQC2`$OFDqH^ES~!|V#(aYLTOt+ZSOH)^j;nMQkrRdgwCdv-6{JemZV!{ zo#lVAr(WX5B;DhSr0%aRzPIh^2{|Lf>ZG zEp-=vtM~r4B%Mjo0^kRvEoGDEly?_s3_0KN5Yve{(PdPMJK} z_>qcP{e&vgc|M=n(`}C(1({Ft4W8Z#i zW5>na#kE@F?=w_s(1f28B9~LIwsN*A8Ze z1Pvz{1_ozAM14A~^7FIG9pN$z44aoMySH*lyZpJXa#;oj1)uNt?ZZ81nVLgtCX)AXUfPXD~7(sQl}aWMDXkR6#54lDK#M`tpDO>hA6;)xPyr zLfO(X($mw^%hR*7T$7kqvu} zJo#90&YRLB-h37Ul+MK&G)4@7em93%D-Q)EALj* zt8Aab$l<#n6zOfx%cc_Wzej71tRU7?cjwK4NIlOn-T4sa4UFj%j+aQtyL~wFCv~Vf*Mc7O~|)>Z`}LaJS%=~3U|!?zg=-Po>dQ7UoL&Se5=xleQ~$qmWD+) zp8B?K`ghIub+2=j-z$e?W@c9Xe!G3@tXWdO+!z{mSQI_!NINsb@X=>mTidEh=G5@2wr@w|iYJ%U$!ScJ6lP_W9?6uL^ozYxw%9 z?8S$0u9WP_aS`vY{p-CQs;-%ToG*1%@{`)X8&#fW9>4ds=>7c_Z~vJyT7L>Lzhw7n z)fK7R%}fj(&66ex>Bj5`nDpgAGk?~>Ce~kX^XpgN|MSdz(h_cQJ(snA6OP@kGZ6k? zx$s?hiOPoU)+?s#oV@#RZ=dXrxajsfldjy-+kWk}bbGmn^!Jr{_w7!GEm+^P%|5zq z&Aad~lh&`jb~*jYz26%?^_8&PXJ<$VvMPSob8e2MvZt1Y#)T$U?l0G(^H;7~mDQtr zIKO_;k?+p?b6K@+?+!_iyR%|d*!{=iZnqcs{WiPidFpcC;r6e*rdj{HWf$i%FdSH7 zYPfwyvE`>Diz3?hD|+^>+VFq1&9!Z zg^QmKyejpz_BPiXt2Z#|`0ZF2iNdqr~Vo28|JIXARlePv=$+dHG}#|kFrk573ly+5Uv z?tZ#0Ds`%g>8eFex1PQKxodUkn-xLX54P1co@dSe-~065dgj~wn{A`pwriDF-+r+^ z-9vh&>+PDwf|j?Q6=lwr`uh3UoW#>?aoHSSpNZ}?NpW!K6)l^3jkmsUo-Knru9*xuzIHCzU-@SSM?Y9F3$Y?UOTzvG<)gN zdkeoj%G#M6!_Abxv}GETnnX6fPSp)Fx~*`YgEO`ob!f8xU4lHYm_4NRdv`Z5e^ zy4{B#erOSX6dM~GwWngEm9=$pgqTxuaN}l|pVtmlUtnZd=IQMn92`73C^-1=t#dcB z9|d23aI$n#^wpy*77RYFEjtRC)UGo!EZcHqm%j`HLrV|V&hL!5d4K0%ey%}+| zq-@ver&8O_#K!8lhh~?Qr)W>u9H3Pmva)o^`s0_&Jol}cw8Sk`Wc%xtjmP6asr6I) zQG=N&xj|3)R({#(oYh(STe()Y`!CaEA0OvCdE5E1H;h5)VdIoG-l)kLlh>eP;ZcPr|pvHYEPQ`x_* zc)N7f=H5O16L?!{8gokj{nZI}-spT$u7E+!ZJOEp8wqLOLrwV z&x^aZVAIy>lFZNiq5Bl?Zm(x|3ngd_0`&Jdq582|Z zRr@Zy%H+g8wyLM+ct7Pmz56~pQu#gejIKw;zISG=?=gR~>9%*M`pT`R6nEc!_c#1u z*gxY+=WCl!$6Z`8XE|5OX3-S}_t$dW|0Vj4Cza3S&ZyBza8UxYH~>Ut6F6Pt?0HjjJaFq@Wj(gbN8K0 zD@;8-;p*LW+kS*G`t+>vT~(rYJ@dGgY|h04DqAOB&H8>T%5(LW*FOw%!<$dZ%+Yl) zQ8}iY_Kt1tx34j|+S7Pv{j}{_>)^_2R(W_&#MQjjM(?CIox8B`?X|LHMO(#SGd&f<-&%W>(dyXLhvuP;9JlFzjDJaubH z?Ci}?ct5|jx-@a!nT66kcf-AB-@0sm!rp8C*B3=g&9C&|ZDwCK7~oFvQ=vpR{AYHDp@pb$CF!X zmFnBBdTwjl_?ml$K=`9mAHMxs`;+-=mHMNbl6J?RTq^Qd*Oq*%?$3-j`+u}9`Oa>C zz0l|BadVGJR#H-K@|W^5C(lW>dKeok>%KiZ`?zwH;j4XFTW?QX>Gj-j?hQSV;a-um z7yY(kJRB***S>t&GPNhXyLRo`Qt>gVw5;sd1|0_Bx38|Q_S*Yd7*x(=#LCyMsD8iK z{MFlKOP8)(xl(hDeetW06+$T%vJ4C@y|9ALGsw%!YmYaBP~4)q>Ma%wp7-MY%&V&& z#j;Jd1qr_*fe*3p&n;Lc#iX(S?h(u>kc%5icRlp zHK~8D=vA*&dAf3iO8h&n-7=+<)*e_nX_3vD--~uX z$-D3}%rk5H?YniqU(XQZO*r83eEF*vz08~qH(xR^NND|2ymw1)yJ`ISCzbNIz=@mp z-c#nzhR?zt8Jr)!A9)=THAgYM(|cX+r1D2Tb5pcC$`cvftn3+8SU{EFl`B_T_Be)z zPZ!gVTXXK*If-ek3(%-9LhAn?Pt2V^#l-h=`k9Wh$OBVK7Vpl!^4v1M@nUZ&pYImVzc;S_``2$;drUSl z_j2`Sb+@Yw61>l~C;U+Rv-$GmNpAaj^0!8n{{2;YcSm7zlNOVK(7AAhjjC6UY+JHK zCHI$p{MGV(e-}-f>|9g7F>AS>jQz9U+k@kKQX5y79jlXXP_&3|{IMxQr&ILN{NH!d zP1DcGn9j3Z9lbrTcdz3$wa~ojr>?ELJZtOgEype{I}@^#ae zpYF#?l)|fwr-(E8FwR-;P;=Dwh_2Y_1J^x0J%3$3E*~BrKR+veHSgNS-^Nq#U0mk< z@3?MziNO)y!`<*4?igGh_^yo@-C2cqH^_{*KRnwQu$RIrY~*$6`Iay{=zAmu$5$d#cLI?%jQN<&NFnnswys zl&zjqg-!3UOEi2I^@tI++vqzf@7uRm|9(H$vaa4Ib#6{zd3pJd_pekvx8BmS0z?te3P|d^Yktdu0C9GRx_& zw=l@M#`|s2IRZr)Zo1~wU z`THsUpX!(LugrU#)7dwht-Ms}vwMr*?&iO7kz0e+x9NYjeGw47Vc905sS8VN-`Ff$ z{`a)hE7gzQjKShilP6s%c-A9V`9<*Qvu9f7=H^Z1U!Awe1iifYRO@`KDsQe@g45aT zQfR>A}bd==9lr97^Lit zdRvyV>e9=-Y33KwE_}30$a+}AD%5}UVL?S!R+iJf1*=zkcZ=(XrKdli@j7mIS?+~& z!|!)qT$43UZw*aQxy``w&aM3Vih73D&!Q4{GoD|lSOPARJy)(=nY{kZCji?89bs^cM{su;NL?`v-32;cLnn6}&9s z88;s>Ig);Up6uyoj4p!DwG-spF2g6<(4#~3>Xj=;cC#@s2ryQGh7+|O{XTN}(xpX_ z>_`UCo z?%6+!e^2={yZ+LenZ~N!s`pe?&HCN%n&-WE%+7tKbgk_hh2`pe3>~v(zU0^1S-5}F zYdpFH%+wb1E$Qz7_>p<%_RAODF1*X_|CIhcJYRp`-yhfi2gh40#v9BsmJ@jS5tQ}= zpT3PaW@q>O*?;rDSEsLkas2$=1()}wYR~(>Yuf6|;q8u!au3T|EEp7a9W%6%*;S(Z zcg~kr^X9)OIk3;~|6l(lXH27BuU9Vat=sUqaH;2{d)NB6|8rUXw3>NCRbTnybMs%X z-&gK5oqcV!>-u*;rDb!wzrOyEXd%lmfkQ1NDf(IcmFJh&y>N;CU|V_L{mF~j*7Db@ z|Nro<{q38X_s_5PzkYE@y^U{lc>Klw?e7BjE}2^YbIqlxi@#c5E~$BK9;)v-Gy7}v z`t^Z_zxTZ^%8Bn>9|uZ7od=8=x6i0lDJ@%Nd!z18x6!33*M1iNeZl*_>2&Y@Yt_5$ zmQVftKXz_a%=s`o?Oe+Rzy7i>Ia3<7xcy7c)B7)PHn!ahYddbNs3->uq}jn@(bMk- zr{9{s)#UMvd$Lwf-rnA>{^0*S$J6Im{JCj7Y1*m}$3?5c@?Rf_FZY^jf4#h1cJ_=5 zd~roLb{yql5D1;e`E$MF|C*qv&v$jB1UHl%HQ&>(+JEKSynEi&F+Wf5J%2X#SLEIA z*Y>{-c^0+zL&z?htO=iQ?!Vf3&T>=Mhg~0k=nH*0!pLyZRPgZ2N%w4j)z)7BZ2R|X z|M%?G^$(-jx1KDXf6a5!bKj};_P*8ox5u~dQ}f&(_VoJwDO-Ggz1v=zv9)~i_pG`F z;`-aYo3Bm1^3%As{JD0O`Lp#dg7W&HL3D*Iv6|;SC66j&cYfMkF+FLDWwD*=+Mf&S zem5^o%ysvdVGu|aF6zIja=5^XL4mR2*KhTA!nf5p{pw}3==_X0YJIq-8Z$nAAg>G^?Q5s zuPbx>U9aq(<7G2x*X~_Yw>&w2_3pQ_8@G)&@-hg77XJ%gn6^y+(wQ&kkM0&xzVo8O z+x*tOYg2FS=dO+h6~oRS6ZLV<+M^dHpz<1dg8$e51D}^V-rQWE!oa}5;OXk;vd$@? F2>^D6R)_!q diff --git a/doc/qtcreator/images/qtquick-transition-editor-view.png b/doc/qtcreator/images/qtquick-transition-editor-view.png index 406b540135f66dca4ba7832fa6ebb88b9547de14..3d747783af568d784e0f0adf0f3e32b6b34432ab 100644 GIT binary patch literal 6750 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 Ys~N61r_8v-z`(%Z>FVdQ&MBb@0M8qVNdN!< literal 8771 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 @@ -208,6 +210,4 @@ \if defined(qtcreator) \include qtquick-states-scxml.qdocinc scxml state machines \endif - - \include qtquick-transition-editor.qdocinc transition editor */ diff --git a/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc b/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc new file mode 100644 index 00000000000..12ade5c3c4b --- /dev/null +++ b/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \page qtquick-transition-editor.html + \previouspage qtquick-states-view.html + \nextpage qtquick-timeline-view.html + + \title Transition Editor + + To make movement between states smooth, you can use + \uicontrol {Transition Editor} to animate the changes between + states. + + First, you need to \l{Adding States}{add states} in the \l States view + and \l{Specifying Component Properties}{edit some properties} that can be + animated, such as colors or numbers, in the \l Properties view. For example, + you can animate the changes in the position of a component. + + \image qtquick-transition-editor-view.png "Transition Editor view" + + In \uicontrol {Transition Editor}, you can set the start frame, end + frame, and duration for the transition of each property. You can also + set an \l{Editing Easing Curves}{easing curve} for each animation and + the maximum duration of the whole transition. + + \section1 Zooming in Transition Editor + + Use the slider on the toolbar to set the zooming level in + \uicontrol {Transition Editor}. Select the \inlineimage zoom_small.png + and \inlineimage zoom_big.png + buttons to zoom out of or into the view. + + \section1 Summary of Transition Editor Toolbar Actions + + \table + \header + \li Button/Field + \li Action + \li Read More + \row + \li \inlineimage animation.png + \li Opens \uicontrol {Transition Settings} dialog for editing + transition settings. + \li \l{Specifying Transition Settings} + \row + \li Transition ID + \li Displays a list of transitions that you can open in + \uicontrol {Transition Editor}. + \li \l{Animating Transitions Between States} + \row + \li \inlineimage curve_editor.png + \li Opens \uicontrol {Easing Curve Editor} for attaching an easing + curve to the selected transition. + \li \l{Editing Easing Curves} + \row + \li \inlineimage zoom_small.png + \li \uicontrol {Zoom Out} (\key Ctrl+-): zooms out of the view. + \li \l{Zooming in Transition Editor} + \row + \li Slider + \li Sets the zooming level. + \li \l{Zooming in Transition Editor} + \row + \li \inlineimage zoom_big.png + \li \uicontrol {Zoom In} (\key Ctrl++): zooms into the view. + \li \l{Zooming in Transition Editor} + \row + \li Maximum Duration + \li Specifies the maximum duration of the transition. + \li + \endtable + + \section1 Animating Transitions Between States + + To animate transitions: + + \list 1 + \li Select \uicontrol View > \uicontrol Views > + \uicontrol {Transition Editor}. + \image qmldesigner-transition-editor-startup.png "Empty Transition Editor" + \li Select the \inlineimage plus.png + (\uicontrol {Add Transition}) button to add a transition. This + works only if you have added at least one state and modified at + least one property in it. + \image qtquick-transition-editor-view.png "Transition Editor view" + \li Move the blue bar next to the component or property name to set + the start and end frame of the animation of the property. Pull its + left and right edges to set the duration of the animation. + \li To attach an \l{Editing Easing Curves}{easing curve} to the + selected transition, select the \inlineimage curve_editor.png + (\uicontrol {Easing Curve Editor (C)}) button. + \endlist + + \section1 Specifying Transition Settings + + To modify transition settings, select the \inlineimage animation.png + (\uicontrol {Transition Settings (S)}) button in + \uicontrol {Transition Editor}. + + \image qtquick-transition-editor-settings.png "Transition settings" + + To add transitions: + + \list 1 + \li Select the \inlineimage plus.png + (\uicontrol {Add Transition}) button. + \li In the \uicontrol {Transition ID} field, enter an ID for the + transition. + \li In the \uicontrol From field, select the state to transition from. + \li In the \uicontrol To field, select the state to transition to. + \endlist + + To remove the current transition, select the \inlineimage minus.png + (\uicontrol {Remove Transition}) button. + + \if defined(qtcreator) + For an example of animating transitions between states, see + \l {Creating a Qt Quick Application}. + \endif +*/ diff --git a/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdocinc b/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdocinc deleted file mode 100644 index ff20d84e22a..00000000000 --- a/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdocinc +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Creator documentation. -** -** 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 Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** -****************************************************************************/ - -/*! -//! [transition editor] - - \section1 Animating Transitions Between States - - To make movement between states smooth, you can use - \uicontrol {Transition Editor} to animate the changes between - states. First, you need to \l{Creating States}{add states} in - the \uicontrol States view and \l{Specifying Component Properties} - {edit some properties} that can be animated, such as colors or - numbers, in the \uicontrol Properties view. For example, you - can animate the changes in the position of an object. - - In \uicontrol {Transition Editor}, you can set the start frame, end - frame, and duration for the transition of each property. You can also - set an easing curve for each transition. - - Use the slider on the menu bar to the zooming level in the view. - - To add transitions: - - \list 1 - \li Select \uicontrol View > \uicontrol Views > - \uicontrol {Transition Editor} to display the view. - \li Select the \inlineimage plus.png - (\uicontrol {Add Transition}) button to add a transition. This - works only if you have added at least one state and modified at - least one property in it. - \image qtquick-transition-editor-view.png "Transition Editor view" - \li Move the blue bar next to the component or property name to set - the start and end frame of the animation of the property. Pull its - left and right edges to set the duration of the animation. - \li To attach an easing curve to a transition, select - \inlineimage curve_editor.png - (\uicontrol {Easing Curve Editor (C)}) on the toolbar. For more - information, see \l{Editing Easing Curves}. - \li To modify transition settings, select the \inlineimage animation.png - (\uicontrol {Transition Settings (S)}) button on the toolbar. - \image qtquick-transition-editor-settings.png "Transition settings" - \endlist - - \if defined(qtcreator) - For an example of animating transitions between states, see - \l {Creating a Qt Quick Application}. - \endif - -//! [transition editor] -*/ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index a0965261c6f..3fad0989341 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -62,6 +62,7 @@ \li \l{Library} \li \l{Navigator} \li \l{Properties} + \li \l{Transition Editor} \endlist \li \l{Managing Workspaces} \li \l{Managing Sessions} From ee07604f79b9eb16e12a444b19fcfb5f62373c22 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 1 Mar 2021 16:32:41 +0200 Subject: [PATCH 09/42] QmlDesigner: Sort previously flow-tagged imports to top of the list Allow prioritizing certain modules in the possible imports list. The obsolete "showTagsForImports" metainfo property was repurposed for this to keep compatibility with old metainfos. A new metainfo property "priorityImports" does the same thing. Fixes: QDS-3801 Change-Id: I96aafcb8e6d10117e29203f55f60e73843b3aae5 Reviewed-by: Thomas Hartmann Reviewed-by: Mahmoud Badri --- .../itemlibrary/itemlibraryaddimportmodel.cpp | 29 +++++++++++++++---- .../itemlibrary/itemlibraryaddimportmodel.h | 3 ++ .../itemlibrary/itemlibrarywidget.cpp | 13 +++++++++ .../itemlibrary/itemlibrarywidget.h | 1 + .../components/itemlibrary/qml/addimport.qml | 9 ++++-- .../designercore/include/itemlibraryinfo.h | 5 ++++ .../designercore/metainfo/itemlibraryinfo.cpp | 16 ++++++++++ .../designercore/metainfo/metainforeader.cpp | 6 ++-- 8 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp index 377662b032b..4c89d339353 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp @@ -40,6 +40,7 @@ ItemLibraryAddImportModel::ItemLibraryAddImportModel(QObject *parent) // add role names m_roleNames.insert(Qt::UserRole + 1, "importUrl"); m_roleNames.insert(Qt::UserRole + 2, "importVisible"); + m_roleNames.insert(Qt::UserRole + 3, "isSeparator"); } ItemLibraryAddImportModel::~ItemLibraryAddImportModel() @@ -63,7 +64,10 @@ QVariant ItemLibraryAddImportModel::data(const QModelIndex &index, int role) con return importUrl; if (m_roleNames[role] == "importVisible") - return m_searchText.isEmpty() || m_importFilterList.contains(importUrl); + return m_searchText.isEmpty() || importUrl.isEmpty() || m_importFilterList.contains(importUrl); + + if (m_roleNames[role] == "isSeparator") + return importUrl.isEmpty(); qWarning() << Q_FUNC_INFO << "invalid role requested"; @@ -83,9 +87,9 @@ void ItemLibraryAddImportModel::update(const QList &possibleImports) const DesignerMcuManager &mcuManager = DesignerMcuManager::instance(); const bool isQtForMCUs = mcuManager.isMCUProject(); QList filteredImports; - const QStringList mcuAllowedList = mcuManager.allowedImports(); - const QStringList mcuBannedList = mcuManager.bannedImports(); if (isQtForMCUs) { + const QStringList mcuAllowedList = mcuManager.allowedImports(); + const QStringList mcuBannedList = mcuManager.bannedImports(); filteredImports = Utils::filtered(possibleImports, [&](const Import &import) { return (mcuAllowedList.contains(import.url()) @@ -96,7 +100,7 @@ void ItemLibraryAddImportModel::update(const QList &possibleImports) filteredImports = possibleImports; } - Utils::sort(filteredImports, [](const Import &firstImport, const Import &secondImport) { + Utils::sort(filteredImports, [this](const Import &firstImport, const Import &secondImport) { if (firstImport.url() == secondImport.url()) return firstImport.toString() < secondImport.toString(); @@ -106,6 +110,10 @@ void ItemLibraryAddImportModel::update(const QList &possibleImports) if (secondImport.url() == "QtQuick") return false; + const bool firstPriority = m_priorityImports.contains(firstImport.url()); + if (firstPriority != m_priorityImports.contains(secondImport.url())) + return firstPriority; + if (firstImport.isLibraryImport() && secondImport.isFileImport()) return false; @@ -122,9 +130,15 @@ void ItemLibraryAddImportModel::update(const QList &possibleImports) }); // create import sections + bool previousIsPriority = false; for (const Import &import : std::as_const(filteredImports)) { - if (import.isLibraryImport()) + if (import.isLibraryImport()) { + bool currentIsPriority = m_priorityImports.contains(import.url()); + if (previousIsPriority && !currentIsPriority) + m_importList.append(Import::empty()); // empty import acts as a separator m_importList.append(import); + previousIsPriority = currentIsPriority; + } } endResetModel(); @@ -153,4 +167,9 @@ Import ItemLibraryAddImportModel::getImportAt(int index) const return m_importList.at(index); } +void ItemLibraryAddImportModel::setPriorityImports(const QSet &priorityImports) +{ + m_priorityImports = priorityImports; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h index bab5ecf73c5..3ed6b3f3b5e 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h @@ -50,11 +50,14 @@ public: void setSearchText(const QString &searchText); Import getImportAt(int index) const; + void setPriorityImports(const QSet &priorityImports); + private: QString m_searchText; QList m_importList; QSet m_importFilterList; QHash m_roleNames; + QSet m_priorityImports; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 9fdef025483..1eb8813bda0 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -229,11 +229,16 @@ void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo) if (m_itemLibraryInfo) { disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged, this, &ItemLibraryWidget::delayedUpdateModel); + disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::priorityImportsChanged, + this, &ItemLibraryWidget::handlePriorityImportsChanged); } m_itemLibraryInfo = itemLibraryInfo; if (itemLibraryInfo) { connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged, this, &ItemLibraryWidget::delayedUpdateModel); + connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::priorityImportsChanged, + this, &ItemLibraryWidget::handlePriorityImportsChanged); + m_itemLibraryAddImportModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); } delayedUpdateModel(); } @@ -365,6 +370,14 @@ void ItemLibraryWidget::updateSearch() } } +void ItemLibraryWidget::handlePriorityImportsChanged() +{ + if (!m_itemLibraryInfo.isNull()) { + m_itemLibraryAddImportModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); + m_itemLibraryAddImportModel->update(m_model->possibleImports()); + } +} + void ItemLibraryWidget::setResourcePath(const QString &resourcePath) { if (m_resourcesView->model() == m_resourcesFileSystemModel.data()) { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index 5bde054fc9b..66d95d0cd4b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -102,6 +102,7 @@ private: void addResources(const QStringList &files); void importDroppedFiles(const QList &files); void updateSearch(); + void handlePriorityImportsChanged(); QTimer m_compressionTimer; QSize m_itemIconSize; diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml index 60712394abd..e73623bd7ee 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml @@ -57,9 +57,11 @@ Column { delegate: Rectangle { width: listView.width - height: 25 - color: mouseArea.containsMouse ? Qt.lighter(Theme.qmlDesignerButtonColor(), 1.3) - : Theme.qmlDesignerButtonColor() + height: isSeparator ? 4 : 25 + color: isSeparator ? Theme.color(Theme.BackgroundColorNormal) + : mouseArea.containsMouse + ? Qt.lighter(Theme.qmlDesignerButtonColor(), 1.3) + : Theme.qmlDesignerButtonColor() visible: importVisible Text { @@ -77,6 +79,7 @@ Column { anchors.fill: parent hoverEnabled: true onClicked: addImport(index) + enabled: !isSeparator } } } diff --git a/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h b/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h index e7d0c3e2927..b31b3d916c3 100644 --- a/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h +++ b/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h @@ -29,6 +29,7 @@ #include "propertycontainer.h" #include +#include #include namespace QmlDesigner { @@ -108,11 +109,14 @@ public: void clearEntries(); QStringList blacklistImports() const; + QSet priorityImports() const; void addBlacklistImports(const QStringList &list); + void addPriorityImports(const QSet &set); signals: void entriesChanged(); + void priorityImportsChanged(); private: // functions ItemLibraryInfo(QObject *parent = nullptr); @@ -123,6 +127,7 @@ private: // variables QPointer m_baseInfo; QStringList m_blacklistImports; + QSet m_priorityImports; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp index 4fc5e7c0887..5bdb5530f60 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp @@ -344,11 +344,27 @@ QStringList ItemLibraryInfo::blacklistImports() const return list; } +QSet ItemLibraryInfo::priorityImports() const +{ + QSet set = m_priorityImports; + if (m_baseInfo) + set.unite(m_baseInfo->m_priorityImports); + return set; +} + void ItemLibraryInfo::addBlacklistImports(const QStringList &list) { m_blacklistImports.append(list); } +void ItemLibraryInfo::addPriorityImports(const QSet &set) +{ + if (!set.isEmpty()) { + m_priorityImports.unite(set); + emit priorityImportsChanged(); + } +} + void ItemLibraryInfo::setBaseInfo(ItemLibraryInfo *baseInfo) { m_baseInfo = baseInfo; diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp index 83d826ad9ac..7c4e1130725 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp @@ -230,8 +230,10 @@ void MetaInfoReader::readImportsProperty(const QString &name, const QVariant &va if (name == "blacklistImports" && !values.isEmpty()) { m_metaInfo.itemLibraryInfo()->addBlacklistImports(values); - } else if (name == "showTagsForImports" && !values.isEmpty()) { - // Flow tags removed, but keeping this for now to avoid errors parsing old metadata files + } else if ((name == "priorityImports" || name == "showTagsForImports") && !values.isEmpty()) { + // Flow tags are no longer shown, but the old property is still supported for prioritizing + // imports to keep compatibility with old metainfo files. + m_metaInfo.itemLibraryInfo()->addPriorityImports(values.toSet()); } else { addError(tr("Unknown property for Imports %1").arg(name), currentSourceLocation()); setParserState(Error); From 720dbf557f2395fb98533092a65724f598168eab Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 1 Mar 2021 14:57:56 +0100 Subject: [PATCH 10/42] PluginManager: Remove plugin crash check at shutdown The check was mostly introduced for the case where Qt Creator crashes at startup. For example if the user enabled or installed a plugin that makes Qt Creator crash at startup, they get the chance to temporarily disable that plugin because otherwise they cannot even access the plugin dialog. For shutdown that makes less sense, and is irritating for development. Change-Id: I7267d74f4bb2d302c946a7488cc645ca4c7f864b Reviewed-by: David Schulz --- src/libs/extensionsystem/pluginmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index adfe161ba8e..ab83ed210b4 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -1474,7 +1474,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt return; std::unique_ptr lockFile; - if (enableCrashCheck) + if (enableCrashCheck && destState < PluginSpec::Stopped) lockFile.reset(new LockFile(this, spec)); switch (destState) { From 3c3e9a97fd4a8c6113a696024efe30b99a6d4bde Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 1 Mar 2021 18:48:24 +0100 Subject: [PATCH 11/42] CMakeProjectManager: Write cmake configuration into qtcsettings.cmake The parameters sent to CMake are also saved as qtcsettings.cmake, this allows Android Multi-ABI CMake projects apply the settings for all ABIs. This was part of 196b0da08add8b36a118481314bd10a3a3dd78e0 Task-number: QTCREATORBUG-25183 Change-Id: I6d4f210247d5377cab855a1a051cf7aa815192c7 Reviewed-by: BogDan Vatra --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 24 +++++++++++++++++++ .../cmakeprojectmanager/cmakebuildsystem.h | 3 ++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index abd515f1a0f..e62893b5a97 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -56,6 +56,7 @@ #include #include +#include #include #include @@ -372,6 +373,27 @@ QString CMakeBuildSystem::reparseParametersString(int reparseFlags) return result.trimmed(); } +void CMakeBuildSystem::writeConfigurationIntoBuildDirectory() +{ + const Utils::MacroExpander *expander = cmakeBuildConfiguration()->macroExpander(); + const FilePath buildDir = workDirectory(m_parameters); + QTC_ASSERT(buildDir.exists(), return ); + + const FilePath settingsFile = buildDir.pathAppended("qtcsettings.cmake"); + + QByteArray contents; + contents.append("# This file is managed by Qt Creator, do not edit!\n\n"); + contents.append( + transform(cmakeBuildConfiguration()->configurationChanges(), + [expander](const CMakeConfigItem &item) { return item.toCMakeSetLine(expander); }) + .join('\n') + .toUtf8()); + + QFile file(settingsFile.toString()); + QTC_ASSERT(file.open(QFile::WriteOnly | QFile::Truncate), return ); + file.write(contents); +} + void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters ¶meters, const int reparseParameters) { @@ -405,6 +427,8 @@ void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters &pa m_reader.setParameters(m_parameters); + writeConfigurationIntoBuildDirectory(); + if (reparseParameters & REPARSE_URGENT) { qCDebug(cmakeBuildSystemLog) << "calling requestReparse"; requestParse(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 283990ed7be..997fdc7fdc0 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -29,7 +29,6 @@ #include "cmakebuildtarget.h" #include "cmakeprojectnodes.h" #include "fileapireader.h" -#include "utils/macroexpander.h" #include @@ -155,6 +154,8 @@ private: void runCTest(); + void writeConfigurationIntoBuildDirectory(); + ProjectExplorer::TreeScanner m_treeScanner; QHash m_mimeBinaryCache; QList m_allFiles; From fe540e88284959fa75ea6c56984f0955bf2ee1da Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 1 Mar 2021 19:27:08 +0100 Subject: [PATCH 12/42] CMakeProjectManager: Remove isCmakeChanged state Since CMake's file-api cache is the only source of truth for CMake configuration, there is no need to keep track of such a state. Qt Creator will issue -D= -U command line parameters for CMake, which will update the file api json files. Change-Id: I08e7041a95422549502eb7961f96570225e942fa Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakebuildconfiguration.cpp | 3 +-- src/plugins/cmakeprojectmanager/configmodel.cpp | 8 -------- src/plugins/cmakeprojectmanager/configmodel.h | 2 -- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index d4d2f0d2675..3f40ca0b92d 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -526,8 +526,7 @@ void CMakeBuildSettingsWidget::updateButtonState() }); m_resetButton->setEnabled(m_configModel->hasChanges() && !isParsing); - m_reconfigureButton->setEnabled((!configChanges.isEmpty() || m_configModel->hasCMakeChanges()) - && !isParsing); + m_reconfigureButton->setEnabled(!configChanges.isEmpty() && !isParsing); m_buildConfiguration->setConfigurationChanges(configChanges); } diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index f30adb22394..b3bf8533c6d 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -123,11 +123,6 @@ bool ConfigModel::hasChanges() const }); } -bool ConfigModel::hasCMakeChanges() const -{ - return Utils::contains(m_configuration, [](const InternalDataItem &i) { return i.isCMakeChanged; }); -} - bool ConfigModel::canForceTo(const QModelIndex &idx, const ConfigModel::DataItem::Type type) const { if (idx.model() != const_cast(this) || idx.column() != 1) @@ -264,7 +259,6 @@ void ConfigModel::setConfiguration(const QList &c // merge old/new entry: InternalDataItem item(*newIt); item.newValue = (newIt->value != oldIt->newValue) ? oldIt->newValue : QString(); - item.isCMakeChanged = (oldIt->value != newIt->value); item.isUserChanged = !item.newValue.isEmpty() && (item.newValue != item.value); result << item; ++newIt; @@ -390,7 +384,6 @@ QVariant ConfigModelTreeItem::data(int column, int role) const return toolTip(); case Qt::FontRole: { QFont font; - font.setItalic(dataItem->isCMakeChanged); font.setBold(dataItem->isUserNew); font.setStrikeOut((!dataItem->inCMakeCache && !dataItem->isUserNew) || dataItem->isUnset); return font; @@ -414,7 +407,6 @@ QVariant ConfigModelTreeItem::data(int column, int role) const case Qt::FontRole: { QFont font; font.setBold((dataItem->isUserChanged || dataItem->isUserNew) && !dataItem->isUnset); - font.setItalic(dataItem->isCMakeChanged); font.setStrikeOut((!dataItem->inCMakeCache && !dataItem->isUserNew) || dataItem->isUnset); return font; } diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 70f0fa3960a..8fb621c2ea0 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -144,7 +144,6 @@ public: void resetAllChanges(); bool hasChanges() const; - bool hasCMakeChanges() const; bool canForceTo(const QModelIndex &idx, const DataItem::Type type) const; void forceTo(const QModelIndex &idx, const DataItem::Type type); @@ -168,7 +167,6 @@ private: bool isUserChanged = false; bool isUserNew = false; - bool isCMakeChanged = false; QString newValue; QString kitValue; }; From 70764080fd2d936fd61728bf6d4c0786d97440ad Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 24 Feb 2021 21:00:19 +0100 Subject: [PATCH 13/42] StudioWelcome: Allow to download examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If46eb9bc2f24a6c1057fd3db34596c4619ddcb7b Reviewed-by: Henning Gründl Reviewed-by: Alessandro Portale --- src/plugins/studiowelcome/CMakeLists.txt | 1 + src/plugins/studiowelcome/examplecheckout.cpp | 347 ++++++++++++++++++ src/plugins/studiowelcome/examplecheckout.h | 163 ++++++++ .../qml/downloaddialog/ArcItem.qml | 249 +++++++++++++ .../downloaddialog/CircularIndicator.ui.qml | 129 +++++++ .../qml/downloaddialog/CoolProgressBar.ui.qml | 193 ++++++++++ .../qml/downloaddialog/DialogButton.qml | 91 +++++ .../qml/downloaddialog/DialogLabel.qml | 37 ++ .../qml/downloaddialog/MinMaxMapper.qml | 54 +++ .../qml/downloaddialog/RangeMapper.qml | 48 +++ .../downloaddialog/downloaddialog.qmlproject | 47 +++ .../studiowelcome/qml/downloaddialog/main.qml | 312 ++++++++++++++++ .../ExampleCheckout/FileDownloader.qml | 59 +++ .../ExampleCheckout/FileExtractor.qml | 41 +++ .../mockData/ExampleCheckout/qmldir | 2 + .../qml/welcomepage/ExamplesModel.qml | 9 + .../qml/welcomepage/HoverOverDesaturate.qml | 21 ++ .../qml/welcomepage/ProjectsGrid.qml | 1 + .../qml/welcomepage/images/downloadCloud.svg | 29 ++ .../images/highendivi_thumbnail.png | Bin 0 -> 48336 bytes .../studiowelcome/qml/welcomepage/main.qml | 2 +- src/plugins/studiowelcome/studiowelcome.pro | 4 +- src/plugins/studiowelcome/studiowelcome.qbs | 2 + .../studiowelcome/studiowelcomeplugin.cpp | 25 +- 24 files changed, 1862 insertions(+), 4 deletions(-) create mode 100644 src/plugins/studiowelcome/examplecheckout.cpp create mode 100644 src/plugins/studiowelcome/examplecheckout.h create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/main.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml create mode 100644 src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir create mode 100644 src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg create mode 100644 src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt index b04caf2a6d4..fe7f34ca7f4 100644 --- a/src/plugins/studiowelcome/CMakeLists.txt +++ b/src/plugins/studiowelcome/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(StudioWelcome DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/" SOURCES studiowelcomeplugin.cpp studiowelcomeplugin.h + examplecheckout.cpp examplecheckout.h studiowelcome_global.h studiowelcome.qrc "${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc" diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp new file mode 100644 index 00000000000..c7180155d85 --- /dev/null +++ b/src/plugins/studiowelcome/examplecheckout.cpp @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** 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 "examplecheckout.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ExampleCheckout::ExampleCheckout(QObject *) {} + +void ExampleCheckout::checkoutExample(const QUrl &url) +{ + FileDownloader::registerQmlType(); + static bool once = []() { + FileDownloader::registerQmlType(); + FileExtractor::registerQmlType(); + return true; + }(); + + QTC_ASSERT(once, ;); + + m_dialog.reset(new QDialog(Core::ICore::dialogParent())); + m_dialog->setModal(true); + m_dialog->setFixedSize(620, 300); + QHBoxLayout *layout = new QHBoxLayout(m_dialog.get()); + layout->setContentsMargins(2, 2, 2, 2); + + auto widget = new QQuickWidget(m_dialog.get()); + + layout->addWidget(widget); + widget->engine()->addImportPath("qrc:/studiofonts"); + + widget->engine()->addImportPath(Core::ICore::resourcePath() + + "/qmldesigner/propertyEditorQmlSources/imports"); + + widget->setSource(QUrl("qrc:/qml/downloaddialog/main.qml")); + + m_dialog->setWindowFlag(Qt::Tool, true); + widget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + rootObject = widget->rootObject(); + + QTC_ASSERT(rootObject, qWarning() << "QML error"; return ); + + rootObject->setProperty("url", url); + + m_dialog->show(); + + rootObject = widget->rootObject(); + + connect(rootObject, SIGNAL(canceled()), this, SLOT(handleCancel())); + connect(rootObject, SIGNAL(accepted()), this, SLOT(handleAccepted())); +} + +QString ExampleCheckout::extractionFolder() const +{ + return m_extrationFolder; +} + +ExampleCheckout::~ExampleCheckout() {} + +void ExampleCheckout::handleCancel() +{ + m_dialog->close(); + m_dialog.release()->deleteLater(); + deleteLater(); +} + +void ExampleCheckout::handleAccepted() +{ + QQmlProperty property(rootObject, "path"); + m_extrationFolder = property.read().toString(); + m_dialog->close(); + emit finishedSucessfully(); + m_dialog.release()->deleteLater(); + deleteLater(); +} + +void FileDownloader::registerQmlType() +{ + qmlRegisterType("ExampleCheckout", 1, 0, "FileDownloader"); +} + +FileDownloader::FileDownloader(QObject *parent) + : QObject(parent) +{} + +FileDownloader::~FileDownloader() +{ + m_tempFile.remove(); +} + +void FileDownloader::start() +{ + m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip"); + + m_tempFile.open(QIODevice::WriteOnly); + + auto request = QNetworkRequest(m_url); + request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true); + QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(request); + + QNetworkReply::connect(reply, &QNetworkReply::readyRead, [this, reply]() { + m_tempFile.write(reply->readAll()); + }); + + QNetworkReply::connect(reply, + &QNetworkReply::downloadProgress, + this, + [this](qint64 current, qint64 max) { + if (max == 0) + return; + + m_progress = current * 100 / max; + emit progressChanged(); + }); + + QNetworkReply::connect(reply, &QNetworkReply::finished, [this, reply]() { + if (reply->error()) { + m_tempFile.remove(); + if (m_url != reply->url()) { + m_url = reply->url(); + start(); + } else { + emit downloadFailed(); + } + } else { + m_tempFile.flush(); + m_tempFile.close(); + m_finished = true; + emit finishedChanged(); + } + }); +} + +void FileDownloader::setUrl(const QUrl &url) +{ + m_url = url; + + emit nameChanged(); +} + +QUrl FileDownloader::url() const +{ + return m_url; +} + +bool FileDownloader::finished() const +{ + return m_finished; +} + +bool FileDownloader::error() const +{ + return m_error; +} + +QString FileDownloader::name() const +{ + const QFileInfo fileInfo(m_url.path()); + return fileInfo.baseName(); +} + +QString FileDownloader::completeBaseName() const +{ + const QFileInfo fileInfo(m_url.path()); + return fileInfo.completeBaseName(); +} + +int FileDownloader::progress() const +{ + return m_progress; +} + +QString FileDownloader::tempFile() const +{ + return QFileInfo(m_tempFile).canonicalFilePath(); +} + +FileExtractor::FileExtractor(QObject *parent) + : QObject(parent) +{ + if (Core::DocumentManager::instance()) + m_targetPath = Core::DocumentManager::projectsDirectory(); + else + m_targetPath = Utils::FilePath::fromString("/temp/"); + + m_timer.setInterval(500); + m_timer.setSingleShot(false); +} + +FileExtractor::~FileExtractor() {} + +void FileExtractor::registerQmlType() +{ + qmlRegisterType("ExampleCheckout", 1, 0, "FileExtractor"); +} + +QString FileExtractor::targetPath() const +{ + return m_targetPath.toUserOutput(); +} + +void FileExtractor::browse() +{ + const QString path = QFileDialog::getExistingDirectory(Core::ICore::dialogParent(), + (tr("Choose Directory")), + m_targetPath.toString()); + + if (!path.isEmpty()) + m_targetPath = Utils::FilePath::fromString(path); + + emit targetPathChanged(); + emit targetFolderExistsChanged(); +} + +void FileExtractor::setSourceFile(QString &sourceFilePath) +{ + m_sourceFile = Utils::FilePath::fromString(sourceFilePath); + emit targetFolderExistsChanged(); +} + +void FileExtractor::setArchiveName(QString &filePath) +{ + m_archiveName = filePath; +} + +const QString FileExtractor::detailedText() +{ + return m_detailedText; +} + +bool FileExtractor::finished() const +{ + return m_finished; +} + +QString FileExtractor::currentFile() const +{ + return m_currentFile; +} + +QString FileExtractor::size() const +{ + return m_size; +} + +QString FileExtractor::count() const +{ + return m_count; +} + +bool FileExtractor::targetFolderExists() const +{ + const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName; + return QFileInfo(targetFolder).exists(); +} + +QString FileExtractor::archiveName() const +{ + return m_archiveName; +} + +QString FileExtractor::sourceFile() const +{ + return m_sourceFile.toString(); +} + +void FileExtractor::extract() +{ + Utils::Archive *archive = Utils::Archive::unarchive(m_sourceFile, m_targetPath); + archive->setParent(this); + QTC_ASSERT(archive, return ); + + m_timer.start(); + const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName; + qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable(); + + QTimer::connect(&m_timer, &QTimer::timeout, [this, bytesBefore, targetFolder]() { + static QHash hash; + QDirIterator it(targetFolder, {"*.*"}, QDir::Files, QDirIterator::Subdirectories); + + int count = 0; + while (it.hasNext()) { + if (!hash.contains(it.fileName())) { + m_currentFile = it.fileName(); + hash.insert(m_currentFile, 0); + emit currentFileChanged(); + } + it.next(); + count++; + } + + m_size = QString::number(bytesBefore + - QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable()); + + m_count = QString::number(count); + emit sizeChanged(); + }); + + QObject::connect(archive, &Utils::Archive::outputReceived, this, [this](const QString &output) { + m_detailedText += output; + emit detailedTextChanged(); + }); + + QObject::connect(archive, &Utils::Archive::finished, [this](bool ret) { + m_finished = ret; + m_timer.stop(); + emit finishedChanged(); + QTC_ASSERT(ret, ;); + }); +} diff --git a/src/plugins/studiowelcome/examplecheckout.h b/src/plugins/studiowelcome/examplecheckout.h new file mode 100644 index 00000000000..0038d7f2c0f --- /dev/null +++ b/src/plugins/studiowelcome/examplecheckout.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** 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 +#include + +#include + +QT_BEGIN_NAMESPACE +class QDialog; +QT_END_NAMESPACE + +class ExampleCheckout : public QObject +{ + Q_OBJECT +public: + explicit ExampleCheckout(QObject *parent = nullptr); + + Q_INVOKABLE void checkoutExample(const QUrl &url); + + QString extractionFolder() const; + + ~ExampleCheckout(); + +public slots: + void handleCancel(); + void handleAccepted(); + +signals: + void finishedSucessfully(); + +private: + std::unique_ptr m_dialog; + QObject *rootObject = nullptr; + QString m_extrationFolder; +}; + +class FileExtractor : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString targetPath READ targetPath NOTIFY targetPathChanged) + Q_PROPERTY(QString archiveName READ archiveName WRITE setArchiveName) + Q_PROPERTY(QString detailedText READ detailedText NOTIFY detailedTextChanged) + Q_PROPERTY(QString currentFile READ currentFile NOTIFY currentFileChanged) + Q_PROPERTY(QString size READ size NOTIFY sizeChanged) + Q_PROPERTY(QString count READ count NOTIFY sizeChanged) + Q_PROPERTY(QString sourceFile READ sourceFile WRITE setSourceFile) + Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged) + Q_PROPERTY(bool targetFolderExists READ targetFolderExists NOTIFY targetFolderExistsChanged) + +public: + explicit FileExtractor(QObject *parent = nullptr); + ~FileExtractor(); + + static void registerQmlType(); + + QString targetPath() const; + void setSourceFile(QString &sourceFilePath); + void setArchiveName(QString &filePath); + const QString detailedText(); + bool finished() const; + QString currentFile() const; + QString size() const; + QString count() const; + bool targetFolderExists() const; + + QString sourceFile() const; + QString archiveName() const; + + Q_INVOKABLE void browse(); + Q_INVOKABLE void extract(); + +signals: + void targetPathChanged(); + void detailedTextChanged(); + void finishedChanged(); + void currentFileChanged(); + void sizeChanged(); + void targetFolderExistsChanged(); + +private: + Utils::FilePath m_targetPath; + Utils::FilePath m_sourceFile; + QString m_detailedText; + bool m_finished = false; + QTimer m_timer; + QString m_currentFile; + QString m_size; + QString m_count; + QString m_archiveName; +}; + +class FileDownloader : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QUrl url READ url WRITE setUrl) + Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged) + Q_PROPERTY(bool error READ error NOTIFY errorChanged) + Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(QString completeBaseName READ completeBaseName NOTIFY nameChanged) + Q_PROPERTY(int progress READ progress NOTIFY progressChanged) + Q_PROPERTY(QString tempFile READ tempFile NOTIFY finishedChanged) + +public: + explicit FileDownloader(QObject *parent = nullptr); + + ~FileDownloader(); + + void setUrl(const QUrl &url); + QUrl url() const; + bool finished() const; + bool error() const; + static void registerQmlType(); + QString name() const; + QString completeBaseName() const; + int progress() const; + QString tempFile() const; + + Q_INVOKABLE void start(); + +signals: + void finishedChanged(); + void errorChanged(); + void nameChanged(); + void progressChanged(); + void downloadFailed(); + +private: + QUrl m_url; + bool m_finished = false; + bool m_error = false; + int m_progress = 0; + QFile m_tempFile; +}; diff --git a/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml b/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml new file mode 100644 index 00000000000..fa38d302dba --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Shapes 1.0 + +Shape { + id: root + + implicitWidth: 100 + implicitHeight: 100 + + property alias gradient: path.fillGradient + property alias strokeStyle: path.strokeStyle + property alias strokeWidth: path.strokeWidth + property alias strokeColor: path.strokeColor + property alias dashPattern: path.dashPattern + property alias joinStyle: path.joinStyle + property alias fillColor: path.fillColor + property alias capStyle: path.capStyle + property alias dashOffset: path.dashOffset + + property real begin: 0 + property real end: 90 + + property real arcWidth: 10 + + property real arcWidthBegin: arcWidth + property real arcWidthEnd: arcWidth + + property real radiusInnerAdjust: 0 + property real radiusOuterAdjust: 0 + + property real alpha: clamp(sortedEnd() - sortedBegin(),0, 359.9) + + layer.enabled: antialiasing + layer.smooth: antialiasing + layer.textureSize: Qt.size(width * 2, height * 2) + property bool outlineArc: false + + property bool round: false + + property bool roundEnd: round + property bool roundBegin: round + + function clamp(num, min, max) { + return num <= min ? min : num >= max ? max : num; + } + + function myCos(angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + return Math.cos(angleInRadians) + } + + function mySin(angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + return Math.sin(angleInRadians) + } + + function polarToCartesianX(centerX, centerY, radius, angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + var x = centerX + radius * Math.cos(angleInRadians) + return x + } + + function polarToCartesianY(centerX, centerY, radius, angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + var y = centerY + radius * Math.sin(angleInRadians); + return y + } + + function calc() + { + path.__xRadius = root.width / 2 - root.strokeWidth / 2 + path.__yRadius = root.height / 2 - root.strokeWidth / 2 + + path.__Xcenter = root.width / 2 + path.__Ycenter = root.height / 2 + + path.startX = root.polarToCartesianX(path.__Xcenter, path.__Ycenter, path.__xRadius, root.sortedBegin() - 90) + root.__beginOff * myCos(root.sortedBegin() + 90) + path.startY = root.polarToCartesianY(path.__Xcenter, path.__Ycenter, path.__yRadius, root.sortedBegin() - 90) + root.__beginOff * mySin(root.sortedBegin() + 90) + + arc1.x = root.polarToCartesianX(path.__Xcenter, path.__Ycenter, path.__xRadius, root.sortedEnd() - 90) + root.__endOff * myCos(root.sortedEnd() + 90) + arc1.y = root.polarToCartesianY(path.__Xcenter, path.__Ycenter, path.__yRadius, root.sortedEnd() - 90) + root.__endOff * mySin(root.sortedEnd() + 90) + + arc1.radiusX = path.__xRadius - root.__endOff / 2 -root.__beginOff / 2 + root.radiusOuterAdjust + arc1.radiusY = path.__yRadius - root.__endOff / 2 -root.__beginOff / 2 + root.radiusOuterAdjust + + arc1.useLargeArc = root.alpha > 180 + } + + function sortedBegin() + { + return(Math.min(root.begin, root.end)) + } + + function sortedEnd() + { + return(Math.max(root.begin, root.end)) + } + + + onWidthChanged: calc() + onHeightChanged: calc() + onBeginChanged: calc() + onEndChanged: calc() + onAlphaChanged: calc() + + ShapePath { + id: path + + property real __xRadius + property real __yRadius + + property real __Xcenter + property real __Ycenter + + strokeColor: "red" + strokeWidth: 4 + capStyle: ShapePath.FlatCap + } + + property real __beginOff: { + + if (root.arcWidthEnd > root.arcWidthBegin) + return (root.arcWidthEnd - root.arcWidthBegin) / 2 + + return 0; + } + + property real __endOff: { + + if (root.arcWidthBegin > root.arcWidthEnd) + return (root.arcWidthBegin - root.arcWidthEnd) / 2 + + return 0; + } + + property real __startP: root.arcWidthBegin + __beginOff + property real __endP: root.arcWidthEnd + __endOff + + Item { + id: shapes + PathArc { + id: arc1 + property bool add: true + } + + PathLine { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + property bool add: !root.roundEnd && (root.outlineArc && root.alpha < 359.8) + + } + + PathArc { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + radiusX: root.arcWidthEnd /2 + radiusY: root.arcWidthEnd /2 + property bool add: root.roundEnd && (root.outlineArc && root.alpha < 359.8) + } + + PathMove { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + property bool add: root.outlineArc && root.alpha > 359.7 + } + + PathArc { + id: arc2 + useLargeArc: arc1.useLargeArc + + radiusX: path.__xRadius - root.arcWidthBegin + root.__beginOff / 2 + root.__endOff / 2 + root.radiusInnerAdjust + radiusY:path.__yRadius - root.arcWidthBegin + root.__beginOff / 2 + root.__endOff / 2 + root.radiusInnerAdjust + + x: path.startX + root.arcWidthBegin * myCos(root.sortedBegin()) + y: path.startY + root.arcWidthBegin * mySin(root.sortedBegin()) + + direction: PathArc.Counterclockwise + + property bool add: root.outlineArc + } + + + PathLine { + x: path.startX + y: path.startY + property bool add: !root.roundBegin && root.outlineArc && root.alpha < 359.8 + + } + + PathArc { + x: path.startX + y: path.startY + radiusX: root.arcWidthEnd /2 + radiusY: root.arcWidthEnd /2 + property bool add: root.roundBegin && root.outlineArc && root.alpha < 359.8 + } + + PathMove { + x: path.startX + y: path.startY + property bool add: root.outlineArc && root.alpha == 360 + } + } + + function invalidatePaths() { + if (!root.__completed) + return + + for (var i = 0; i < shapes.resources.length; i++) { + var s = shapes.resources[i]; + if (s.add) + path.pathElements.push(s) + } + + } + + property bool __completed: false + + Component.onCompleted: { + root.__completed = true + invalidatePaths() + calc() + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml b/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml new file mode 100644 index 00000000000..15b2e265527 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + + +import QtQuick 2.12 +import QtQuick.Timeline 1.0 + +Rectangle { + id: rectangle + width: 60 + height: 60 + color: "#8c8c8c" + radius: 50 + property alias inputMax: rangeMapper.inputMax + property alias inputMin: rangeMapper.inputMin + property alias value: minMaxMapper.input + + ArcItem { + id: arc + x: -1 + y: -1 + width: 62 + height: 62 + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + end: rangeMapper.value + antialiasing: true + strokeWidth: 8 + strokeColor: "#ffffff" + capStyle: 32 + fillColor: "#00000000" + } + + RangeMapper { + id: rangeMapper + outputMax: 358 + input: minMaxMapper.value + } + + MinMaxMapper { + id: minMaxMapper + input: 95 + max: rangeMapper.inputMax + min: rangeMapper.inputMin + } + + Rectangle { + id: rectangle1 + width: 60 + height: 60 + color: "#ffffff" + radius: 40 + anchors.verticalCenter: parent.verticalCenter + scale: 1 + anchors.horizontalCenter: parent.horizontalCenter + } + + Timeline { + id: timeline + currentFrame: rangeMapper.value + enabled: true + endFrame: 360 + startFrame: 0 + + KeyframeGroup { + target: rectangle1 + property: "opacity" + Keyframe { + frame: 0 + value: 0 + } + + Keyframe { + frame: 360 + value: 1 + } + } + + KeyframeGroup { + target: rectangle1 + property: "scale" + Keyframe { + frame: 360 + value: 1 + } + + Keyframe { + frame: 0 + value: 0.1 + } + } + + KeyframeGroup { + target: arc + property: "opacity" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 1 + frame: 40 + } + } + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml b/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml new file mode 100644 index 00000000000..b48880406c5 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + + +import QtQuick 2.12 +import QtQuick.Timeline 1.0 + +Item { + id: coolProgressBar + width: 605 + height: 16 + property alias value: timeline.currentFrame + clip: true + + Timeline { + id: timeline + enabled: true + endFrame: 100 + startFrame: 0 + + KeyframeGroup { + target: rectangle + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 150 + frame: 25 + } + + Keyframe { + value: 300 + frame: 50 + } + + Keyframe { + value: 450 + frame: 75 + } + + Keyframe { + value: 600 + frame: 100 + } + } + + KeyframeGroup { + target: rectangle1 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 300 + frame: 25 + } + + Keyframe { + value: 450 + frame: 50 + } + + Keyframe { + value: 600 + frame: 75 + } + } + + KeyframeGroup { + target: rectangle2 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 450 + frame: 25 + } + + Keyframe { + value: 600 + frame: 50 + } + } + + KeyframeGroup { + target: rectangle3 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 600 + frame: 25 + } + } + + KeyframeGroup { + target: content + property: "opacity" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 1 + frame: 50 + } + } + } + + Item { + id: content + anchors.fill: parent + + Rectangle { + id: rectangle + y: 0 + width: 80 + height: 16 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle1 + y: 0 + width: 80 + height: 16 + opacity: 0.6 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle2 + y: 0 + width: 80 + height: 16 + opacity: 0.4 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle3 + y: 0 + width: 80 + height: 16 + opacity: 0.2 + color: "#ffffff" + radius: 12 + } + } +} + +/*##^## +Designer { + D{i:0;height:16;width:590}D{i:1} +} +##^##*/ diff --git a/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml b/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml new file mode 100644 index 00000000000..d21acdde359 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Templates 2.1 as T + +T.Button { + id: control + + implicitWidth: Math.max(buttonBackground ? buttonBackground.implicitWidth : 0, + textItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(buttonBackground ? buttonBackground.implicitHeight : 0, + textItem.implicitHeight + topPadding + bottomPadding) + leftPadding: 4 + rightPadding: 4 + + text: "My Button" + + property color defaultColor: "#b9b9ba" + property color checkedColor: "#ffffff" + + background: buttonBackground + Rectangle { + id: buttonBackground + color: control.defaultColor + implicitWidth: 100 + implicitHeight: 40 + opacity: enabled ? 1 : 0.3 + radius: 0 + border.width: 1 + } + + contentItem: textItem + Text { + id: textItem + text: control.text + + opacity: enabled ? 1.0 : 0.3 + color: "#bababa" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + states: [ + State { + name: "normal" + when: !control.down && !control.checked + PropertyChanges { + target: buttonBackground + color: "#2d2e30" + } + }, + State { + name: "down" + when: control.down || control.checked + PropertyChanges { + target: textItem + color: control.checkedColor + } + + PropertyChanges { + target: buttonBackground + color: "#545456" + border.color: "#70a2f5" + border.width: 2 + } + } + ] +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml b/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml new file mode 100644 index 00000000000..c5dac79a504 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.15 + +import ExampleCheckout 1.0 +import QtQuick.Layouts 1.11 + +import StudioFonts 1.0 + +Text { + font.family: StudioFonts.titilliumWeb_light + color: root.textColor +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml b/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml new file mode 100644 index 00000000000..451c098f9e3 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick Designer Components. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 + +QtObject { + id: object + + + property real input + + property bool minClipped: object.input < object.min + property bool maxClipped: object.input > object.max + property bool outOfRage: object.maxClipped ||object.minClipped + + property real value: { + if (object.maxClipped) + return object.max + + if (object.minClipped) + return object.min + + return object.input + } + + property real min: 0 + property real max: 100 +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml b/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml new file mode 100644 index 00000000000..dc75325b084 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick Designer Components. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 + +QtObject { + id: object + + + property real input + + property real value: { + var slope = (object.outputMax - object.outputMin) / (object.inputMax - object.inputMin) + return object.outputMin + slope * (object.input - object.inputMin) + } + + property real inputMin: 0 + property real inputMax: 100 + property real outputMin: 0 + property real outputMax: 100 + +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject b/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject new file mode 100644 index 00000000000..880c6022a96 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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. +** +****************************************************************************/ + +import QmlProject 1.1 + +Project { + mainFile: "main.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } + /* List of plugin directories passed to QML runtime */ + importPaths: [ "mockData", "../../../../share/3rdparty/studiofonts", "../../../../../share/qtcreator/qmldesigner/propertyEditorQmlSources/imports" ] + + Environment { + QT_AUTO_SCREEN_SCALE_FACTOR: "1" + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/main.qml b/src/plugins/studiowelcome/qml/downloaddialog/main.qml new file mode 100644 index 00000000000..cb7f62a68c4 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/main.qml @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.15 + +import ExampleCheckout 1.0 +import QtQuick.Layouts 1.11 + +import StudioFonts 1.0 + +Rectangle { + id: root + property alias url: downloader.url + property string path: fileExtractor.targetPath + width: 620 + height: 300 + + color: "#2d2e30" + + property color textColor: "#b9b9ba" + + signal canceled + signal accepted + + StackLayout { + id: stackLayout + anchors.fill: parent + currentIndex: 0 + + FileExtractor { + id: fileExtractor + sourceFile: downloader.tempFile + archiveName: downloader.completeBaseName + } + + FileDownloader { + id: downloader + //onNameChanged: start() + onFinishedChanged: { + button.enabled = downloader.finished + if (!downloader.finished) + stackLayout.currentIndex = 3 + } + + onDownloadFailed: stackLayout.currentIndex = 3 + } + + Item { + id: download + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: button + x: 532 + y: 432 + text: qsTr("Continue") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + enabled: false + onClicked: stackLayout.currentIndex = 1 + } + + CoolProgressBar { + id: coolProgressBar + width: 605 + anchors.top: parent.top + value: downloader.progress + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 69 + } + + DialogLabel { + x: 201 + text: "Downloading Example " + downloader.completeBaseName + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + + DialogButton { + id: downloadbutton + y: 420 + enabled: !button.enabled + text: qsTr("Start Download") + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + onClicked: { + downloadbutton.enabled = false + downloader.start() + } + } + + CircularIndicator { + id: circularIndicator + x: 304 + anchors.top: parent.top + anchors.horizontalCenterOffset: 0 + value: downloader.progress + anchors.topMargin: 120 + anchors.horizontalCenter: parent.horizontalCenter + } + + } + + Item { + id: destiationfolder + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: nextPageDestination + x: 532 + y: 432 + text: qsTr("Continue") + anchors.right: parent.right + anchors.bottom: parent.bottom + enabled: !fileExtractor.targetFolderExists + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: { + stackLayout.currentIndex = 2 + fileExtractor.extract() + } + } + + RowLayout { + y: 114 + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: 104 + anchors.leftMargin: 67 + + TextField { + id: textField + text: fileExtractor.targetPath + Layout.fillWidth: true + font.family: StudioFonts.titilliumWeb_light + wrapMode: Text.WordWrap + selectByMouse: true + readOnly: true + } + + DialogButton { + id: browse + text: qsTr("Browse") + onClicked: fileExtractor.browse() + } + } + + DialogLabel { + id: label + y: 436 + text: qsTr("Folder ") + downloader.completeBaseName + (" already exists") + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + visible: !nextPageDestination.enabled + } + + DialogButton { + id: button5 + x: 400 + y: 420 + text: qsTr("Cancel") + anchors.right: nextPageDestination.left + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: root.canceled() + } + + DialogLabel { + text: "Choose installation folder" + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + x: 8 + } + } + + Item { + id: extraction + Layout.fillHeight: true + Layout.fillWidth: true + + + DialogButton { + id: done + x: 532 + y: 432 + text: qsTr("Open") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + enabled: fileExtractor.finished + onClicked: root.accepted() + } + + + DialogLabel { + id: text2 + text: fileExtractor.count + " files " + (fileExtractor.size / 1024 / 1024).toFixed(2) + " MB "+ fileExtractor.currentFile + anchors.left: parent.left + anchors.bottom: parent.bottom + font.pixelSize: 12 + wrapMode: Text.WrapAnywhere + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + } + + + DialogButton { + id: details + x: 8 + text: qsTr("Details") + anchors.top: parent.top + anchors.topMargin: 66 + anchors.horizontalCenter: parent.horizontalCenter + checkable: true + } + + + DialogLabel { + x: 8 + text: "Extracting Example " + downloader.completeBaseName + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + + Flickable { + visible: details.checked + clip: true + anchors.bottomMargin: 60 + anchors.rightMargin: 20 + anchors.leftMargin: 20 + anchors.topMargin: 120 + anchors.fill: parent + id: flickable + interactive: false + + DialogLabel { + onHeightChanged: flickable.contentY = text1.implicitHeight - flickable.height + id: text1 + + text: fileExtractor.detailedText + + font.pixelSize: 12 + wrapMode: Text.WrapAnywhere + + width: flickable.width + } + } + } + + Item { + id: failed + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: finish + x: 532 + y: 432 + text: qsTr("Finish") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: root.canceled() + } + + DialogLabel { + x: 8 + text: qsTr("Download failed") + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + } + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml new file mode 100644 index 00000000000..bf873ec5631 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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. +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + id: root + + signal downloadFailed + + property bool finished: false + + property bool url + + property int progress: 55 + Behavior on progress { PropertyAnimation { + duration: 2000 + } + } + + function start() { + timer.start() + root.progress = 100 + + } + + property Timer timer: Timer { + interval: 2000 + repeat: false + onTriggered: { + root.finished + root.progress = 1000 + finished = true + } + + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml new file mode 100644 index 00000000000..d3ee8e20f6b --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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. +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + signal finished + + property string sourceFile: "SomeExample.zip" + property string archiveName: "SomeExample" + + property string targetPath: "/extract/here" + + property string detailedText: "Start" + + "\n1 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\n2 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\n3 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\nend" +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir new file mode 100644 index 00000000000..7c2bb0bcd49 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir @@ -0,0 +1,2 @@ +FileDownloader 1.0 FileDownloader.qml +FileExtractor 1.0 FileExtractor.qml diff --git a/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml b/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml index 5e9fe07985c..3f33f0205e8 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml @@ -74,4 +74,13 @@ ListModel { thumbnail: "images/washingmachinedemo_thumbnail.png" displayName: "Washing Machine" } + + ListElement { + projectName: "highendivisystem" + qmlFileName: "Screen01.ui.qml" + thumbnail: "images/highendivi_thumbnail.png" + displayName: "Highend IVI System" + url: "https://download.qt.io/learning/examples/qtdesignstudio/highendivisystem.zip" + showDownload: true + } } diff --git a/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml b/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml index e160a1f70e3..a7d7501a52c 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml @@ -35,6 +35,8 @@ Item { property alias imageSource: image.source property alias labelText: label.text + property alias downloadIcon: downloadCloud.visible + onVisibleChanged: { animateOpacity.start() animateScale.start() @@ -89,6 +91,19 @@ Item { rectangle.color = "#262728" label.color = "#686868" } + + Image { + id: downloadCloud + x: 210 + y: 118 + width: 60 + height: 60 + source: "images/downloadCloud.svg" + sourceSize.height: 60 + sourceSize.width: 60 + fillMode: Image.PreserveAspectFit + visible: false + } } } @@ -187,3 +202,9 @@ Item { font.family: StudioFonts.titilliumWeb_regular } } + +/*##^## +Designer { + D{i:0;formeditorZoom:1.3300000429153442}D{i:8} +} +##^##*/ diff --git a/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml b/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml index 6faf3a65547..6a18d10ded3 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml @@ -39,6 +39,7 @@ GridView { id: hoverOverDesaturate imageSource: typeof(thumbnail) === "undefined" ? "images/thumbnail_test.png" : thumbnail; labelText: displayName + downloadIcon: typeof(showDownload) === "undefined" ? false : showDownload; SequentialAnimation { id: animation diff --git a/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg b/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg new file mode 100644 index 00000000000..3a527c3e54f --- /dev/null +++ b/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg @@ -0,0 +1,29 @@ + + + + + + + diff --git a/src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png b/src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..5428c80776ec89562e2bfdb21f7e209ddfbf7ac9 GIT binary patch literal 48336 zcmeAS@N?(olHy`uVBq!ia0y~yVEDzrz_5dZje&vTRL#dI1_lPUByV>YhW{YAVDIwD z3=9mM1s;*b3=G`DAk4@xYmNj10|R@Br>`sfQzj{XJ&WfFMy(7C3Jjhujv*Dd?(B`6 z9DB1=?c3VgW!CrSG`OgxE#NYpG{qxWH(SZHWP7x3@RFSJ-v|fWm?{odpv~S<%yY=Qu4{j^`vJ(6&*dWU!$f3ZXz_hZy;mY=a`-~|y&R3PE^>6%l z?N9Q$f5-nl`qa6jii7dNC+TbYYwFW%oBzoghwo2$9De%!739W&HA2$usw>|1M3u!~ELx^y{d7xk{h?-(FXET)FexlQX^N zx%BLLZ(na`+!og=`(JatZn*#1ukF+KEB_Tsu$Md2yFYTDypf#qx8p|Z`Hg3+sA4ku zw|&?0XP-^i?fkoQ#nX*EdGkC!@02|Kx$SBC68%Fb{=eA$|2M~h?Tj^ZIqF$1@MXRZ zO>dH7U-ReZr{7N%H}cM(c7L~>;MF&d_Y;&>$?9Cuo0NFq%(vuI(peH#*W

|QR@ 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 I&MBb@04#3?!T #include @@ -175,9 +176,29 @@ public: QDesktopServices::openUrl(QUrl("qthelp://org.qt-project.qtcreator/doc/index.html")); } - Q_INVOKABLE void openExample(const QString &example, const QString &formFile) + Q_INVOKABLE void openExample(const QString &example, const QString &formFile, const QString &url) { - const QString projectFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + example + ".qmlproject"; + if (!url.isEmpty()) { + ExampleCheckout *checkout = new ExampleCheckout; + checkout->checkoutExample(QUrl::fromUserInput(url)); + connect(checkout, + &ExampleCheckout::finishedSucessfully, + this, + [checkout, this, formFile, example]() { + const QString projectFile = checkout->extractionFolder() + "/" + example + + "/" + example + ".qmlproject"; + + ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); + const QString qmlFile = checkout->extractionFolder() + "/" + example + "/" + + formFile; + + Core::EditorManager::openEditor(qmlFile); + }); + return; + } + + const QString projectFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + + example + ".qmlproject"; ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); const QString qmlFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + formFile; Core::EditorManager::openEditor(qmlFile); From 550359b954436a2d7a1768262046944988b930f8 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Sun, 21 Feb 2021 23:00:25 +0100 Subject: [PATCH 14/42] QmlDesigner: Use predicate to walk nodes for merging Required for important customer Task-number: QDS-3776 Change-Id: I59f647042d5975f953c4c9e2f24e60a0003b85c8 Reviewed-by: Thomas Hartmann (cherry picked from commit c17458cfa909b06e4a2204d069fc7a596fe57be9) --- .../designercore/include/modelmerger.h | 9 ++- .../designercore/model/modelmerger.cpp | 74 ++++++++++++------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/include/modelmerger.h b/src/plugins/qmldesigner/designercore/include/modelmerger.h index 28541d3b98b..790cc8de1e7 100644 --- a/src/plugins/qmldesigner/designercore/include/modelmerger.h +++ b/src/plugins/qmldesigner/designercore/include/modelmerger.h @@ -28,19 +28,24 @@ #include #include +#include namespace QmlDesigner { class AbstractView; class ModelNode; +using MergePredicate = std::function; + class QMLDESIGNERCORE_EXPORT ModelMerger { public: ModelMerger(AbstractView *view) : m_view(view) {} - ModelNode insertModel(const ModelNode &modelNode); - void replaceModel(const ModelNode &modelNode); + ModelNode insertModel(const ModelNode &modelNode, + const MergePredicate &predicate = [](const ModelNode &) { return true; }); + void replaceModel(const ModelNode &modelNode, + const MergePredicate &predicate = [](const ModelNode &) { return true; }); protected: AbstractView *view() const diff --git a/src/plugins/qmldesigner/designercore/model/modelmerger.cpp b/src/plugins/qmldesigner/designercore/model/modelmerger.cpp index 8213109c034..6bf80dfd570 100644 --- a/src/plugins/qmldesigner/designercore/model/modelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelmerger.cpp @@ -43,7 +43,9 @@ namespace QmlDesigner { -static ModelNode createNodeFromNode(const ModelNode &modelNode,const QHash &idRenamingHash, AbstractView *view); +static ModelNode createNodeFromNode(const ModelNode &modelNode, + const QHash &idRenamingHash, + AbstractView *view, const MergePredicate &mergePredicate); static QString fixExpression(const QString &expression, const QHash &idRenamingHash) { @@ -130,25 +132,36 @@ static void setupIdRenamingHash(const ModelNode &modelNode, QHash &idRenamingHash, AbstractView *view) +static void syncNodeProperties(ModelNode &outputNode, const ModelNode &inputNode, + const QHash &idRenamingHash, + AbstractView *view, const MergePredicate &mergePredicate) { foreach (const NodeProperty &nodeProperty, inputNode.nodeProperties()) { - ModelNode newNode = createNodeFromNode(nodeProperty.modelNode(), idRenamingHash, view); + ModelNode node = nodeProperty.modelNode(); + if (!mergePredicate(node)) + continue; + ModelNode newNode = createNodeFromNode(node, idRenamingHash, view, mergePredicate); outputNode.nodeProperty(nodeProperty.name()).reparentHere(newNode); } } -static void syncNodeListProperties(ModelNode &outputNode, const ModelNode &inputNode, const QHash &idRenamingHash, AbstractView *view) +static void syncNodeListProperties(ModelNode &outputNode, const ModelNode &inputNode, + const QHash &idRenamingHash, + AbstractView *view, const MergePredicate &mergePredicate) { foreach (const NodeListProperty &nodeListProperty, inputNode.nodeListProperties()) { foreach (const ModelNode &node, nodeListProperty.toModelNodeList()) { - ModelNode newNode = createNodeFromNode(node, idRenamingHash, view); + if (!mergePredicate(node)) + continue; + ModelNode newNode = createNodeFromNode(node, idRenamingHash, view, mergePredicate); outputNode.nodeListProperty(nodeListProperty.name()).reparentHere(newNode); } } } -static ModelNode createNodeFromNode(const ModelNode &modelNode,const QHash &idRenamingHash, AbstractView *view) +static ModelNode createNodeFromNode(const ModelNode &modelNode, + const QHash &idRenamingHash, + AbstractView *view, const MergePredicate &mergePredicate) { QList > propertyList; QList > variantPropertyList; @@ -162,14 +175,17 @@ static ModelNode createNodeFromNode(const ModelNode &modelNode,const QHashbeginRewriterTransaction(QByteArrayLiteral("ModelMerger::insertModel"))); QList newImports; @@ -183,32 +199,36 @@ ModelNode ModelMerger::insertModel(const ModelNode &modelNode) QHash idRenamingHash; setupIdRenamingHash(modelNode, idRenamingHash, view()); - ModelNode newNode(createNodeFromNode(modelNode, idRenamingHash, view())); + ModelNode newNode(createNodeFromNode(modelNode, idRenamingHash, view(), predicate)); return newNode; } -void ModelMerger::replaceModel(const ModelNode &modelNode) + +void ModelMerger::replaceModel(const ModelNode &modelNode, const MergePredicate &predicate) { - view()->model()->changeImports(modelNode.model()->imports(), {}); - view()->model()->setFileUrl(modelNode.model()->fileUrl()); + if (!predicate(modelNode)) + return; - view()->executeInTransaction("ModelMerger::replaceModel", [this, modelNode](){ - ModelNode rootNode(view()->rootModelNode()); + view()->model()->changeImports(modelNode.model()->imports(), {}); + view()->model()->setFileUrl(modelNode.model()->fileUrl()); - foreach (const PropertyName &propertyName, rootNode.propertyNames()) - rootNode.removeProperty(propertyName); + view()->executeInTransaction("ModelMerger::replaceModel", [this, modelNode, &predicate](){ + ModelNode rootNode(view()->rootModelNode()); - QHash idRenamingHash; - setupIdRenamingHash(modelNode, idRenamingHash, view()); + foreach (const PropertyName &propertyName, rootNode.propertyNames()) + rootNode.removeProperty(propertyName); - syncAuxiliaryProperties(rootNode, modelNode); - syncVariantProperties(rootNode, modelNode); - syncBindingProperties(rootNode, modelNode, idRenamingHash); - syncId(rootNode, modelNode, idRenamingHash); - syncNodeProperties(rootNode, modelNode, idRenamingHash, view()); - syncNodeListProperties(rootNode, modelNode, idRenamingHash, view()); - m_view->changeRootNodeType(modelNode.type(), modelNode.majorVersion(), modelNode.minorVersion()); - }); + QHash idRenamingHash; + setupIdRenamingHash(modelNode, idRenamingHash, view()); + + syncAuxiliaryProperties(rootNode, modelNode); + syncVariantProperties(rootNode, modelNode); + syncBindingProperties(rootNode, modelNode, idRenamingHash); + syncId(rootNode, modelNode, idRenamingHash); + syncNodeProperties(rootNode, modelNode, idRenamingHash, view(), predicate); + syncNodeListProperties(rootNode, modelNode, idRenamingHash, view(), predicate); + m_view->changeRootNodeType(modelNode.type(), modelNode.majorVersion(), modelNode.minorVersion()); + }); } } //namespace QmlDesigner From 385aecc692329bfe47a27bf26bbd46b63b84a735 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Wed, 24 Feb 2021 15:05:17 +0100 Subject: [PATCH 15/42] QmlDesigner: Handle dynamic properties while merging model Add variant properties explicitly to handle dynamic properties Required for important customer Change-Id: I22366e29e390a2dda7d882e4c2fde2540397c955 Reviewed-by: Thomas Hartmann (cherry picked from commit 0c1d44604ad45d9f587910e828dc9368268b41d6) --- .../designercore/model/modelmerger.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/modelmerger.cpp b/src/plugins/qmldesigner/designercore/model/modelmerger.cpp index 6bf80dfd570..df1939cc4bb 100644 --- a/src/plugins/qmldesigner/designercore/model/modelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelmerger.cpp @@ -62,8 +62,13 @@ static QString fixExpression(const QString &expression, const QHash &idRenamingHash, AbstractView *view, const MergePredicate &mergePredicate) { - QList > propertyList; - QList > variantPropertyList; - foreach (const VariantProperty &variantProperty, modelNode.variantProperties()) { - propertyList.append(QPair(variantProperty.name(), variantProperty.value())); - } NodeMetaInfo nodeMetaInfo = view->model()->metaInfo(modelNode.type()); ModelNode newNode(view->createModelNode(modelNode.type(), nodeMetaInfo.majorVersion(), nodeMetaInfo.minorVersion(), - propertyList, variantPropertyList, modelNode.nodeSource(), modelNode.nodeSourceType())); + {}, {}, modelNode.nodeSource(), modelNode.nodeSourceType())); + syncVariantProperties(newNode, modelNode); syncAuxiliaryProperties(newNode, modelNode); syncBindingProperties(newNode, modelNode, idRenamingHash); syncSignalHandlerProperties(newNode, modelNode, idRenamingHash); From 261967a5f4a479e3e63aaa57d7bea02ff716f25e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 2 Mar 2021 09:10:08 +0100 Subject: [PATCH 16/42] Fix search result font for symbol searches SearchResultItem defaults to the standard application font, we need to tell it to use the text editor font explicitly, like the specialized addResult method did that was removed. Amends d3deefc3a4306e5b8882c7388f2ef1684dc0d922 Fixes: QTCREATORBUG-25396 Change-Id: Id8d41d93c96fbfd6d993568a37d42509da452665 Reviewed-by: Alessandro Portale --- src/plugins/cppeditor/cppeditorwidget.cpp | 1 + src/plugins/cpptools/cppfindreferences.cpp | 2 ++ src/plugins/qmljseditor/qmljsfindreferences.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 738c15f45d2..7643b1976b2 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -421,6 +421,7 @@ static void addSearchResults(CppTools::Usages usages, SearchResult &search, cons item.setFilePath(FilePath::fromString(usage.path)); item.setLineText(lineContent); item.setMainRange(range); + item.setUseTextEditorFont(true); search.addResult(item); } } diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index 72fe7b885de..d0fe1c75bdd 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -636,6 +636,7 @@ static void displayResults(SearchResult *search, QFutureWatcheraddResult(item); if (parameters.prettySymbolName.isEmpty()) @@ -831,6 +832,7 @@ void CppFindReferences::findMacroUses(const CPlusPlus::Macro ¯o, const QStri item.setFilePath(Utils::FilePath::fromString(macro.fileName())); item.setLineText(line); item.setMainRange(macro.line(), column, macro.nameToQString().length()); + item.setUseTextEditorFont(true); search->addResult(item); } diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index 4d4fe5c7b94..a251e823062 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -1012,6 +1012,7 @@ void FindReferences::displayResults(int first, int last) item.setFilePath(Utils::FilePath::fromString(result.path)); item.setLineText(result.lineText); item.setMainRange(result.line, result.col, result.len); + item.setUseTextEditorFont(true); m_currentSearch->addResult(item); } } From c100616ea68d18238989178636565dbd887fab99 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 23 Feb 2021 09:17:31 +0100 Subject: [PATCH 17/42] QmlDesigner.RichTextEditor: Use proper parent and make dialog modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ifeb7f228acfcfc7daecdcd431be639809ec47f0e Reviewed-by: Henning Gründl Reviewed-by: Thomas Hartmann --- .../components/richtexteditor/richtexteditorproxy.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditorproxy.cpp b/src/plugins/qmldesigner/components/richtexteditor/richtexteditorproxy.cpp index 12e0cee41bc..5d7d631ccf5 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditorproxy.cpp +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditorproxy.cpp @@ -24,23 +24,25 @@ ****************************************************************************/ #include "richtexteditorproxy.h" +#include "richtexteditor.h" #include #include +#include + #include #include #include -#include "richtexteditor.h" - namespace QmlDesigner { RichTextEditorProxy::RichTextEditorProxy(QObject *parent) : QObject(parent) - , m_dialog(new QDialog{}) + , m_dialog(new QDialog(Core::ICore::dialogParent())) , m_widget(new RichTextEditor{}) { + m_dialog->setModal(true); QGridLayout *layout = new QGridLayout{}; layout->addWidget(m_widget); From daea0d4c07bffdfab72556e88d8fad2443f1b9c4 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 24 Feb 2021 17:16:39 +0100 Subject: [PATCH 18/42] Doc: Add summary of Form Editor toolbar buttons and fields Replace all occurrences of "item" with "component" Task-number: QDS-3771 Change-Id: Idbfdf30a4f651126d2f9875770cab036b65d9779 Reviewed-by: Brook Cronin Reviewed-by: Thomas Hartmann --- .../qmldesigner-form-editor-move-cursor.png | Bin 0 -> 8669 bytes .../images/qmldesigner-form-editor.png | Bin 8669 -> 14960 bytes .../src/qtquick/qtquick-form-editor.qdoc | 208 ++++++++++++------ .../src/qtquick/qtquick-properties.qdoc | 4 +- 4 files changed, 139 insertions(+), 73 deletions(-) create mode 100644 doc/qtcreator/images/qmldesigner-form-editor-move-cursor.png diff --git a/doc/qtcreator/images/qmldesigner-form-editor-move-cursor.png b/doc/qtcreator/images/qmldesigner-form-editor-move-cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5aa3a6c3fbbd206358f2a2bfc8a5fa3dd1675c21 GIT binary patch literal 8669 zcmeAS@N?(olHy`uVBq!ia0y~yU_8OVz!=8C#K6Fiw0>3}1B2ocPZ!6Kid%2zR>p)p zy?5aE==(1zRqO8{dEb{JZD8&F4AK8PcD;mJR|s$;4G$C0iGL2XBcup?a&oQrlXE}p(l zJ8aFJh-q6wSM&7#5!6m{UBmLQ#HHl*w7GL-FYRfKtl$0NoBo~&%d5)n?(#XEdvwoV zcAgEUpC2eX&k@Q#IA?qJCa)yFILDoTQ`4OuI~!g)VL9(>*}~Jie*_=<9UEtt`ugHL zYx}aWHHDwerY6Si_`Ht$`Z+^=y*qCfTAbbAF;ziJQ^h#<>aO0@`uqF-F7v7N**kmY z&U>$(ojh5r?msW-=KhkGmlwPBmwByejdbrn{zQaDGmx=!;apDcXELUprB|yRRh46J zCtunf-(y{IZd3iyi}`Hte;#?+V|vHq&K~C3k9>5Gr*+>hIdEp*F}c+2ZplNv!rHp8 zZ!3j0X$U7D>wA6E_|(4{esitQ&#=6_##lMoH(~NJz3!{4qJzcsw{2Oaw{g}@U5(`z zrj&Nc``Q+j`!{|xJ72PUxj|b0rwqq{dxhOwuFTTwR@b?;zT>J%;)Qv^zt7JxQrlL| zCG#d^espkuP44kkeBO*p{~6yiOx>tDGyR9nR?+k;&-XC1pOev;eLL!MYDJ+|jl;}{ zcjt`no9(ISNvnHl{+4y4&{i`hCMI*+&py-F32tNC!pl3EaT=fQ{)n@8vQDo$*KPXz zN8L-qXR|*Ae4M%aWJ9Z?WvaYwaaNzEZg1u9kg$1Id#=_TvV7HYEXd)cN4xdaiQBEV ztP)N#J>`FKUZnHh_(}7l&PSL|Ua_*^C7;RdtYbMr$0fE(r`zYct#Rq)|G0QXFiY0Y zfbMB)=T*P6Jnghfc4OD#?Kw9;J=s&~m2=|Mrv2rGucxdGej5?m9&vuot@@D8$8L+C zioU%cJV&L=@cEM!aylDR3U`0m6Suq5D6z1&)ITv`raQOJQK=Ne=BaaUt>yGNVZZ$N zD!&d>zqPH?roL@tR*hV_HK<`y`>LDiFDDduZ)}TRvh(O!qfFx@)vVGEtL=Gr)uc>c zi?~LKu9MxU6}cft`tI(2pBJyw3wC@DkFPEL`if_IIO~k`HAQXfmd!WJpKrKruITEs zoVi_B5Bj}5_FH^?ig>Kn|5XfEGu7IoVon-8ofOuSu~=k*;S%4CS-M(DX4?d{9jDkn z74Kbja-~P`yKV0;T)b9copjaGq4P@W=_Tj1C0Ad~j?|mVbZY*_TXQb>tSQ>QM>6}@ z#_o;P_EUSVzS^oY-8ihfYUNAEtwITVUOTMWW*l~QTgn=ih3D5MIY;ts&Ae>9X~8O+ zdsmdhHm-_d-0(OoT|ch#z295&d8g-Vh0VUaw82<)YisZ_?%++_k6Vt-GmhFQCA(|? zk4IDQ&b_s5RTSfe$6~(kz6C*3vqj_ik~@fE~|Syf%%wrc+plb z?Xb7oUiI-!Nju#!RY6BkZ$!#z-#&JPXVcded&*b0b${Jg%6hkK&bF^Bz8fDG(006XYeGxN zy_s6wOV2pzxkbhA(F9Us=|*FZBS{%v{5PSh?f9Mk}5~jiZ+KeERF(G6|U`P zVsK~;dvYgm&G%4&(4WS^;g{t1d|&{n?TTO&0F_q^9a}dYwaUA*!|PYz)tMJnlh%68 zGR-zCdUE39b!1}>l&`@FBg3JCMO}Wqw@1JQSGoT85f=2nn>`RJbALRvU09f>8eMS4(lW2 zt6nJne1AHNX~oljzu#}yzs4?K6OdB={cidFWbvC5Yd4;fnEBklZ^z?4>p7yU7u7v| zzNJ3<_}UK9jl0yY#qKWKx#9bjD_2y#r(IbcetymW_x1mOw{QwSd0Z`Rk`XZVbA{Nt zzh||5)~pU&J1Kg#bcc_#lhc>N@e6+j4GRx>nE3cT`LI zl)uJyewz;sSEHW>9_flWd*s({Ht{37Rn_9KgMoM1({f1*%?rRq95ma_Nu{fx_eBrTGXCrbQk3|I^ef9S3+CTf( znXU3!v-{Md`s<6`dMAa?{}FQQ|BvJLfByU_DlUH775w+t*Qty}yk36hbLTGK$M*O0 zk+gUB=FXH@Ex0nZf2Fapp^l-k@wfFGJ3AAv=3nh9UA;DaqHxmGv%kK-*XKVOA5*w` zUQol*h*WLMb*pwBSv&3X3&GVhzFc&d4}HGzRhX^h>Xc<+-eQ-O|9ahfwIrhY$n$6U zC(llexN`T(W!qHmb-yGZb9Vdi=bk*@>%Qh{OMidAO6tLb2R~I!XgfD~1DD`yz3dk^ z*Uwp^uBLWwmZ`T?(g9X(v5ruFdAmQ4y7f=F-|tRI^?849?^B(7H!IDiKR9BO*tz@Y z)Nj>ZN2IcM39di3t36cv)Y`InuID;Kbyiw=-_q+2-8eNUVd}QiNqb+f+r4DVDv^k# zZ=-rc1y?^kzw*zYQ;W}an%b3n*GTr4c%RfaTeC9u&x#vnOWBjwiamL$n||TcYNyN- zHw&+Je67oVar6ECf8Vwrm#g-fqv5nBdiy$+Rm^NW6;G#z3keBTeS5Pq#9Q@lgw11J5QfidVVD9`MThx3^&6fGeYM{ zW&fNWooO6qom6U;{C3(Rl_it5EGscyx?-7I{|}MJv7Tw(Dzg`OCJSbVDjyHGQPO9t zT&2xx*q1H7UPm?B)4tfn<;ZFM{W_)rPv0r`+bG3r2uVq;TDC}2Q!{wEUul`#=_%J9 z+Dw`!H+l0v1Le*jMh~9NZwzlQ__ZgB_q@{aq|iI++mi$=C%h8eTE&&`zUEaz=86C9 z(LOg;soxM>trW1c_SMSe&oU?M&YQHcE8;4b!@d=pEgIi$JW=wlKjN;0EftE0FK zI!*0V_s=j+{}e2=<fW4++k&5>>BsyoB22?78JeoJZpG+d%phZ-|D`zmKeX+dvCMI@9N@>GmpD0o@Sf+IdpOKVIT9Wfm|Br z@84-npJ=;=T!JE*R|2K0+Z)IAY6ndROLwvfH z%bF~|Ebj2EHIwFOiLd|U?Y%ndSe8%7=g&JULie6voGS8AQP}J7%}~atnyeY|&;9lu zda88NTYs<0^cmmY-POK6;ptP&=XWPgoLKbi-?Q2IUA$M{Y~^}p*mY$_lT?0k?w2W5 zp(R;swx*?}h55T4c)EXQ_Iai1q^aF8r=%E4nLobd5uWzC>upD9mcy${s$1iC&-3h$ zcq+AbkE_egB}_+GtqBR8&N$;P*P7(DD^0_4b5E`0)qcXubn5k;mEk*7T#^pIyu7^o z>k=C+(}0arVoptuuG}5+_*n1i3c3Ent>DC6ofP_N)2ay9WkHM+niVTo2MJ%$3`;yQ zK`||9@9mc0B+;a#BrTidr*p&iI4*c~bk&}7U*Cspl8OAU(mCI3`V<%USD8UmR{yHB zxxO}ZvoiZq21~(rmzVb!{fy&LVs~C?e`?}{-B#IajC{`hdi?0omZc1?JI+mGO7Xq= z;o)J?ji*?(*M>e_$DK6Qe#;*QzI;LLq_u7;$3>*oR8?PE2Cr$VJRrJJOD;s5S)(mf zY-85vxc1i(qPd!0m-@ngZ)JYd5n5CAd~W%wZbp&AT9ft$H*>#^&}KQ(6`?I{={U!> zy6k6eMBwKJ?W9un9}BXNa5Y4L+x-k3q8pXM8lqIg7#Plrtu|+1uwYJNWpG%-z|bMe z0IG5sR*2Yrihe(@F@lj{^{%bag4zrUVMn+?8kra}j{b7HT*|FPDjW zl?;pGP9BZqy(emy7ndu9F)+j?ZRM#v5woW5b@zz~Mh2O#(jON@OXo%Wa`=?Ac}H#C zsbD|lPb+<6-3U5t`F7!C%i3j((Y}A%{q*lG)QXTS zsQS21nDe(++gppsGM*&X1}W8RGX%Ad@kM2tW=>u8`ix!Xt)K(PgSaN#{!{C^=*kJ% z<>y7_nV4;xcS6@@Zo;J%FY^KqE$pAVsBvZBl3b11+0q@N3|TWG(!az`y`z2i(yGtoY_ncNx@=XkF4d=e9Muh~HClTgjwLGSj-l83Kfl{t9@M zRJi);ivK@?Jk$CmuUXIBD5rJK|MSv6t9mRyZ+w|o*n9Pca_;Bs7?4+*BJT5^5!rsL z%lBb6A8XpQ@}D7@uBEk^cBhN98CI-JTH9riw#jRjxOZ`}%E3=V5V_e?(}n(fTMAPr73Q}x39@3dass}RPp z!ffNLR`qv>Ud0J$GlXo9tG#Z%!FTSium655XMeJ-adpVk|H7dg?{um2GE8w_(-r#k z&n}xh*EI|c5ogz~dawzS3bn&@%U;XJ7HTK4G91Y|a%ol8y{-sGh8U68x!dom7RG)2o%`x8+|xZflHSJaG5utplqaUmVmB4BHrS_v-QvQHDEFYrJAZ53Qc*KYOmN zNMfYu>N`_8Zr$PB$i#3%WOdb6uXEp>?{{6Yx)QX;=-IE{_`9dpf^>PWxn;_ro-N?{But|o~ZcFK#kzYAt;DY&{ z1>0-YPch_z0$VXjw`}!Fz6Swo_T@T9wUuwmzxrr(^!~V$zlv7Zs^|T)^6ynYzYJug zWztruX-TnVb!#_^@7TBFTj_D-+T6EJ)}QA8ujAgx6_3CD<>}|+`}8-}e0jEZ_GbIYmI%fLW!FZNn&ldr5*M(YTBOdUfEaOquBRV|6pFrF6?)9Q|Zo?pC>XN zuhW>kciqkj%@K?XzIBC`uHLiVD>l;f;nbT^oN>GAZti;{R=3T``rn`P;o;{ir zdUw^ja8v88{aP~5E|lN;7@ik5l_&hAe9)8)&p$D$Zb{y^t1j?uc+$W0(}LOzS7bJ> z%HHtAY>h%x_JQu}dS5kU9$hG3?C*0qZ|awqNlWVwy}W4^F7l*yHz)vlg;q;_KCgHE zSKjgM)n9a;y)U=n+sMR_v{ml;x_RcptLLr#RcrC-+S=$>VYByD$$_MFr$_vj>;L_9 z`=!+AO>EvT`>n)gmy~r1-OB9$U*hyOT$gU(toQ3TfIcS zT9|EqX0M%{)9%oulhIM2y5XAL+f#KMr_0U%$*z37I^z8QKdv*+b6M~STwtam5H_Onl%b}gd z;pbK*=lv;jHWT@;RW&us`F!$W0d0ngNkLm52E-+u;l94l#cGph%={djLv*Z0ICvCkr#)j&bTMwmP|9|*mn&<03 z=ck2Fiipf(1tq^}@A-bby_TPA*Re)rbz9Eswg|=r&$>geef$66bpNd-U*BB)JayyZ z3x8Hr*D`}LPR+)w@PDVpw=Ro6v2IGt*PD6YO}YL&-rEcE7uQCwn(Dv156bthUUKrb z+?$mVq8phUbcM2?wq6N+Z_1((1}@FDjl#k7Y3Z}^FY4ykORiP|CEs=Kvzcvm*LFoP z9(a4?*M|dP^Mtciv98_W!$kRQr~fy%CHH+B!^=?@s$;&c8Zvd0lq2^7psZ z$xm)XUh?pa{CoE3`z0Tr?`K^bx!rYtM03=)TYG=c=jDBPDerpbg;QI4z3LCOERnC@ z14@)_9be~`_s8w}GygC9zpv+;+t!f3L)E zsIGc1@iN>h{jA@~dtaJNHWkf#Z=TVlbxG#U-*SfpE za+mx~m^4Tx_Z6rp4W{HfsfNxYd*PjrL_H?r4n!9yQZU( zt0La-*uU|~hEHo5A3c@Z`)JC+`W?5wFMYe-bN`m({`0gaU&+1Tb?XvGrs!3}q#ILL z+naN~o3_j7^ZSC`|3?&Y%KnNFieYONO#B4f$;)Y6-vB}F-qOY&K^uH;-`ew^{yZxUt9(LY- z|LyO)PxX2+KVJ2k^WXno@A&`U_xh!L32N8E%jLJM*(hgSXO#EmF{q$yico#G>-zeL zH6NEI%{40R3r<@5UijbJ?b9dEkNNoS;o`5ghx=u8s}%FM$H@G?T>CFA>2C0*__Y!J zGJiGdF2x+-Vwk6UEm?k^l$d$#jm4Mu{rEKd^Zfds8^T|#_@TbUNWu2f{^I9x)=8p@ z$NJ{Tt%lkQ|G_B@;=)}CWl@j?fgt|UIdlmptekh=td@nD>WPM{azpss$`-P z3!ndOW8;;AwC$#@{*_fPc!Z1LozgX_&yWTmBojXMWQKGPl3?aFWGUrVJkne9j&&oG z!`9BP<-Ai>uARCEX$uyJZwzw_Ij9HA(NmZ-SQWw;F1%FMi&G3^V5q+FT@kHM!f=F( zp&^2iK>(EF;hmLTde{2)-ZJ~5wfFWa=MM`yCps^4+4@%GkRda}kympfW^d(?5x8Ib z_2A8Yb#`9<1+UdItJC>p?kg8%9A9cJ$DQ%)d?H9?ON8}zPTBn#1-JG^u8L^)?T-6! zhs85t@18x&mhgE;2pk5hD$!JUdi3O~2z5Ozk{Y_wL2XSTZ=QS=U{9YSWE}#$HFPRJBU4o9Kh9Q=6p?KUfWg zgV?m+PAvX)_P$x;VK#=2tuaYczcQSTo2$3{ztH7NZap)u&IXBJ<=j}-l{b4s!i7(^ z#zJCz@66Sls-(i4+P%EJf2CL@4qp$Lv!&{H zMeCN_Yny5}^y^;@WpG%tXQ?P!P%4Enz{5DZwL8>K!az+e?ct$TO9qBKXE(QFQ#6BT zndiTom?UeGapBh1Y|Ac&2W@BO*+wrvd&hf?rlzKh4MTx{*!sA)&!0c9ObV@U?5&i% zSv`Nc|NX@fiNMLV1_~2wxZK>^B)+%j0C4Rc#3Bv)~$o+MD-RqhUEb*LdQNi$Fo=)VZBiFBA|9nJB zM#d)jSkIR)C47nuJ3`m(DtUP+Zg15|bIF38YKq<&?&CX82^Jh9|*lqdhe)DfSPp+=*+GbwX*T3}UUrBs-VnhAX?|Ij5 zw1ZMZ==zAmv&^mbEbHI?GI*DBGjIE)YVYKCCoX)y_HAPSyJ`RKEa^xUwl28Az_9U^ zXm-r{33I!ZrmnXa=&hS^_x|zK4}Z;^d)@E#5}pVvyFc-2w?Tf3-ID+E|Gimuxy`(6 z@$a`Owk_)YyY$H}Rl}r*H_A>ioQ&&F{rdgew?`)!8IrD^K6O&IFa2wEa_X0FthQZ6 zY$ui}U1Lo?>~-YUw;OCnxEMOFo_reS`?ogA>@&AP#ooDcy5-l;Yv{5r@q1B_VY-xo z!C{Tw+T^HaRh&Mf&C@57@!axWe! z&-lJT(6%|6^&=Z2;Y6R>VQOV%WoT%~%y1yL;@8XN$9p7&MMR!VOnQ5J`}o)$DC0%dkZa5g!tfzIMWn9l_q1v*4G z3b8bTrgafaghAP71+&xA)aD2AF}(8(3!CQNRr>16O0fH$XtUPV*4p~7SsS(0%gZZj zcbRUx0K*-va9?k4X@i7@>C>mX*ZnO`NLcW~REFU|E(b3!FCX8xj~_ptSihf*VFe>N z*@H@7STzADhZz`>Tw#Mop!5STpdk{V;U)%$Uh!<@`uMl~H&$$%FIC4D4~^Da76;ZR zyPV#lD_r}xYkSsZy^PP<{p$MC^QL6=6kh%XPPbNy*BTF7uRk?+%I4y>ur<>0GcW4w zFm&f;5Lo?sX+x^C@R=i0my9mlKHkj?DmR&q+%mJ#NWXsOjqK&k@iPq{eyqE9?**t! z^Yh3pivt(bY&?vv@x?}a{r^yCYmvjy5OG>HOn36LFYz-ByFhtrYfREt;~!K0tcfe0 zcFfOH?gX?Xjc#ZCDt#;S=`+qE>5H3tzZ~&>GjmUlONr0#js33cE9<-*CcDX)F*vO8 z>)4uld)Z#LZT)>O71Vg&-*Kv1vg=lQ!SRP5?&cJY|O?_TP(u)fV8yg$tG_RdFaUyhe*i#0E9rBYtS5{V5&Wm_{ zZtm%W%naXEbal_3KY#x7k*HtNIp^+t$=S8s#qV9zykdr}jNo)w`|RkIwZG?mm~!J! z5tqLO19*u5YUv9pU|B&@;4&AKjX^B}P&|X8Gl>;c2!r}71b+9ArY!0O1a|J7|x*O@mi_G4gR OVDNPHb6Mw<&;$UB^LK~< literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qmldesigner-form-editor.png b/doc/qtcreator/images/qmldesigner-form-editor.png index 5aa3a6c3fbbd206358f2a2bfc8a5fa3dd1675c21..b042afe44e7aa6d22d378cb06b3e162109b3a094 100644 GIT binary patch literal 14960 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 BvZeq4 literal 8669 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 OVDNPHb6Mw<&;$UB^LK~< diff --git a/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc b/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc index e93be2f583f..12aa6187b0a 100644 --- a/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc @@ -33,47 +33,129 @@ You design applications in the \uicontrol {Form Editor} view by placing \l{Component Types}{2D components} and \l{Assets}{assets} into it. - When you select items in \uicontrol {Form Editor}, markers - appear around their edges and in their corners. Depending on the shape of - the cursor, you can move, resize, or rotate the item by dragging it. - The following image shows the move cursor. - \image qmldesigner-form-editor.png "Form Editor view" - \section1 Resizing 2D Items + When you select components in \uicontrol {Form Editor}, markers appear + around their edges and in their corners. Depending on the shape of the + cursor, you can apply the following actions on the components by dragging + them: - When the resize cursor is displayed, you can drag the selection handles - to resize items. + \list + \li \l{Moving Components}{Move components} + \li \l{Resizing 2D Components}{Resize components} + \li \l{Rotating 2D Components}{Rotate components} + \endlist + + \section1 Summary of Form Editor Buttons + + The \uicontrol {Form Editor} toolbar contains the following buttons and + fields. + + \table + \header + \li Button/Field + \li Tooltip + \li Read More + \row + \li \inlineimage no_snapping.png + \li Disables snapping. + \li \l{Snapping to Parent and Sibling Components} + \row + \li \inlineimage snapping_and_anchoring.png + \li Anchors the component to the components that it is snapped to. + \li \l{Snapping to Parent and Sibling Components} + \row + \li \inlineimage snapping.png + \li Snaps components to their parent or sibling components when you + align them. + \li \l{Snapping to Parent and Sibling Components} + \row + \li \inlineimage boundingrect.png + \li Hides and shows component boundaries. + \li \l{Hiding Component Boundaries} + \row + \li \uicontrol {Override Width} + \li Shows a preview of the component using the specified width. + \li \l{Previewing Component Size} + \row + \li \uicontrol {Override Height} + \li Shows a preview of the component using the specified height. + \li \l{Previewing Component Size} + \row + \li \inlineimage icons/canvas-color.png + \li Sets the color of the \uicontrol {Form Editor} working area. + \li \l{Setting Canvas Color} + \row + \li \inlineimage icons/zoomIn.png + \li Zooms in. + \li \l{Zooming} + \row + \li \inlineimage icons/zoomOut.png + \li Zooms out. + \li \l{Zooming} + \row + \li Zoom level + \li Sets the zoom level that you select from the list. + \li \l{Zooming} + \row + \li \inlineimage icons/zoomAll.png + \li Zooms to fit all content. + \li \l{Zooming} + \row + \li \inlineimage icons/zoomSelection.png + \li Zooms to fit the current selection. + \li \l{Zooming} + \row + \li \inlineimage reset.png + \li Refreshes the contents of \uicontrol {Form Editor}. + \li \l{Refreshing Form Editor Contents} + \endtable + + \section1 Moving Components + + When the move cursor is displayed, you can move the selected component to + any position in \uicontrol {Form Editor}. + + \image qmldesigner-form-editor-move-cursor.png "Move cursor in Form Editor view" + + For more information about alternative ways of positioning components in + UIs, see \l{Positioning Items}. + + \section1 Resizing 2D Components + + When the resize cursor is displayed, you can drag the markers to resize + components. \image qtquick-designer-scaling-items.png "Form Editor view" - \if defined(qtdesignstudio) - To have the resizing done from the center of the selected item instead from - its edges, press \key Alt. + To have the resizing done from the center of the selected component rather + than from its edges, press \key Alt (or the option key on \macos). To preserve the image aspect ratio while resizing when using the corner - handles, press \key Shift. This also works on items that are anchored + markers, press \key Shift. This also works on components that are anchored using left, right, top, or bottom anchors. - To both resize from the center of the item and preserve the aspect ratio, - press \key Alt+Shift. - \endif + To both resize from the center of the component and preserve the aspect + ratio, press \key Alt+Shift (or the option key + \key Shift on \macos). - \section1 Rotating 2D Items + For more information about alternative ways to specify the size of a + component in a UI, see \l{2D Geometry}. + + \section1 Rotating 2D Components When the rotation cursor \inlineimage icons/rotation-cursor.png - is displayed in one of the corners of an item, you can drag - clockwise or counter-clockwise to freely rotate the item around - its origin in \uicontrol {Form Editor}. + is displayed in one of the corners of a component, you can drag + clockwise or counter-clockwise to freely rotate the component around + its origin. \image qtquick-designer-rotating-items.png "2D rotation tool" - Additionally, press \key Shift or \key Alt to rotate items in steps of 5 or - 45 degrees, respectively. + Additionally, press \key Shift or \key Alt (or the option key on \macos) + to rotate components in steps of 5 or 45 degrees, respectively. You can set the \l{Managing 2D Transformations}{origin} in the \uicontrol Origin field in the \uicontrol Advanced tab in the - \uicontrol Properties view. There, you can also enter the value + \l Properties view. There, you can also enter the value of the \uicontrol Rotation property in degrees. \section1 Zooming @@ -85,43 +167,23 @@ \image qmldesigner-zooming.gif "Zooming in Form Editor" - The following table lists the zoom buttons: + \section1 Snapping to Parent and Sibling Components - \table - \header - \li Icon - \li Tooltip - \row - \li \inlineimage icons/zoomIn.png - \li Zoom in - \row - \li \inlineimage icons/zoomOut.png - \li Zoom out - \row - \li \inlineimage icons/zoomAll.png - \li Zoom to fit all content - \row - \li \inlineimage icons/zoomSelection.png - \li Zoom to fit the current selection - \endtable - - \section1 Snapping to Parent and Sibling Items - - When you are working on a design, you can use snapping to align - items in \uicontrol {Form Editor}. Click the \inlineimage snapping.png - button to have the items snap to their parent or sibling items. Snapping - lines automatically appear to help you position the items. + You can use snapping to align components in \uicontrol {Form Editor}. + Click the \inlineimage snapping.png + button to have the components snap to their parent or sibling components. + Snapping lines automatically appear to help you position the components. Click the \inlineimage snapping_and_anchoring.png - button to anchor the item to the items that you snap to. + button to anchor the component to the components that you snap to. Only one snapping button can be selected at the time. Selecting one snapping button automatically deselects the others. Choose \uicontrol Tools > \uicontrol Options > \uicontrol {Qt Quick} > \uicontrol {Qt Quick Designer} to specify settings for snapping. In the \uicontrol {Parent item padding} field, specify the - distance in pixels between the parent item and the snapping lines. In the - \uicontrol {Sibling item spacing} field, specify the distance in pixels between - sibling items and the snapping lines. + distance in pixels between the parent component and the snapping lines. In + the \uicontrol {Sibling item spacing} field, specify the distance in pixels + between sibling components and the snapping lines. \image qtquick-designer-options.png "Qt Quick Designer options" @@ -130,33 +192,36 @@ \image qmldesigner-snap-margins.png "Snapping lines on canvas" - \section1 Hiding Item Boundaries + For alternative ways of aligning and distributing components by using the + \l Properties view, see \l{Aligning and Distributing Items}. - \uicontrol {Form Editor} displays the boundaries of items. + \section1 Hiding Component Boundaries + + \uicontrol {Form Editor} displays the boundaries of components. To hide them, select the \inlineimage boundingrect.png button. \section1 Previewing Component Size - The width and height of the root item in a QML file determine the size of - the component. You can reuse components, such as buttons, in different - sizes in other QML files and design UIs for use with different device + The width and height of the root component in a UI file determine the size + of the component. You can reuse components, such as buttons, in different + sizes in other UI files and design UIs for use with different device profiles, screen resolution, or screen orientation. The component size - might also be zero (0,0) if its final size is determined by property - bindings. + might also be zero (0,0) if its final size is determined by + \l{Setting Bindings}{property bindings}. To experiment with different component sizes, enter values in the \uicontrol {Override Width} and \uicontrol {Override Height} fields (1) on - the canvas toolbar. The changes are displayed in the \uicontrol {Form Editor} + the toolbar. The changes are displayed in the \uicontrol {Form Editor} view (2) and in the \uicontrol States view (3), but the property - values are not changed permanently in the QML file. You can permanently + values are not changed permanently in the UI file. You can permanently change the property values in the \uicontrol Properties view (4). - \image qmldesigner-preview-size.png "Canvas width and height" + \image qmldesigner-preview-size.png "Component width and height" - To set the initial size of the root item, select \uicontrol Tools > + To set the initial size of the root component, select \uicontrol Tools > \uicontrol Options > \uicontrol {Qt Quick} > \uicontrol {Qt Quick Designer} and - specify the item width and height in the \uicontrol {Root Item Init Size} + specify the component width and height in the \uicontrol {Root Item Init Size} group. \section1 Specifying Canvas Size @@ -167,8 +232,8 @@ \section1 Setting Canvas Color - If you set the background of the root item of your component transparent, - the canvas color can make it difficult to see the component you are working + If you set the background of the root component transparent, the color of + the working area can make it difficult to see the component you are working on. To make components more visible, you can select the canvas color in the \inlineimage icons/canvas-color.png list. By default, the color is transparent. Setting the canvas color does @@ -176,13 +241,14 @@ \image qmldesigner-canvas-color.png "Transparent canvas color for a transparent component" - \section1 Refreshing the Form Editor Contents + \section1 Refreshing Form Editor Contents - When you open QML files in the Design mode, the items in the file are drawn - in \uicontrol {Form Editor}. When you edit the item properties, the QML - file and the contents of the editor might get out of sync. For example, when - you change the position of an item within a column or a row, the new - position might not be displayed correctly in \uicontrol {Form Editor}. + When you open a UI file, the components in the file are drawn in + \uicontrol {Form Editor}. When you edit component properties in + \l Properties, the code and its representation in \uicontrol {Form Editor} + might get out of sync. For example, when you change the position of a + component within a column or a row, the new position might not be displayed + correctly in \uicontrol {Form Editor}. To refresh the contents of \uicontrol {Form Editor}, press \key R or select the \inlineimage reset.png diff --git a/doc/qtcreator/src/qtquick/qtquick-properties.qdoc b/doc/qtcreator/src/qtquick/qtquick-properties.qdoc index 5bfd3d4a11f..56329f11f0c 100644 --- a/doc/qtcreator/src/qtquick/qtquick-properties.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-properties.qdoc @@ -71,7 +71,7 @@ The value of the \uicontrol {Custom ID} field specifies the name of an \l{Annotating Designs}{annotation}. - \section2 Geometry + \section2 2D Geometry In the \uicontrol Position group, you can set the position of a component on the x and y axis. The position of a component in the UI can be either @@ -83,7 +83,7 @@ it in the \uicontrol Z field in the \uicontrol Advanced tab. In the \uicontrol Size group, you can set the width and height of a - component. You can also use the resize cursor to \l{Resizing 2D Items} + component. You can also use the resize cursor to \l{Resizing 2D Components} {resize 2D components} in \uicontrol {Form Editor} or the scaling gizmo to \l{Scaling Items}{scale 3D components} in \uicontrol {3D Editor}. The values in the \uicontrol X and \uicontrol Y fields change accordingly. From 8f2db9fcbe2b7407c7a989231d5aebe2b4d97774 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 2 Mar 2021 13:08:29 +0100 Subject: [PATCH 19/42] CMakePM: Ask for configuration save if the user has changed variables If the use has forgotten to click "Apply Configuration Changes" button in project settings but it tries to build or run the project, then the "Apply Configuration Changes" dialog box pops as a reminder. Change-Id: I26728ee3c79af72125be3bede759620c2cf3d7a1 Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 17 +++++++---------- .../cmakeprojectmanager/cmakebuildsystem.h | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index e62893b5a97..ec843295ebd 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -284,9 +284,8 @@ void CMakeBuildSystem::triggerParsing() } if ((0 == (reparseParameters & REPARSE_FORCE_EXTRA_CONFIGURATION)) - && !m_parameters.extraCMakeArguments.isEmpty()) { - if (mustApplyExtraArguments()) - reparseParameters |= REPARSE_FORCE_CMAKE_RUN | REPARSE_FORCE_EXTRA_CONFIGURATION; + && mustApplyExtraArguments(m_parameters)) { + reparseParameters |= REPARSE_FORCE_CMAKE_RUN | REPARSE_FORCE_EXTRA_CONFIGURATION; } qCDebug(cmakeBuildSystemLog) << "Asking reader to parse"; @@ -438,15 +437,15 @@ void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters &pa } } -bool CMakeBuildSystem::mustApplyExtraArguments() const +bool CMakeBuildSystem::mustApplyExtraArguments(const BuildDirParameters ¶meters) const { - if (m_parameters.extraCMakeArguments.isEmpty()) + if (parameters.extraCMakeArguments.isEmpty()) return false; auto answer = QMessageBox::question(Core::ICore::mainWindow(), tr("Apply configuration changes?"), tr("Run CMake with \"%1\"?") - .arg(m_parameters.extraCMakeArguments.join(" ")), + .arg(parameters.extraCMakeArguments.join(" ")), QMessageBox::Apply | QMessageBox::Discard, QMessageBox::Apply); return answer == QMessageBox::Apply; @@ -506,12 +505,10 @@ bool CMakeBuildSystem::persistCMakeState() qCDebug(cmakeBuildSystemLog) << "Checking whether build system needs to be persisted:" << "workdir:" << parameters.workDirectory << "buildDir:" << parameters.buildDirectory - << "Has extraargs:" << !parameters.extraCMakeArguments.isEmpty() - << "must apply extra Args:" - << mustApplyExtraArguments(); + << "Has extraargs:" << !parameters.extraCMakeArguments.isEmpty(); if (parameters.workDirectory == parameters.buildDirectory - && !parameters.extraCMakeArguments.isEmpty() && mustApplyExtraArguments()) { + && mustApplyExtraArguments(parameters)) { reparseFlags = REPARSE_FORCE_EXTRA_CONFIGURATION; qCDebug(cmakeBuildSystemLog) << " -> must run CMake with extra arguments."; } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 997fdc7fdc0..7667b77a772 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -116,7 +116,7 @@ private: void setParametersAndRequestParse(const BuildDirParameters ¶meters, const int reparseParameters); - bool mustApplyExtraArguments() const; + bool mustApplyExtraArguments(const BuildDirParameters ¶meters) const; // State handling: // Parser states: From 7c112ed01d6745cf67ff39a601b0e0902fea328d Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 2 Mar 2021 14:01:40 +0100 Subject: [PATCH 20/42] QmlDesigner: Fix build with Qt 6 No QList::toSet anymore Change-Id: I6e42bd3a1e917c128142b4628277ed48844d1d4d Reviewed-by: Miikka Heikkinen --- .../qmldesigner/designercore/metainfo/metainforeader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp index 7c4e1130725..c9ae1ef0d0c 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp @@ -26,6 +26,8 @@ #include "metainforeader.h" #include "metainfo.h" +#include + #include #include #include @@ -233,7 +235,7 @@ void MetaInfoReader::readImportsProperty(const QString &name, const QVariant &va } else if ((name == "priorityImports" || name == "showTagsForImports") && !values.isEmpty()) { // Flow tags are no longer shown, but the old property is still supported for prioritizing // imports to keep compatibility with old metainfo files. - m_metaInfo.itemLibraryInfo()->addPriorityImports(values.toSet()); + m_metaInfo.itemLibraryInfo()->addPriorityImports(Utils::toSet(values)); } else { addError(tr("Unknown property for Imports %1").arg(name), currentSourceLocation()); setParserState(Error); From c43956ea453b033f58eca82d10c4377d51220f74 Mon Sep 17 00:00:00 2001 From: Ivan Komissarov Date: Tue, 2 Mar 2021 17:02:59 +0300 Subject: [PATCH 21/42] Update Qbs submodule to the top of 1.18 branch Change-Id: Ia684a71c5b460cdbb6617e30ea218e349a8901d1 Reviewed-by: Eike Ziller --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 7b50dca83a5..b9907900069 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 7b50dca83a5a75a5c24b5ef329f25990daf2ff50 +Subproject commit b99079000697268bdf29c8ae09aa9fc02235edfc From 9d72c807f1186bc45f9213a002e6ac861b9fdd84 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 2 Mar 2021 07:04:46 +0100 Subject: [PATCH 22/42] Theme: fix saving default theme on dark systems Change-Id: I08fbe6441b87c05c93ae30f816eb0d6f79bfb4da Reviewed-by: Eike Ziller Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/themechooser.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/plugins/coreplugin/themechooser.cpp b/src/plugins/coreplugin/themechooser.cpp index 2f4127b5a98..13af462167f 100644 --- a/src/plugins/coreplugin/themechooser.cpp +++ b/src/plugins/coreplugin/themechooser.cpp @@ -171,6 +171,12 @@ ThemeChooser::~ThemeChooser() delete d; } +static QString defaultThemeId() +{ + return Theme::systemUsesDarkMode() ? QString(Constants::DEFAULT_DARK_THEME) + : QString(Constants::DEFAULT_THEME); +} + void ThemeChooser::apply() { const int index = d->m_themeComboBox->currentIndex(); @@ -181,9 +187,7 @@ void ThemeChooser::apply() const QString currentThemeId = ThemeEntry::themeSetting().toString(); if (currentThemeId != themeId) { // save filename of selected theme in global config - settings->setValueWithDefault(Constants::SETTINGS_THEME, - themeId, - QString(Constants::DEFAULT_THEME)); + settings->setValueWithDefault(Constants::SETTINGS_THEME, themeId, defaultThemeId()); RestartDialog restartDialog(ICore::dialogParent(), tr("The theme change will take effect after restart.")); restartDialog.exec(); @@ -225,10 +229,8 @@ QList ThemeEntry::availableThemes() Id ThemeEntry::themeSetting() { - auto defaultId = Theme::systemUsesDarkMode() ? Constants::DEFAULT_DARK_THEME - : Constants::DEFAULT_THEME; const Id setting = Id::fromSetting( - ICore::settings()->value(Constants::SETTINGS_THEME, defaultId)); + ICore::settings()->value(Constants::SETTINGS_THEME, defaultThemeId())); const QList themes = availableThemes(); if (themes.empty()) From b4de69795f97e31061af439345c750e6693b475c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 2 Mar 2021 07:22:38 +0100 Subject: [PATCH 23/42] Debugger: Mark elision of long QUrls in Locals and Expressions Fixes: QTCREATORBUG-25404 Change-Id: Ieee42f9239c9ffe88da03765678e1d2c4b6bb11d Reviewed-by: David Schulz (cherry picked from commit 6df27ccbe7a1baa8c0adf6cfb4b7079c22c8ed82) Reviewed-by: Eike Ziller --- share/qtcreator/debugger/qttypes.py | 4 ++-- tests/manual/debugger/simple/simple_test_app.cpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 041a9232555..6b704a9642d 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -1854,7 +1854,7 @@ def qdump__QUrl(d, value): userNameEnc = d.encodeString(userName) hostEnc = d.encodeString(host) - pathEnc = d.encodeString(path) + elided, pathEnc = d.encodeStringHelper(path, d.displayStringLimit) url = d.encodeString(scheme) url += '3a002f002f00' # '://' if len(userNameEnc): @@ -1863,7 +1863,7 @@ def qdump__QUrl(d, value): if port >= 0: url += '3a00' + ''.join(['%02x00' % ord(c) for c in str(port)]) url += pathEnc - d.putValue(url, 'utf16') + d.putValue(url, 'utf16', elided=elided) displayFormat = d.currentItemFormat() if displayFormat == DisplayFormat.Separate: diff --git a/tests/manual/debugger/simple/simple_test_app.cpp b/tests/manual/debugger/simple/simple_test_app.cpp index 5d782d4190e..cbe4294389d 100644 --- a/tests/manual/debugger/simple/simple_test_app.cpp +++ b/tests/manual/debugger/simple/simple_test_app.cpp @@ -3919,11 +3919,13 @@ namespace qurl { void testQUrl() { + QString s("123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_"); + QUrl u(QString("123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_")); QUrl url(QString("http://qt-project.org")); BREAK_HERE; // Check url "http://qt-project.org" QUrl. // Continue. - dummyStatement(&url); + dummyStatement(&url, &u); } } // namespace qurl From d38a49a9d616b02a43b53a7fa7235b6cb368d891 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 3 Mar 2021 00:10:07 +0100 Subject: [PATCH 24/42] CMakeProjectManager: Conform Modules icon The Modules node in the tree of a loaded CMake project looks quite different than the rest of the icons. Also, it is neither available as High-DPI variant nor do we have the original vector graphics for it. Thich change fixes the above issues. Task-number: QTCREATORBUG-25412 Change-Id: I4ad5853330424f9fec2520b8b539a325b6c80176 Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/cmakeprojectnodes.cpp | 4 +- .../images/fileoverlay_modules.png | Bin 0 -> 461 bytes .../images/fileoverlay_modules@2x.png | Bin 0 -> 792 bytes .../projectexplorer/images/session.png | Bin 583 -> 0 bytes .../projectexplorer/projectexplorer.qrc | 3 +- .../projectexplorerconstants.h | 1 + src/tools/iconlister/iconlister.cpp | 2 - src/tools/icons/qtcreatoricons.svg | 65 ++++++++++++++++++ 8 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/plugins/projectexplorer/images/fileoverlay_modules.png create mode 100644 src/plugins/projectexplorer/images/fileoverlay_modules@2x.png delete mode 100644 src/plugins/projectexplorer/images/session.png diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 002a2b82623..211aca4065d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -46,7 +46,9 @@ CMakeInputsNode::CMakeInputsNode(const Utils::FilePath &cmakeLists) : { setPriority(Node::DefaultPriority - 10); // Bottom most! setDisplayName(QCoreApplication::translate("CMakeFilesProjectNode", "CMake Modules")); - setIcon(QIcon(":/projectexplorer/images/session.png")); // TODO: Use a better icon! + static const QIcon modulesIcon = Core::FileIconProvider::directoryIcon( + ProjectExplorer::Constants::FILEOVERLAY_MODULES); + setIcon(modulesIcon); setListInProject(false); } diff --git a/src/plugins/projectexplorer/images/fileoverlay_modules.png b/src/plugins/projectexplorer/images/fileoverlay_modules.png new file mode 100644 index 0000000000000000000000000000000000000000..0ebdea29e5c1833df16ce01fe0282ed0a6dec2d9 GIT binary patch literal 461 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7I14-?iy0XB4ude`@%$Aj z3=9mCC9V-A!TD(=<%vb94CUqJdYO6I#mR{Use1WE>9gP2NHH)lMtQn8hFJ8zopf5e zB~hkze*QDnQ_m-#&{cf0N$QYW9`~lH_KuMe(VIgjscur}n%g@i+GEzSwivavg#lfy z(Q4dn$%$?=B+J6ieXE`S`HvX;zt83qQ#`XKn5bq(1ua(LKJbf|Wmdzx%?~^uo;zDs z>7l=F)t6lkov~$HJ;!t=JYkAz$WutYVI44k&cp{b|33d(@mtRSeP1WzcE;HBgOmSs z6qZ)sbrDtDuFD&Id_V$>> zVV~!h+^(=POfDAoD+{|;uFSAi6CQ%m#dGBBw3Q zh{~E~vU}6^7uoVTRZ>=OxPRrB)lNz~oNu3}9+cF2-Apzv-r42@?}wZfF*1j$MHv_v O7(8A5T-G@yGywqm0LeoD literal 0 HcmV?d00001 diff --git a/src/plugins/projectexplorer/images/fileoverlay_modules@2x.png b/src/plugins/projectexplorer/images/fileoverlay_modules@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..96c940d5c767f131a06666571344759c2d7cd441 GIT binary patch literal 792 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9Fx?I6t9|MX)j z0|SF(iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$QVa}COFdm2Ln2z=PP^|N zoG5YJ{(WNJw6@KW#^F(djf*(aN`hUUotP%t^4Db1iUq6xaj)OQ;l-u(Vp;q(*GX#v z7Ot6~7vvP=Zl&T+WgCmHecW+2_f_ccL)`7(E6@M_JLmhuJ?EJvQ>O&F z{oj4WD@SYT7KW`3i_N|Yyby9~2^VoNwp$>XZ_vtoK>0zdKvG#Gg8wcz5Zbh`+-SK8`&+G*R-};eq(pjt$VN0>ZfkKdbMG*&nm}#KkNkO%yS5wqElOU zQFuboJZ7l|Q@7;Lf&J`EH80+#UU|>n(UkH$N>WNvWeHoLh^p1CbNk-D?O~ya8=5fHIsRU;}@Cpzb{p&Z|FIb7bPJ?_auq=VHjSGlhRGUs!$HdL_IW@LVYR`0aStqf?s27yi^w zzp;I#xYzn`($jpH%p2Skj|4BaR4Es(YB-&7^!eTA=9Sy6*5^z9F-%}zVZBj3u1~$g zL?JGjIVmjYYJm3s_RcG{><3miuKV+>Z<$f~-MHeu z=-Y%HTmR1OU#ru7hb4Jh&p#7~j|+5jUVEgTah-N2b8%C>5x=>~VSPhUDd|~N53?h# ztxJvg8Wk(n&FL2G(-v@|xjFy(uPGBx zKI#yc=t|F7XdIiRyt>P6mAmd0rqDN=mT;6Gv3$PrqU4un$yc}fUyXmqbd>qQ;ea&{ z=6rDsJ8^u~3cU%c-M1&Qnornsf4ZPOQ^w2SOKT?mNLFBvyrm$QZeXj|_%SiBfI0rd zZ=)BU6RP#X-rBGpub4GCS?I<3`PH|+-ad4>x$wl)e@5YKyU#w?x%l%)nuyDe{gu)6 zeiG^yQ;tZR%sBh}j*bSs}@a`?4Kp{hSyW7#KWV{an^LB{Ts5V1)@u diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 76a913e8df1..b09c7e26da0 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -24,7 +24,6 @@ images/debugger_overlay_small@2x.png images/analyzer_overlay_small.png images/analyzer_overlay_small@2x.png - images/session.png images/BuildSettings.png images/CodeStyleSettings.png images/RunSettings.png @@ -67,6 +66,8 @@ images/fileoverlay_product@2x.png images/fileoverlay_group.png images/fileoverlay_group@2x.png + images/fileoverlay_modules.png + images/fileoverlay_modules@2x.png images/fileoverlay_ui.png images/fileoverlay_ui@2x.png images/fileoverlay_scxml.png diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 5bc3a8da3f0..e0f7fa80459 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -215,6 +215,7 @@ const char PROJECTTREE_ID[] = "Projects"; const char FILEOVERLAY_QT[]=":/projectexplorer/images/fileoverlay_qt.png"; const char FILEOVERLAY_GROUP[] = ":/projectexplorer/images/fileoverlay_group.png"; const char FILEOVERLAY_PRODUCT[] = ":/projectexplorer/images/fileoverlay_product.png"; +const char FILEOVERLAY_MODULES[] = ":/projectexplorer/images/fileoverlay_modules.png"; const char FILEOVERLAY_QML[]=":/projectexplorer/images/fileoverlay_qml.png"; const char FILEOVERLAY_UI[]=":/projectexplorer/images/fileoverlay_ui.png"; const char FILEOVERLAY_QRC[]=":/projectexplorer/images/fileoverlay_qrc.png"; diff --git a/src/tools/iconlister/iconlister.cpp b/src/tools/iconlister/iconlister.cpp index e8b9d3eb18d..d3d084e8ca5 100644 --- a/src/tools/iconlister/iconlister.cpp +++ b/src/tools/iconlister/iconlister.cpp @@ -334,8 +334,6 @@ void IconLister::addProjectExplorerIcons() {QIcon(":/projectexplorer/images/category_buildrun.png"), "category_buildrun.png", prefix, ""}, - {QIcon(":/projectexplorer/images/session.png"), "session.png", prefix, - ""}, {QIcon(":/projectexplorer/images/BuildSettings.png"), "BuildSettings.png", prefix, ""}, {QIcon(":/projectexplorer/images/CodeStyleSettings.png"), "CodeStyleSettings.png", prefix, diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index e0bec68332c..bc5658d99cd 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -18,6 +18,18 @@ sodipodi:docname="qtcreatoricons.svg"> + + + + @@ -587,6 +599,15 @@ values="0.66 0 0 0.35 0.0182292 0.02 0.66 0.02 0.35 0.0182292 0.08 0.08 0.66 0.35 0.02 0 0 0 1 0 " id="feColorMatrix2747" /> + + + + + + + + + + + Date: Thu, 25 Feb 2021 11:19:57 +0100 Subject: [PATCH 25/42] QmlDesigner: Fix qmake .pri file Change-Id: I85b8e4e5569879131b0697aa3f4f6e8d1e477fe4 Reviewed-by: Tim Jenssen --- share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri | 1 - 1 file changed, 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri index d0096f86609..81c00b796e0 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri @@ -13,7 +13,6 @@ versionAtLeast(QT_VERSION, 5.15.0) { HEADERS += $$PWD/qt5nodeinstanceserver.h \ $$PWD/capturenodeinstanceserverdispatcher.h \ - $$PWD/capturescenecreatedcommand.h \ $$PWD/nodeinstanceserverdispatcher.h \ $$PWD/qt5captureimagenodeinstanceserver.h \ $$PWD/qt5capturepreviewnodeinstanceserver.h \ From e5a4fdaa1b65beb0ca257ef698f685303b867802 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 1 Mar 2021 13:47:42 +0100 Subject: [PATCH 26/42] Keep -test option even if Qt Creator is built without tests If we remove the -test option, external plugins cannot run their tests with the binary package + development package, even if _they_ are built with WITH_TESTS (or add the plugin tests some other way). Fixes: QTCREATORBUG-24526 Change-Id: I53f4125b52ba625ba37a91237e4826d62c008c2e Reviewed-by: Cristian Adam --- src/libs/extensionsystem/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libs/extensionsystem/CMakeLists.txt b/src/libs/extensionsystem/CMakeLists.txt index 71e5cbd3801..a8424c1df47 100644 --- a/src/libs/extensionsystem/CMakeLists.txt +++ b/src/libs/extensionsystem/CMakeLists.txt @@ -17,3 +17,11 @@ add_qtc_library(ExtensionSystem pluginmanager_p.h SKIP_AUTOMOC pluginmanager.cpp ) + +find_package(Qt5 COMPONENTS Test QUIET) + +extend_qtc_library(ExtensionSystem + CONDITION TARGET Qt5::Test + DEPENDS Qt5::Test + DEFINES WITH_TESTS +) From 60f103b681b84ac3ad2513124f7bd9234b4449cc Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 3 Mar 2021 11:50:37 +0100 Subject: [PATCH 27/42] Utils: Keep editing position in StringAspects with TextDisplay Fixes: QTCREATORBUG-25410 Change-Id: I414c90fe679d9f63bfc29361ab753979ff20bfe6 Reviewed-by: Cristian Adam --- src/libs/utils/aspects.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 645f22e17db..e5f0aba77c1 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -918,7 +918,9 @@ void StringAspect::update() } if (d->m_textEditDisplay) { - d->m_textEditDisplay->setText(displayedString); + const QString old = d->m_textEditDisplay->document()->toPlainText(); + if (displayedString != old) + d->m_textEditDisplay->setText(displayedString); d->updateWidgetFromCheckStatus(d->m_textEditDisplay.data()); } From 2f86e6d7b54d226576ebd52d84b578bb7b623365 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Wed, 3 Mar 2021 14:54:10 +0000 Subject: [PATCH 28/42] fix "qmldesigner: do not use hardcoded path in plugin" -> 6571bd51977ffe130c191a525ce94f9ff1d38a22. Change-Id: I62524ec88fed1d041227cf7d9ac97ff65b24af8a Reviewed-by: Tim Jenssen --- src/plugins/qmldesigner/qmldesignerplugin.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index d8c9f60f5ec..b7f003be676 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -45,8 +45,6 @@ #include #include -#include - #include #include #include @@ -62,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +70,7 @@ #include #include +#include #include #include @@ -232,12 +232,12 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e bool QmlDesignerPlugin::delayedInitialize() { // adding default path to item library plugins - const QString pluginPath = Utils::HostOsInfo::isMacHost() - ? QString(QCoreApplication::applicationDirPath() + "/../PlugIns/QmlDesigner") - : QString(QCoreApplication::applicationDirPath() + "/../" - + QLatin1String(IDE_LIBRARY_BASENAME) + "/" + Core::Constants::IDE_ID - + "/plugins/qmldesigner"); - MetaInfo::setPluginPaths(QStringList(pluginPath)); + const QString postfix = Utils::HostOsInfo::isMacHost() ? "/QmlDesigner" : "/qmldesigner"; + const QStringList pluginPaths = + Utils::transform(ExtensionSystem::PluginManager::pluginPaths(), [postfix](const QString &p) { + return QString(p + postfix); + }); + MetaInfo::setPluginPaths(pluginPaths); d->settings.fromSettings(Core::ICore::settings()); From ffb19f9acfedd1f66c6f1041e3f43ee028bba0f0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 25 Feb 2021 15:21:44 +0100 Subject: [PATCH 29/42] RemoteLinux: Proper support for rsync on Windows The Windows implementations of rsync have some peculiarities. Fixes: QTCREATORBUG-25333 Change-Id: Ic69c7ffb868d25e391501a3e3c1b8d007abca8ae Reviewed-by: Christian Stenger --- src/plugins/remotelinux/rsyncdeploystep.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 7aafa41b46f..65ffce4030b 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -159,8 +159,19 @@ void RsyncDeployService::deployNextFile() } const DeployableFile file = m_deployableFiles.takeFirst(); const RsyncCommandLine cmdLine = RsyncDeployStep::rsyncCommand(*connection(), m_flags); + QString localFilePath = file.localFilePath().toString(); + + // On Windows, rsync is either from msys or cygwin. Neither work with the other's ssh.exe. + if (HostOsInfo::isWindowsHost()) { + localFilePath = '/' + localFilePath.at(0) + localFilePath.mid(2); + if (anyOf(cmdLine.options, [](const QString &opt) { + return opt.contains("cygwin", Qt::CaseInsensitive); })) { + localFilePath.prepend("/cygdrive"); + } + } + const QStringList args = QStringList(cmdLine.options) - << (file.localFilePath().toString() + (file.localFilePath().isDir() ? "/" : QString())) + << (localFilePath + (file.localFilePath().isDir() ? "/" : QString())) << (cmdLine.remoteHostSpec + ':' + file.remoteFilePath()); m_rsync.start("rsync", args); // TODO: Get rsync location from settings? } @@ -228,7 +239,7 @@ RsyncCommandLine RsyncDeployStep::rsyncCommand(const SshConnection &sshConnectio { const QString sshCmdLine = QtcProcess::joinArgs( QStringList{SshSettings::sshFilePath().toUserOutput()} - << sshConnection.connectionOptions(SshSettings::sshFilePath())); + << sshConnection.connectionOptions(SshSettings::sshFilePath()), OsTypeLinux); const SshConnectionParameters sshParams = sshConnection.connectionParameters(); return RsyncCommandLine(QStringList{"-e", sshCmdLine, flags}, sshParams.userName() + '@' + sshParams.host()); From 6fa671b329ffce681f9f522f27491bddd2ab8a15 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 3 Mar 2021 18:07:56 +0100 Subject: [PATCH 30/42] CMakePM: Use UNINITIALIZED for -D= in Batch Edit CMake is setting the UNINITIALIZED type if you forget to set the type of a variable when you do it from command line. Qt Creator was setting INTERNAL, which had the effect of not being displayed in the UI at all, giving the impression that the value has been dropped. Change-Id: I9a6b487bf5062d288365938fd7ef99b49de42884 Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakebuildconfiguration.cpp | 2 +- src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp | 13 ++++++++++--- src/plugins/cmakeprojectmanager/cmakeconfigitem.h | 2 +- src/plugins/cmakeprojectmanager/configmodel.h | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 3f40ca0b92d..7b2d8eb5690 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -519,7 +519,7 @@ void CMakeBuildSettingsWidget::updateButtonState() break; case CMakeProjectManager::ConfigModel::DataItem::UNKNOWN: default: - ni.type = CMakeConfigItem::INTERNAL; + ni.type = CMakeConfigItem::UNINITIALIZED; break; } return ni; diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index f979c283f35..4887bd130dd 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -145,9 +145,11 @@ CMakeConfigItem::Type CMakeConfigItem::typeStringToType(const QByteArray &type) return CMakeConfigItem::PATH; if (type == "STATIC") return CMakeConfigItem::STATIC; + if (type == "INTERNAL") + return CMakeConfigItem::INTERNAL; - QTC_CHECK(type == "INTERNAL" || type == "UNINITIALIZED"); - return CMakeConfigItem::INTERNAL; + QTC_CHECK(type == "UNINITIALIZED"); + return CMakeConfigItem::UNINITIALIZED; } QString CMakeConfigItem::typeToTypeString(const CMakeConfigItem::Type t) @@ -163,8 +165,10 @@ QString CMakeConfigItem::typeToTypeString(const CMakeConfigItem::Type t) return {"INTERNAL"}; case CMakeProjectManager::CMakeConfigItem::STATIC: return {"STATIC"}; - case CMakeConfigItem::BOOL: + case CMakeProjectManager::CMakeConfigItem::BOOL: return {"BOOL"}; + case CMakeProjectManager::CMakeConfigItem::UNINITIALIZED: + return {"UNINITIALIZED"}; } QTC_CHECK(false); return {}; @@ -418,6 +422,9 @@ QString CMakeConfigItem::toString(const Utils::MacroExpander *expander) const case CMakeProjectManager::CMakeConfigItem::INTERNAL: typeStr = QLatin1String("INTERNAL"); break; + case CMakeProjectManager::CMakeConfigItem::UNINITIALIZED: + typeStr = QLatin1String("UNINITIALIZED"); + break; case CMakeProjectManager::CMakeConfigItem::STRING: default: typeStr = QLatin1String("STRING"); diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h index 10c7651f6f7..7da405a48d8 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h @@ -45,7 +45,7 @@ namespace CMakeProjectManager { class CMAKE_EXPORT CMakeConfigItem { public: - enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC }; + enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC, UNINITIALIZED }; CMakeConfigItem(); CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v, const QStringList &s = {}); CMakeConfigItem(const QByteArray &k, const QByteArray &v); diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 8fb621c2ea0..a5cb94612e5 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -101,7 +101,7 @@ public: cmi.type = CMakeConfigItem::STRING; break; case DataItem::UNKNOWN: - cmi.type = CMakeConfigItem::INTERNAL; + cmi.type = CMakeConfigItem::UNINITIALIZED; break; } cmi.isUnset = isUnset; From 60aac50a444382c250d54da381f7c66fc1222b52 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 4 Mar 2021 06:23:57 +0100 Subject: [PATCH 31/42] QmlDesigner: Fix build Amends 2f86e6d7b54d22. Change-Id: I55bdb470137f945267f792a6513ae96afad7aa48 Reviewed-by: David Schulz --- src/plugins/qmldesigner/qmldesignerplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index b7f003be676..1d56ef0e8ce 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -232,7 +232,8 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e bool QmlDesignerPlugin::delayedInitialize() { // adding default path to item library plugins - const QString postfix = Utils::HostOsInfo::isMacHost() ? "/QmlDesigner" : "/qmldesigner"; + const QString postfix = Utils::HostOsInfo::isMacHost() ? QString("/QmlDesigner") + : QString("/qmldesigner"); const QStringList pluginPaths = Utils::transform(ExtensionSystem::PluginManager::pluginPaths(), [postfix](const QString &p) { return QString(p + postfix); From 1ba7c149af2fc0219de81089ab75bce29e1e255b Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Tue, 2 Mar 2021 12:26:40 +0100 Subject: [PATCH 32/42] Enable step functions in the curve-editor ... and shut-up an annoying qDebug log in the transition-editor. Change-Id: Iea8b48e48bb7e52cd4c845f28c49f8a513785fab Reviewed-by: Thomas Hartmann --- .../qmldesigner/components/curveeditor/curveeditor.cpp | 4 +++- .../qmldesigner/components/curveeditor/curveeditorview.cpp | 5 ++--- .../qmldesigner/components/curveeditor/curvesegment.cpp | 7 +++++++ .../components/transitioneditor/transitioneditorview.cpp | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp index 800dc0c523b..23623ae3095 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp @@ -100,7 +100,9 @@ QToolBar *CurveEditor::createToolBar(CurveEditorModel *model) auto setLinearInterpolation = [this]() { m_view->setInterpolation(Keyframe::Interpolation::Linear); }; - auto setStepInterpolation = [this]() { m_view->setInterpolation(Keyframe::Interpolation::Step); }; + auto setStepInterpolation = [this]() { + m_view->setInterpolation(Keyframe::Interpolation::Step); + }; auto setSplineInterpolation = [this]() { m_view->setInterpolation(Keyframe::Interpolation::Bezier); }; diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp index 51fc7c31a32..b885b3d91c5 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp @@ -338,7 +338,8 @@ void CurveEditorView::commitKeyframes(TreeItem *item) group.setValue(QVariant(pos.y()), pos.x()); if (previous.isValid()) { - if (frame.interpolation() == Keyframe::Interpolation::Bezier) { + if (frame.interpolation() == Keyframe::Interpolation::Bezier || + frame.interpolation() == Keyframe::Interpolation::Step ) { CurveSegment segment(previous, frame); if (segment.isValid()) attachEasingCurve(group, pos.x(), segment.easingCurve()); @@ -346,8 +347,6 @@ void CurveEditorView::commitKeyframes(TreeItem *item) QVariant data = frame.data(); if (data.type() == static_cast(QMetaType::QEasingCurve)) attachEasingCurve(group, pos.x(), data.value()); - } else if (frame.interpolation() == Keyframe::Interpolation::Step) { - // Warning: Keyframe::Interpolation::Step not yet implemented } } diff --git a/src/plugins/qmldesigner/components/curveeditor/curvesegment.cpp b/src/plugins/qmldesigner/components/curveeditor/curvesegment.cpp index 75d956c666c..cf2861991bd 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curvesegment.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curvesegment.cpp @@ -294,6 +294,13 @@ void CurveSegment::extend(QPainterPath &path) const QEasingCurve CurveSegment::easingCurve() const { + if (interpolation() == Keyframe::Interpolation::Step) { + QEasingCurve curve; + curve.addCubicBezierSegment(QPointF(0.1, 0.0), QPointF(0.9, 0.0), QPointF(1.0, 0.0)); + curve.addCubicBezierSegment(QPointF(1.0, 0.1), QPointF(1.0, 0.9), QPointF(1.0, 1.0)); + return curve; + } + auto mapPosition = [this](const QPointF &position) { QPointF min = m_left.position(); QPointF max = m_right.position(); diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp index 3b648f5435a..97dc457f39c 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp @@ -110,7 +110,7 @@ void TransitionEditorView::nodeReparented(const ModelNode &node, const ModelNode parent = newPropertyParent.parentModelNode(); - qDebug() << Q_FUNC_INFO << parent; + // qDebug() << Q_FUNC_INFO << parent; if (parent.isValid() && parent.metaInfo().isValid() && parent.metaInfo().isSubclassOf("QtQuick.Transition")) { asyncUpdate(parent); From 28f53a9040a286b5892c619d3b3adbf9165d1358 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 4 Mar 2021 11:57:32 +0100 Subject: [PATCH 33/42] macOS: Fix vanishing controls in Welcome mode with macOS dark mode The example set selector and the search input field were missing some palette tweaks that were done by other classes deriving from WelcomePageFrame. Fixes: QTCREATORBUG-25405 Change-Id: I43a022aa5464a1167f94d26e945de225a436b768 Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/iwelcomepage.cpp | 6 +++--- src/plugins/coreplugin/iwelcomepage.h | 2 ++ src/plugins/coreplugin/welcomepagehelper.cpp | 6 ++++-- src/plugins/qtsupport/gettingstartedwelcomepage.cpp | 4 ++++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/plugins/coreplugin/iwelcomepage.cpp b/src/plugins/coreplugin/iwelcomepage.cpp index e305bbe7d5f..acb59fe9eae 100644 --- a/src/plugins/coreplugin/iwelcomepage.cpp +++ b/src/plugins/coreplugin/iwelcomepage.cpp @@ -58,7 +58,7 @@ IWelcomePage::~IWelcomePage() g_welcomePages.removeOne(this); } -static QPalette buttonPalette(bool isActive, bool isCursorInside, bool forText) +QPalette WelcomePageFrame::buttonPalette(bool isActive, bool isCursorInside, bool forText) { QPalette pal; Theme *theme = Utils::creatorTheme(); @@ -175,8 +175,8 @@ bool WelcomePageButtonPrivate::isActive() const void WelcomePageButtonPrivate::doUpdate(bool cursorInside) { const bool active = isActive(); - q->setPalette(buttonPalette(active, cursorInside, false)); - const QPalette lpal = buttonPalette(active, cursorInside, true); + q->setPalette(WelcomePageFrame::buttonPalette(active, cursorInside, false)); + const QPalette lpal = WelcomePageFrame::buttonPalette(active, cursorInside, true); m_label->setPalette(lpal); if (m_icon) m_icon->setPalette(lpal); diff --git a/src/plugins/coreplugin/iwelcomepage.h b/src/plugins/coreplugin/iwelcomepage.h index bc4ea7878d0..1a89b5df8c4 100644 --- a/src/plugins/coreplugin/iwelcomepage.h +++ b/src/plugins/coreplugin/iwelcomepage.h @@ -68,6 +68,8 @@ public: WelcomePageFrame(QWidget *parent); void paintEvent(QPaintEvent *event) override; + + static QPalette buttonPalette(bool isActive, bool isCursorInside, bool forText); }; class CORE_EXPORT WelcomePageButton : public WelcomePageFrame diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 8e2b3c61a9f..d971712e2f0 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -57,15 +57,17 @@ static QFont sizedFont(int size, const QWidget *widget) SearchBox::SearchBox(QWidget *parent) : WelcomePageFrame(parent) { - QPalette pal; + QPalette pal = buttonPalette(false, false, true); pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundColor)); + // for macOS dark mode + pal.setColor(QPalette::Text, themeColor(Theme::Welcome_TextColor)); + setPalette(pal); m_lineEdit = new FancyLineEdit; m_lineEdit->setFiltering(true); m_lineEdit->setFrame(false); m_lineEdit->setFont(sizedFont(14, this)); m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false); - m_lineEdit->setPalette(pal); auto box = new QHBoxLayout(this); box->setContentsMargins(10, 3, 3, 3); diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index 7a048dfa3e2..6092e8d0cbb 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -287,6 +287,10 @@ public: m_searcher->setPlaceholderText(ExamplesWelcomePage::tr("Search in Examples...")); auto exampleSetSelector = new QComboBox(this); + QPalette pal = exampleSetSelector->palette(); + // for macOS dark mode + pal.setColor(QPalette::Text, Utils::creatorTheme()->color(Theme::Welcome_TextColor)); + exampleSetSelector->setPalette(pal); exampleSetSelector->setMinimumWidth(GridProxyModel::GridItemWidth); exampleSetSelector->setMaximumWidth(GridProxyModel::GridItemWidth); ExampleSetModel *exampleSetModel = m_examplesModel->exampleSetModel(); From 011bc5ce330c79f95deaa811a61b08566c8837c2 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 4 Mar 2021 18:00:02 +0100 Subject: [PATCH 34/42] Core: Hide the horizontal scrollbar in WelcomePage The horizontal scrollbar appears with some certain window sizes. That is most likely due to the column count calculation not taking the vertical scroll bar width into consideration. This change simply prevents the unneeded horizontal scrolbar from sporadically popping up. Change-Id: I2fb4aac0921f4a6627058d3e73af22c1fe6db3b9 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/welcomepagehelper.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index e7b183a964b..a6fd69aed10 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -84,6 +84,7 @@ GridView::GridView(QWidget *parent) setSelectionMode(QAbstractItemView::NoSelection); setFrameShape(QFrame::NoFrame); setGridStyle(Qt::NoPen); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QPalette pal; pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundColor)); From 8c9faaf3e5cc5ee9caec1272c8e30753141d5127 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 5 Mar 2021 11:32:47 +0100 Subject: [PATCH 35/42] CMakePM: Do not issue error message when CMakeCache.txt is missing Only do the backup of the CMakeCache.txt and the file-api json reply directory when they exist. Change-Id: I0fe1098968c5b6b3a8285745452d5a24d7ded638 Reviewed-by: Eike Ziller --- src/plugins/cmakeprojectmanager/fileapireader.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 152f22b468f..0657782c980 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -321,9 +321,10 @@ void FileApiReader::makeBackupConfiguration(bool store) if (!store) std::swap(cmakeCacheTxt, cmakeCacheTxtPrev); - if (!FileUtils::copyIfDifferent(cmakeCacheTxt, cmakeCacheTxtPrev)) - Core::MessageManager::writeFlashing(tr("Failed to copy %1 to %2.") - .arg(cmakeCacheTxt.toString(), cmakeCacheTxtPrev.toString())); + if (cmakeCacheTxt.exists()) + if (!FileUtils::copyIfDifferent(cmakeCacheTxt, cmakeCacheTxtPrev)) + Core::MessageManager::writeFlashing(tr("Failed to copy %1 to %2.") + .arg(cmakeCacheTxt.toString(), cmakeCacheTxtPrev.toString())); } From 69afdcd290d12427fb529cbee4259c96daa12aa6 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 5 Mar 2021 12:20:14 +0100 Subject: [PATCH 36/42] CMakePM: Use case insensitive search for file-api configuration Fixes the case of CMAKE_BUILD_TYPE=RELEASE on Linux, when the project loading would fail due to "Release" build type name used by Qt Creator. Change-Id: I2b1a643df190fd02acc422d154a717ed5cd9ce31 Reviewed-by: Eike Ziller --- src/plugins/cmakeprojectmanager/fileapiparser.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/fileapiparser.cpp b/src/plugins/cmakeprojectmanager/fileapiparser.cpp index 3e0cdc56d89..1e2ccfb0114 100644 --- a/src/plugins/cmakeprojectmanager/fileapiparser.cpp +++ b/src/plugins/cmakeprojectmanager/fileapiparser.cpp @@ -892,7 +892,9 @@ FileApiData FileApiParser::parseData(const QFileInfo &replyFileInfo, const QStri } auto it = std::find_if(codeModels.cbegin(), codeModels.cend(), - [cmakeBuildType](const Configuration& cfg) { return cfg.name == cmakeBuildType; }); + [cmakeBuildType](const Configuration& cfg) { + return QString::compare(cfg.name, cmakeBuildType, Qt::CaseInsensitive) == 0; + }); if (it == codeModels.cend()) { errorMessage = QString("No '%1' CMake configuration found!").arg(cmakeBuildType); qWarning() << errorMessage; From 30da5aafd7469494ae397703a64113b079ee66aa Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 5 Mar 2021 12:28:41 +0100 Subject: [PATCH 37/42] CMake build/Qt6: Automatically disable build of profilers Tracing library does not build with Qt 6. Disable that automatically and also the plugins that depend on it. Add some feature info for the Tracing library, though we usually do not add feature information for libraries in general. Change-Id: I51b6993e30ec69d63a031c7bf404ea3887e14d84 Reviewed-by: Cristian Adam --- cmake/QtCreatorAPI.cmake | 6 +++++- src/libs/tracing/CMakeLists.txt | 2 ++ src/plugins/ctfvisualizer/CMakeLists.txt | 1 + src/plugins/perfprofiler/CMakeLists.txt | 1 + src/plugins/qmlprofiler/CMakeLists.txt | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index c417d3ab9eb..df497f70e93 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -94,7 +94,7 @@ function(qtc_output_binary_dir varName) endfunction() function(add_qtc_library name) - cmake_parse_arguments(_arg "STATIC;OBJECT;SKIP_TRANSLATION;ALLOW_ASCII_CASTS;UNVERSIONED" + cmake_parse_arguments(_arg "STATIC;OBJECT;SKIP_TRANSLATION;ALLOW_ASCII_CASTS;UNVERSIONED;FEATURE_INFO" "DESTINATION;COMPONENT;SOURCES_PREFIX;BUILD_DEFAULT" "CONDITION;DEPENDS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;EXTRA_TRANSLATIONS;PROPERTIES" ${ARGN} ) @@ -110,6 +110,7 @@ function(add_qtc_library name) update_cached_list(__QTC_LIBRARIES "${name}") + condition_info(_extra_text _arg_CONDITION) if (NOT _arg_CONDITION) set(_arg_CONDITION ON) endif() @@ -131,6 +132,9 @@ function(add_qtc_library name) set(_library_enabled OFF) endif() + if(DEFINED _arg_FEATURE_INFO) + add_feature_info("Library ${name}" _library_enabled "${_extra_text}") + endif() if (NOT _library_enabled) return() endif() diff --git a/src/libs/tracing/CMakeLists.txt b/src/libs/tracing/CMakeLists.txt index 9cc68ec149a..b7205527f38 100644 --- a/src/libs/tracing/CMakeLists.txt +++ b/src/libs/tracing/CMakeLists.txt @@ -5,6 +5,8 @@ if (WITH_TESTS) endif() add_qtc_library(Tracing + CONDITION Qt5_VERSION VERSION_LESS 6.0.0 + FEATURE_INFO DEPENDS Utils Qt5::Qml Qt5::Quick PUBLIC_DEPENDS Qt5::Widgets SOURCES ${TEST_SOURCES} diff --git a/src/plugins/ctfvisualizer/CMakeLists.txt b/src/plugins/ctfvisualizer/CMakeLists.txt index 32f1188e3ec..1b4df7f2fa2 100644 --- a/src/plugins/ctfvisualizer/CMakeLists.txt +++ b/src/plugins/ctfvisualizer/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_plugin(CtfVisualizer + CONDITION TARGET Tracing DEPENDS Tracing Qt5::QuickWidgets INCLUDES ${PROJECT_SOURCE_DIR}/src PLUGIN_DEPENDS Core Debugger ProjectExplorer diff --git a/src/plugins/perfprofiler/CMakeLists.txt b/src/plugins/perfprofiler/CMakeLists.txt index 20345cb0389..97f82871f02 100644 --- a/src/plugins/perfprofiler/CMakeLists.txt +++ b/src/plugins/perfprofiler/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_plugin(PerfProfiler + CONDITION TARGET Tracing DEPENDS Tracing Qt5::QuickWidgets PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport SOURCES diff --git a/src/plugins/qmlprofiler/CMakeLists.txt b/src/plugins/qmlprofiler/CMakeLists.txt index 9b465f3e45d..016e874e039 100644 --- a/src/plugins/qmlprofiler/CMakeLists.txt +++ b/src/plugins/qmlprofiler/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_plugin(QmlProfiler + CONDITION TARGET Tracing DEPENDS QmlDebug QmlJS Tracing Qt5::QuickWidgets PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport TextEditor SOURCES From 064da4e0cc199743def9ffec008cfb162b4ad3b6 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 5 Mar 2021 11:56:41 +0100 Subject: [PATCH 38/42] LanguageClient: make typed settings backwards compatible Instead of saving the typed settings in the same list as the generic stdio settings use a separate key. This way the new typed settings won't get misinterpreted and overwritten by running older Qt Creator versions. Change-Id: Ic14dfd978b5577b6ae08735bf811c21fba5ab725 Reviewed-by: Christian Stenger --- .../languageclient/languageclientsettings.cpp | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index fff4b3d9c0e..db793e3c110 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -79,6 +79,7 @@ constexpr char executableKey[] = "executable"; constexpr char argumentsKey[] = "arguments"; constexpr char settingsGroupKey[] = "LanguageClient"; constexpr char clientsKey[] = "clients"; +constexpr char typedClientsKey[] = "typedClients"; constexpr char mimeType[] = "application/language.client.setting"; namespace LanguageClient { @@ -615,16 +616,21 @@ QList LanguageClientSettings::fromSettings(QSettings *settingsIn { settingsIn->beginGroup(settingsGroupKey); QList result; - for (const QVariant& var : settingsIn->value(clientsKey).toList()) { - const QMap &map = var.toMap(); - Utils::Id typeId = Utils::Id::fromSetting(map.value(typeIdKey)); - if (!typeId.isValid()) - typeId = Constants::LANGUAGECLIENT_STDIO_SETTINGS_ID; - if (BaseSettings *settings = generateSettings(typeId)) { - settings->fromMap(var.toMap()); - result << settings; + + for (auto varList : + {settingsIn->value(clientsKey).toList(), settingsIn->value(typedClientsKey).toList()}) { + for (const QVariant &var : varList) { + const QMap &map = var.toMap(); + Utils::Id typeId = Utils::Id::fromSetting(map.value(typeIdKey)); + if (!typeId.isValid()) + typeId = Constants::LANGUAGECLIENT_STDIO_SETTINGS_ID; + if (BaseSettings *settings = generateSettings(typeId)) { + settings->fromMap(map); + result << settings; + } } } + settingsIn->endGroup(); return result; } @@ -659,10 +665,16 @@ void LanguageClientSettings::toSettings(QSettings *settings, const QList &languageClientSettings) { settings->beginGroup(settingsGroupKey); - settings->setValue(clientsKey, Utils::transform(languageClientSettings, - [](const BaseSettings *setting){ - return QVariant(setting->toMap()); - })); + auto transform = [](const QList &settings) { + return Utils::transform(settings, [](const BaseSettings *setting) { + return QVariant(setting->toMap()); + }); + }; + auto isStdioSetting = Utils::equal(&BaseSettings::m_settingsTypeId, + Utils::Id(Constants::LANGUAGECLIENT_STDIO_SETTINGS_ID)); + auto [stdioSettings, typedSettings] = Utils::partition(languageClientSettings, isStdioSetting); + settings->setValue(clientsKey, transform(stdioSettings)); + settings->setValue(typedClientsKey, transform(typedSettings)); settings->endGroup(); } From dfeff5b30d8b8c99dbe0f2d66cda99132e42fafa Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 2 Mar 2021 17:15:59 +0200 Subject: [PATCH 39/42] QmlDesigner: Search also possible imports in item library Possible imports are now also parsed for items in item library. They are only shown in case the search string is not empty. Starting a drag of unimported item will automatically add the import. Added a small manhattanlength check to the start of the drag to avoid unwanted import additions on clicks. Also fixed the item sorting to alphabetical order within categories. Task-number: QDS-3825 Change-Id: I93366182af3fd7eda38bf94d53807393ecf92a08 Reviewed-by: Thomas Hartmann Reviewed-by: Mahmoud Badri --- .../itemLibraryQmlSources/ItemDelegate.qml | 8 ++- .../itemLibraryQmlSources/ItemsView.qml | 35 ++++++++-- .../HelperWidgets/ImagePreviewTooltipArea.qml | 9 ++- .../components/integration/designdocument.cpp | 3 +- .../itemlibrarycategoriesmodel.cpp | 3 + .../itemlibrary/itemlibrarycategory.cpp | 2 + .../itemlibrary/itemlibraryimport.cpp | 66 +++++++++++++++---- .../itemlibrary/itemlibraryimport.h | 20 +++++- .../itemlibrary/itemlibraryitem.cpp | 17 ++++- .../components/itemlibrary/itemlibraryitem.h | 7 +- .../itemlibrary/itemlibraryitemsmodel.cpp | 2 +- .../itemlibrary/itemlibrarymodel.cpp | 65 +++++++++++------- .../components/itemlibrary/itemlibrarymodel.h | 2 + .../itemlibrary/itemlibrarywidget.cpp | 47 ++++++++++--- .../itemlibrary/itemlibrarywidget.h | 5 +- 15 files changed, 228 insertions(+), 63 deletions(-) diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml index f7cf00d92c3..045398205db 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml @@ -29,6 +29,9 @@ import QtQuickDesignerTheme 1.0 import HelperWidgets 2.0 Item { + id: delegateRoot + signal showContextMenu() + Rectangle { anchors.rightMargin: 1 anchors.topMargin: 1 @@ -71,11 +74,12 @@ Item { ImagePreviewTooltipArea { id: mouseRegion - anchors.fill: parent + onShowContextMenu: delegateRoot.showContextMenu() onPressed: { - rootView.startDragAndDrop(itemLibraryEntry) + if (mouse.button === Qt.LeftButton) + rootView.startDragAndDrop(itemLibraryEntry, mapToGlobal(mouse.x, mouse.y)) } } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index 2f792372331..a93bc173a81 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -77,11 +77,14 @@ ScrollView { id: itemsView property string importToRemove: "" + property string importToAdd: "" + property var currentItem: null // called from C++ to close context menu on focus out function closeContextMenu() { - contextMenu.close() + importContextMenu.close() + itemContextMenu.close() } Item { @@ -99,11 +102,11 @@ ScrollView { 2 * cellVerticalMargin + cellVerticalSpacing StudioControls.Menu { - id: contextMenu + id: importContextMenu StudioControls.MenuItem { text: qsTr("Remove Module") - enabled: importToRemove !== "" && importToRemove !== "QtQuick" + enabled: importToRemove !== "" onTriggered: rootView.removeImport(importToRemove) } @@ -119,6 +122,19 @@ ScrollView { onTriggered: itemLibraryModel.collapseAll() } } + + StudioControls.Menu { + id: itemContextMenu + // Workaround for menu item implicit width not properly propagating to menu + width: importMenuItem.implicitWidth + + StudioControls.MenuItem { + id: importMenuItem + text: qsTr("Import Module: ") + importToAdd + enabled: currentItem + onTriggered: rootView.addImportForItem(currentItem) + } + } } Column { @@ -144,8 +160,8 @@ ScrollView { importExpanded = !importExpanded } onShowContextMenu: { - importToRemove = importUsed ? "" : importUrl - contextMenu.popup() + importToRemove = importRemovable ? importUrl : "" + importContextMenu.popup() } Column { @@ -180,6 +196,15 @@ ScrollView { visible: itemVisible width: styleConstants.cellWidth + itemGrid.flexibleWidth height: styleConstants.cellHeight + onShowContextMenu: { + if (!itemUsable) { + importToAdd = itemRequiredImport + if (importToAdd !== "") { + currentItem = itemLibraryEntry + itemContextMenu.popup() + } + } + } } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml index 5921bf50520..0f2f5b69b9e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml @@ -30,12 +30,19 @@ import QtQuick.Layouts 1.0 MouseArea { id: mouseArea + signal showContextMenu() + onExited: tooltipBackend.hideTooltip() onCanceled: tooltipBackend.hideTooltip() - onClicked: forceActiveFocus() onPositionChanged: tooltipBackend.reposition() + onClicked: { + forceActiveFocus() + if (mouse.button === Qt.RightButton) + showContextMenu() + } hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton Timer { interval: 1000 diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index ae4b09bdc41..c626f4baa59 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -370,7 +370,8 @@ void DesignDocument::close() void DesignDocument::updateSubcomponentManager() { Q_ASSERT(m_subComponentManager); - m_subComponentManager->update(QUrl::fromLocalFile(fileName().toString()), currentModel()->imports()); + m_subComponentManager->update(QUrl::fromLocalFile(fileName().toString()), + currentModel()->imports() + currentModel()->possibleImports()); } void DesignDocument::deleteSelected() diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp index 1845c025400..1cc032090e2 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp @@ -127,6 +127,9 @@ void ItemLibraryCategoriesModel::sortCategorySections() }; std::sort(m_categoryList.begin(), m_categoryList.end(), categorySort); + + for (const auto &category : qAsConst(m_categoryList)) + category->sortItems(); } void ItemLibraryCategoriesModel::resetModel() diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp index 1662b0ce966..55ef88a97c6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp @@ -70,6 +70,8 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool * bool itemVisible = item->itemName().toLower().contains(searchText) || item->typeName().toLower().contains(searchText); + if (searchText.isEmpty() && !item->isUsable()) + itemVisible = false; bool itemChanged = item->setVisible(itemVisible); *changed |= itemChanged; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp index f2f22b1b74f..649d879895d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp @@ -28,18 +28,22 @@ namespace QmlDesigner { -ItemLibraryImport::ItemLibraryImport(const Import &import, QObject *parent, bool isUserSection) +ItemLibraryImport::ItemLibraryImport(const Import &import, QObject *parent, SectionType sectionType) : QObject(parent), m_import(import), - m_isUserSection(isUserSection) + m_sectionType(sectionType) { + updateRemovable(); } QString ItemLibraryImport::importName() const { - if (m_isUserSection) + if (m_sectionType == SectionType::User) return userComponentsTitle(); + if (m_sectionType == SectionType::Unimported) + return unimportedComponentsTitle(); + if (importUrl() == "QtQuick") return tr("Default Components"); @@ -48,9 +52,12 @@ QString ItemLibraryImport::importName() const QString ItemLibraryImport::importUrl() const { - if (m_isUserSection) + if (m_sectionType == SectionType::User) return userComponentsTitle(); + if (m_sectionType == SectionType::Unimported) + return unimportedComponentsTitle(); + return m_import.url(); } @@ -61,11 +68,14 @@ bool ItemLibraryImport::importExpanded() const QString ItemLibraryImport::sortingName() const { - if (m_isUserSection) // user components always come first - return "_"; + if (m_sectionType == SectionType::User) + return "_"; // user components always come first + + if (m_sectionType == SectionType::Unimported) + return "zzzzzz"; // Unimported components always come last if (!hasCategories()) // imports with no categories are at the bottom of the list - return "zzzzz" + importName(); + return "zzzzz_" + importName(); return importName(); } @@ -113,6 +123,7 @@ bool ItemLibraryImport::setVisible(bool isVisible) { if (isVisible != m_isVisible) { m_isVisible = isVisible; + emit importVisibleChanged(); return true; } @@ -126,7 +137,11 @@ bool ItemLibraryImport::importVisible() const void ItemLibraryImport::setImportUsed(bool importUsed) { - m_importUsed = importUsed; + if (importUsed != m_importUsed) { + m_importUsed = importUsed; + updateRemovable(); + emit importUsedChanged(); + } } bool ItemLibraryImport::importUsed() const @@ -134,6 +149,11 @@ bool ItemLibraryImport::importUsed() const return m_importUsed; } +bool ItemLibraryImport::importRemovable() const +{ + return m_importRemovable; +} + bool ItemLibraryImport::hasCategories() const { return m_categoryModel.rowCount() > 0; @@ -146,7 +166,10 @@ void ItemLibraryImport::sortCategorySections() void ItemLibraryImport::setImportExpanded(bool expanded) { - m_importExpanded = expanded; + if (expanded != m_importExpanded) { + m_importExpanded = expanded; + emit importExpandChanged(); + } } ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &categoryName) const @@ -159,15 +182,30 @@ ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &catego return nullptr; } -bool ItemLibraryImport::isUserSection() const -{ - return m_isUserSection; -} - // static QString ItemLibraryImport::userComponentsTitle() { return tr("My Components"); } +QString ItemLibraryImport::unimportedComponentsTitle() +{ + return tr("All Other Components"); +} + +ItemLibraryImport::SectionType ItemLibraryImport::sectionType() const +{ + return m_sectionType; +} + +void ItemLibraryImport::updateRemovable() +{ + bool importRemovable = !m_importUsed && m_sectionType == SectionType::Default + && m_import.url() != "QtQuick"; + if (importRemovable != m_importRemovable) { + m_importRemovable = importRemovable; + emit importRemovableChanged(); + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h index c922e984084..8993dfcb8b6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h @@ -41,10 +41,18 @@ class ItemLibraryImport : public QObject Q_PROPERTY(bool importVisible READ importVisible NOTIFY importVisibleChanged FINAL) Q_PROPERTY(bool importUsed READ importUsed NOTIFY importUsedChanged FINAL) Q_PROPERTY(bool importExpanded READ importExpanded WRITE setImportExpanded NOTIFY importExpandChanged FINAL) + Q_PROPERTY(bool importRemovable READ importRemovable NOTIFY importRemovableChanged FINAL) Q_PROPERTY(QObject *categoryModel READ categoryModel NOTIFY categoryModelChanged FINAL) public: - ItemLibraryImport(const Import &import, QObject *parent = nullptr, bool isUserSection = false); + enum class SectionType { + Default, + User, + Unimported + }; + + ItemLibraryImport(const Import &import, QObject *parent = nullptr, + SectionType sectionType = SectionType::Default); QString importName() const; QString importUrl() const; @@ -53,6 +61,7 @@ public: Import importEntry() const; bool importVisible() const; bool importUsed() const; + bool importRemovable() const; bool hasCategories() const; ItemLibraryCategory *getCategorySection(const QString &categoryName) const; @@ -66,21 +75,26 @@ public: void expandCategories(bool expand = true); static QString userComponentsTitle(); + static QString unimportedComponentsTitle(); - bool isUserSection() const; + SectionType sectionType() const; signals: void categoryModelChanged(); void importVisibleChanged(); void importUsedChanged(); void importExpandChanged(); + void importRemovableChanged(); private: + void updateRemovable(); + Import m_import; bool m_importExpanded = true; bool m_isVisible = true; bool m_importUsed = false; - bool m_isUserSection = false; // user components import section + bool m_importRemovable = false; + SectionType m_sectionType = SectionType::Default; ItemLibraryCategoriesModel m_categoryModel; }; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp index 31d5edb57cf..78e06f0b56b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp @@ -27,9 +27,10 @@ namespace QmlDesigner { -ItemLibraryItem::ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, QObject *parent) - : QObject(parent), - m_itemLibraryEntry(itemLibraryEntry) +ItemLibraryItem::ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, bool isUsable, QObject *parent) + : QObject(parent) + , m_itemLibraryEntry(itemLibraryEntry) + , m_isUsable(isUsable) { } @@ -61,6 +62,11 @@ QString ItemLibraryItem::componentPath() const return m_itemLibraryEntry.customComponentSource(); } +QString ItemLibraryItem::requiredImport() const +{ + return m_itemLibraryEntry.requiredImport(); +} + bool ItemLibraryItem::setVisible(bool isVisible) { if (isVisible != m_isVisible) { @@ -77,6 +83,11 @@ bool ItemLibraryItem::isVisible() const return m_isVisible; } +bool ItemLibraryItem::isUsable() const +{ + return m_isUsable; +} + QVariant ItemLibraryItem::itemLibraryEntry() const { return QVariant::fromValue(m_itemLibraryEntry); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h index d7321b11794..564a2a9aa54 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h @@ -43,18 +43,22 @@ class ItemLibraryItem: public QObject Q_PROPERTY(QString itemLibraryIconPath READ itemLibraryIconPath FINAL) Q_PROPERTY(bool itemVisible READ isVisible NOTIFY visibilityChanged FINAL) Q_PROPERTY(QString componentPath READ componentPath FINAL) + Q_PROPERTY(bool itemUsable READ isUsable FINAL) + Q_PROPERTY(QString itemRequiredImport READ requiredImport FINAL) public: - ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, QObject *parent); + ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, bool isImported, QObject *parent); ~ItemLibraryItem() override; QString itemName() const; QString typeName() const; QString itemLibraryIconPath() const; QString componentPath() const; + QString requiredImport() const; bool setVisible(bool isVisible); bool isVisible() const; + bool isUsable() const; QVariant itemLibraryEntry() const; @@ -64,6 +68,7 @@ signals: private: ItemLibraryEntry m_itemLibraryEntry; bool m_isVisible = true; + bool m_isUsable = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp index b9530917241..f4f02d124d6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp @@ -70,7 +70,7 @@ void ItemLibraryItemsModel::addItem(ItemLibraryItem *element) { m_itemList.append(element); - element->setVisible(true); + element->setVisible(element->isUsable()); } const QList> &ItemLibraryItemsModel::items() const diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 25bef1edd4b..a11004d2102 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -167,7 +167,7 @@ void ItemLibraryModel::setSearchText(const QString &searchText) } } -Import entryToImport(const ItemLibraryEntry &entry) +Import ItemLibraryModel::entryToImport(const ItemLibraryEntry &entry) { if (entry.majorVersion() == -1 && entry.minorVersion() == -1) return Import::createFileImport(entry.requiredImport()); @@ -204,46 +204,61 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) bool valid = metaInfo.isValid() && metaInfo.majorVersion() == entry.majorVersion(); bool isItem = valid && metaInfo.isSubclassOf("QtQuick.Item"); - bool forceVisiblity = valid && NodeHints::fromItemLibraryEntry(entry).visibleInLibrary(); + bool forceVisibility = valid && NodeHints::fromItemLibraryEntry(entry).visibleInLibrary(); if (m_flowMode && metaInfo.isValid()) { isItem = metaInfo.isSubclassOf("FlowView.FlowItem") || metaInfo.isSubclassOf("FlowView.FlowWildcard") || metaInfo.isSubclassOf("FlowView.FlowDecision"); - forceVisiblity = isItem; + forceVisibility = isItem; } + bool blocked = false; const DesignerMcuManager &mcuManager = DesignerMcuManager::instance(); if (mcuManager.isMCUProject()) { const QSet blockTypes = mcuManager.bannedItems(); if (blockTypes.contains(QString::fromUtf8(entry.typeName()))) - valid = false; + blocked = true; } - if (valid && (isItem || forceVisiblity) // We can change if the navigator does support pure QObjects - && (entry.requiredImport().isEmpty() - || model->hasImport(entryToImport(entry), true, true))) { - + Import import = entryToImport(entry); + bool hasImport = model->hasImport(import, true, true); + bool isImportPossible = false; + if (!hasImport) + isImportPossible = model->isImportPossible(import, true, true); + bool isUsable = (valid && (isItem || forceVisibility)) + && (entry.requiredImport().isEmpty() || hasImport); + if (!blocked && (isUsable || isImportPossible)) { ItemLibraryImport *importSection = nullptr; - QString catName = entry.category(); - if (catName == ItemLibraryImport::userComponentsTitle()) { - // create an import section for user components - importSection = importByUrl(ItemLibraryImport::userComponentsTitle()); + if (isUsable) { + if (catName == ItemLibraryImport::userComponentsTitle()) { + // create an import section for user components + importSection = importByUrl(ItemLibraryImport::userComponentsTitle()); + if (!importSection) { + importSection = new ItemLibraryImport( + {}, this, ItemLibraryImport::SectionType::User); + m_importList.append(importSection); + importSection->setImportExpanded(loadExpandedState(catName)); + } + } else { + if (catName.startsWith("Qt Quick - ")) + catName = catName.mid(11); // remove "Qt Quick - " + importSection = importByUrl(entry.requiredImport()); + } + } else { + catName = ItemLibraryImport::unimportedComponentsTitle(); + importSection = importByUrl(catName); if (!importSection) { - importSection = new ItemLibraryImport({}, this, true); + importSection = new ItemLibraryImport( + {}, this, ItemLibraryImport::SectionType::Unimported); m_importList.append(importSection); importSection->setImportExpanded(loadExpandedState(catName)); } - } else { - if (catName.startsWith("Qt Quick - ")) - catName = catName.mid(11); // remove "Qt Quick - " - - importSection = importByUrl(entry.requiredImport()); } - if (!importSection) { // should not happen, but just in case + if (!importSection) { qWarning() << __FUNCTION__ << "No import section found! skipping entry: " << entry.name(); continue; } @@ -253,12 +268,12 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) if (!categorySection) { categorySection = new ItemLibraryCategory(catName, importSection); importSection->addCategory(categorySection); - if (!importSection->isUserSection()) + if (importSection->sectionType() == ItemLibraryImport::SectionType::Default) categorySection->setExpanded(loadExpandedState(categorySection->categoryName())); } // create item - auto item = new ItemLibraryItem(entry, categorySection); + auto item = new ItemLibraryItem(entry, isUsable, categorySection); categorySection->addItem(item); } } @@ -300,7 +315,9 @@ ItemLibraryImport *ItemLibraryModel::importByUrl(const QString &importUrl) const if (itemLibraryImport->importUrl() == importUrl || (importUrl.isEmpty() && itemLibraryImport->importUrl() == "QtQuick") || (importUrl == ItemLibraryImport::userComponentsTitle() - && itemLibraryImport->isUserSection())) { + && itemLibraryImport->sectionType() == ItemLibraryImport::SectionType::User) + || (importUrl == ItemLibraryImport::unimportedComponentsTitle() + && itemLibraryImport->sectionType() == ItemLibraryImport::SectionType::Unimported)) { return itemLibraryImport; } } @@ -324,9 +341,11 @@ void ItemLibraryModel::updateVisibility(bool *changed) for (ItemLibraryImport *import : std::as_const(m_importList)) { bool categoryChanged = false; bool hasVisibleItems = import->updateCategoryVisibility(m_searchText, &categoryChanged); - *changed |= categoryChanged; + if (import->sectionType() == ItemLibraryImport::SectionType::Unimported) + *changed |= import->setVisible(!m_searchText.isEmpty()); + // expand import if it has an item matching search criteria if (hasVisibleItems && !import->importExpanded()) import->setImportExpanded(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h index 535bfb014f9..2412550a3a0 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h @@ -69,6 +69,8 @@ public: Q_INVOKABLE void expandAll(); Q_INVOKABLE void collapseAll(); + Import entryToImport(const ItemLibraryEntry &entry); + private: void updateVisibility(bool *changed); void addRoleNames(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 1eb8813bda0..7ce542de024 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -86,15 +86,35 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) QMetaObject::invokeMethod(m_itemViewQuickWidget->rootObject(), "closeContextMenu"); } else if (event->type() == QMouseEvent::MouseMove) { if (m_itemToDrag.isValid()) { - ItemLibraryEntry entry = m_itemToDrag.value(); - auto drag = new QDrag(this); - drag->setPixmap(Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath())); - drag->setMimeData(m_itemLibraryModel->getMimeData(entry)); - drag->exec(); - drag->deleteLater(); + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { + ItemLibraryEntry entry = m_itemToDrag.value(); + // For drag to be handled correctly, we must have the component properly imported + // beforehand, so we import the module immediately when the drag starts + if (!entry.requiredImport().isEmpty()) { + Import import = Import::createLibraryImport(entry.requiredImport()); + if (!m_model->hasImport(import, true, true)) { + const QList possImports = m_model->possibleImports(); + for (const auto &possImport : possImports) { + if (possImport.url() == import.url()) { + m_model->changeImports({possImport}, {}); + break; + } + } + } + } - m_itemToDrag = {}; + auto drag = new QDrag(this); + drag->setPixmap(Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath())); + drag->setMimeData(m_itemLibraryModel->getMimeData(entry)); + drag->exec(); + drag->deleteLater(); + + m_itemToDrag = {}; + } } + } else if (event->type() == QMouseEvent::MouseButtonRelease) { + m_itemToDrag = {}; } return QObject::eventFilter(obj, event); @@ -349,6 +369,7 @@ void ItemLibraryWidget::updateModel() void ItemLibraryWidget::updatePossibleImports(const QList &possibleImports) { m_itemLibraryAddImportModel->update(possibleImports); + delayedUpdateModel(); } void ItemLibraryWidget::updateUsedImports(const QList &usedImports) @@ -387,12 +408,13 @@ void ItemLibraryWidget::setResourcePath(const QString &resourcePath) updateSearch(); } -void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry) +void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos) { // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay // active (and blocks mouse release) if mouse is released at the same spot of the drag start. // This doesn't completely eliminate the bug but makes it significantly harder to produce. m_itemToDrag = itemLibEntry; + m_dragStartPoint = mousePos.toPoint(); } void ItemLibraryWidget::setFlowMode(bool b) @@ -409,6 +431,15 @@ void ItemLibraryWidget::removeImport(const QString &importUrl) m_model->changeImports({}, {importSection->importEntry()}); } +void ItemLibraryWidget::addImportForItem(const QVariant &entry) +{ + QTC_ASSERT(m_itemLibraryModel, return); + QTC_ASSERT(m_model, return); + + Import import = m_itemLibraryModel->entryToImport(entry.value()); + m_model->changeImports({import}, {}); +} + void ItemLibraryWidget::addResources(const QStringList &files) { auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index 66d95d0cd4b..0b78c485e58 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -87,8 +88,9 @@ public: void setModel(Model *model); void setFlowMode(bool b); - Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry); + Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); Q_INVOKABLE void removeImport(const QString &importUrl); + Q_INVOKABLE void addImportForItem(const QVariant &entry); signals: void itemActivated(const QString& itemName); @@ -127,6 +129,7 @@ private: QVariant m_itemToDrag; bool m_updateRetry = false; QString m_filterText; + QPoint m_dragStartPoint; private slots: void handleTabChanged(int index); From fab090907d094d459fda0d4ed0618644584cb9ff Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 5 Mar 2021 13:11:57 +0200 Subject: [PATCH 40/42] QmlDesigner: Remove duplicate sections from item library If there are multiple imports of the same library, only use the highest version to populate item library. Fixes: QDS-3786 Change-Id: I2dd0976c9353692342b390bec15a99554e74aa05 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../itemlibrary/itemlibrarymodel.cpp | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index a11004d2102..4def2f46dc3 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -177,6 +177,28 @@ Import ItemLibraryModel::entryToImport(const ItemLibraryEntry &entry) } +// Returns true if first import version is higher or equal to second import version +static bool compareVersions(const QString &version1, const QString &version2) +{ + if (version2.isEmpty() || version1 == version2) + return true; + const QStringList version1List = version1.split(QLatin1Char('.')); + const QStringList version2List = version2.split(QLatin1Char('.')); + if (version1List.count() == 2 && version2List.count() == 2) { + int major1 = version1List.constFirst().toInt(); + int major2 = version2List.constFirst().toInt(); + if (major1 > major2) { + return true; + } else if (major1 == major2) { + int minor1 = version1List.constLast().toInt(); + int minor2 = version2List.constLast().toInt(); + if (minor1 >= minor2) + return true; + } + } + return false; +} + void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) { if (!model) @@ -190,14 +212,30 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) QString projectName = project ? project->displayName() : ""; // create import sections + QHash importHash; for (const Import &import : model->imports()) { if (import.isLibraryImport() && import.url() != projectName) { - ItemLibraryImport *itemLibImport = new ItemLibraryImport(import, this); - m_importList.append(itemLibImport); - itemLibImport->setImportExpanded(loadExpandedState(import.url())); + bool addNew = true; + ItemLibraryImport *oldImport = importHash.value(import.url()); + if (oldImport && oldImport->importEntry().url() == import.url()) { + // Retain the higher version if multiples exist + if (compareVersions(oldImport->importEntry().version(), import.version())) + addNew = false; + else + delete oldImport; + } + if (addNew) { + ItemLibraryImport *itemLibImport = new ItemLibraryImport(import, this); + importHash.insert(import.url(), itemLibImport); + } } } + for (const auto itemLibImport : qAsConst(importHash)) { + m_importList.append(itemLibImport); + itemLibImport->setImportExpanded(loadExpandedState(itemLibImport->importEntry().url())); + } + const QList itemLibEntries = itemLibraryInfo->entries(); for (const ItemLibraryEntry &entry : itemLibEntries) { NodeMetaInfo metaInfo = model->metaInfo(entry.typeName()); From 5e1f40a3afbaf829a48bb6fbef342cb9b0615663 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 5 Mar 2021 13:25:32 +0100 Subject: [PATCH 41/42] CMake: Don't add standard Linux paths to LD_LIBRARY_PATH If a project specifically links to a library in a standard path (like /usr/lib/...), we do not need to add that path to LD_LIBRARY_PATH. Actually adding it can be harmful if the build needs to link against some other library in a different version than is available in the system path. Common case is linking the application against a Qt version from the online installer. If /usr/lib/... ends up in the LD_LIBRARY_PATH before the path to the Qt from the online installer, the system Qt is picked up at runtime instead of the Qt from the online installer. Fixes: QTCREATORBUG-25292 Change-Id: Ib080e41f5893fb68e9d65cc9c9f11d1a9a60f485 Reviewed-by: Cristian Adam --- .../fileapidataextractor.cpp | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 80ea50c6d0c..1474a8da4da 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -179,6 +179,14 @@ QVector extractBacktraceInformation(const BacktraceInf return info; } +static bool isChildOf(const FilePath &path, const QStringList &prefixes) +{ + for (const QString &prefix : prefixes) + if (path.isChildOf(FilePath::fromString(prefix))) + return true; + return false; +} + QList generateBuildTargets(const PreprocessedData &input, const FilePath &sourceDirectory, const FilePath &buildDirectory) @@ -269,16 +277,28 @@ QList generateBuildTargets(const PreprocessedData &input, if (f.role == "libraries") tmp = tmp.parentDir(); - if (!tmp.isEmpty() - && tmp.isDir()) { // f.role is libraryPath or frameworkPath - librarySeachPaths.append(tmp); - // Libraries often have their import libs in ../lib and the - // actual dll files in ../bin on windows. Qt is one example of that. - if (tmp.fileName() == "lib" && HostOsInfo::isWindowsHost()) { - const FilePath path = tmp.parentDir().pathAppended("bin"); + if (!tmp.isEmpty() && tmp.isDir()) { + // f.role is libraryPath or frameworkPath + // On Linux, exclude sub-paths from "/lib(64)", "/usr/lib(64)" and + // "/usr/local/lib" since these are usually in the standard search + // paths. There probably are more, but the naming schemes are arbitrary + // so we'd need to ask the linker ("ld --verbose | grep SEARCH_DIR"). + if (!HostOsInfo::isLinuxHost() + || !isChildOf(tmp, + {"/lib", + "/lib64", + "/usr/lib", + "/usr/lib64", + "/usr/local/lib"})) { + librarySeachPaths.append(tmp); + // Libraries often have their import libs in ../lib and the + // actual dll files in ../bin on windows. Qt is one example of that. + if (tmp.fileName() == "lib" && HostOsInfo::isWindowsHost()) { + const FilePath path = tmp.parentDir().pathAppended("bin"); - if (path.isDir()) - librarySeachPaths.append(path); + if (path.isDir()) + librarySeachPaths.append(path); + } } } } From 88d1708018d40d471248f053cbf213be4e6944a0 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 5 Mar 2021 16:26:21 +0100 Subject: [PATCH 42/42] Perfparser: Update to HEAD of 4.15 branches Fixes build with Qt 6 Change-Id: I0f0965939a85d5a5d6757c98c968caa20a4c1b82 Reviewed-by: Ulf Hermann --- src/tools/perfparser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/perfparser b/src/tools/perfparser index 37720832aa0..6998eeec65a 160000 --- a/src/tools/perfparser +++ b/src/tools/perfparser @@ -1 +1 @@ -Subproject commit 37720832aa0212c51cbd60f43dda7dc9a4f2f425 +Subproject commit 6998eeec65ad30d67495e71dc3e2486c5a390d32