From 536bb51c5abf69104b4e49dbf068b594ca195435 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 27 Feb 2024 08:43:26 +0100 Subject: [PATCH 01/38] Android: Validate selected Java version Change-Id: If77e5b524fdfea7d87ff4f221ef81d2f723f2f82 Reviewed-by: hjk --- src/plugins/android/androidsettingswidget.cpp | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index ca0ff057dfb..0001c37de5f 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -13,13 +13,14 @@ #include +#include #include #include #include #include #include -#include #include +#include #include #include @@ -203,6 +204,47 @@ enum OpenSslValidation { OpenSslCmakeListsPathExists }; +static expected_str testJavaC(const FilePath &jdkPath) +{ + if (!jdkPath.isReadableDir()) + return make_unexpected(Tr::tr("The selected path does not exist or is not readable.")); + + const FilePath bin = jdkPath.pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX); + + if (!bin.isExecutableFile()) + return make_unexpected( + Tr::tr("The selected path does not contain an executable bin/javac.")); + + QVersionNumber jdkVersion; + + Process javacProcess; + CommandLine cmd(bin, {"-version"}); + javacProcess.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels); + javacProcess.setCommand(cmd); + javacProcess.runBlocking(); + + const QString stdOut = javacProcess.stdOut().trimmed(); + + if (javacProcess.exitCode() != 0) + return make_unexpected( + Tr::tr("The selected path does not contain a valid JDK. (javac -version failed: %1)") + .arg(stdOut)); + + // We expect "javac " where is "major.minor.patch" + if (!stdOut.startsWith("javac ")) + return make_unexpected(Tr::tr("Unexpected output from \"javac -version\": %1").arg(stdOut)); + + jdkVersion = QVersionNumber::fromString(stdOut.mid(6).split('\n').first()); + + if (jdkVersion.isNull() || jdkVersion.majorVersion() != 17) { + return make_unexpected(Tr::tr("Unsupported JDK version (needs to be 17): %1 (parsed: %2)") + .arg(stdOut) + .arg(jdkVersion.toString())); + } + + return {}; +} + AndroidSettingsWidget::AndroidSettingsWidget() { setWindowTitle(Tr::tr("Android Configuration")); @@ -307,6 +349,15 @@ AndroidSettingsWidget::AndroidSettingsWidget() Tr::tr("OpenSSL settings have errors."), openSslDetailsWidget); + m_openJdkLocationPathChooser->setValidationFunction([](const QString &s) { + return Utils::asyncRun([s]() -> expected_str { + expected_str test = testJavaC(FilePath::fromUserInput(s)); + if (!test) + return make_unexpected(test.error()); + return s; + }); + }); + connect(m_openJdkLocationPathChooser, &PathChooser::rawPathChanged, this, &AndroidSettingsWidget::validateJdk); if (androidConfig().openJDKLocation().isEmpty()) @@ -533,10 +584,9 @@ bool AndroidSettingsWidget::isDefaultNdkSelected() const void AndroidSettingsWidget::validateJdk() { androidConfig().setOpenJDKLocation(m_openJdkLocationPathChooser->filePath()); - bool jdkPathExists = androidConfig().openJDKLocation().exists(); - const FilePath bin = androidConfig().openJDKLocation() - .pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX); - m_androidSummary->setPointValid(JavaPathExistsAndWritableRow, jdkPathExists && bin.exists()); + expected_str test = testJavaC(androidConfig().openJDKLocation()); + + m_androidSummary->setPointValid(JavaPathExistsAndWritableRow, test.has_value()); updateUI(); From 7c98f2aa9ea3c1464c490e3dfc9636e7e1f51510 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 17:44:14 +0100 Subject: [PATCH 02/38] Axivion: Unuglify issues view frame BaseTreeView's c'tor calls setFrameStyle(QFrame::NoFrame), that's why the frame was lacking. Bring back the Qt defaults explicitly. Change-Id: If48c97cc0b0afa3fdb71b5ba30284371da35192f Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index a13b63dd3a2..31a03f0d569 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -334,6 +334,8 @@ IssuesWidget::IssuesWidget(QWidget *parent) connect(m_pathGlobFilter, &QLineEdit::textEdited, this, &IssuesWidget::onSearchParameterChanged); m_issuesView = new BaseTreeView(this); + m_issuesView->setFrameShape(QFrame::StyledPanel); // Bring back Qt default + m_issuesView->setFrameShadow(QFrame::Sunken); // Bring back Qt default m_headerView = new IssueHeaderView(this); connect(m_headerView, &IssueHeaderView::sortTriggered, this, &IssuesWidget::onSearchParameterChanged); From 0114933deba8d0f75a9e76f0699358748e8be33d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 20:59:11 +0100 Subject: [PATCH 03/38] AndroidRunWorker: Remove redundant variables Change-Id: I6677ce5d4640fdd68d3571d833f9c3651068facc Reviewed-by: hjk Reviewed-by: --- src/plugins/android/androidrunnerworker.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 6cba25a0179..7452e975811 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -819,15 +819,13 @@ void AndroidRunnerWorker::removeForwardPort(const QString &port) void AndroidRunnerWorker::onProcessIdChanged(PidUserPair pidUser) { - qint64 pid = pidUser.first; - qint64 user = pidUser.second; // Don't write to m_psProc from a different thread QTC_ASSERT(QThread::currentThread() == thread(), return); qCDebug(androidRunWorkerLog) << "Process ID changed from:" << m_processPID - << "to:" << pid; - m_processPID = pid; - m_processUser = user; - if (pid == -1) { + << "to:" << pidUser.first; + m_processPID = pidUser.first; + m_processUser = pidUser.second; + if (m_processPID == -1) { emit remoteProcessFinished(QLatin1String("\n\n") + Tr::tr("\"%1\" died.") .arg(m_packageName)); // App died/killed. Reset log, monitor, jdb & gdbserver/lldb-server processes. From e95ad3778fef7bf198bc8296e3c5ba1894ae0e1a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 21:02:42 +0100 Subject: [PATCH 04/38] AndroidRunnerWorker: Avoid deleting process directly from its handler Task-number: QTCREATORBUG-29928 Change-Id: If25c742e57ddaa90ed3342d09dafe626288f0783 Reviewed-by: hjk --- src/plugins/android/androidrunnerworker.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 7452e975811..d18f645165f 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -850,7 +850,10 @@ void AndroidRunnerWorker::onProcessIdChanged(PidUserPair pidUser) QTC_ASSERT(m_psIsAlive, return); m_psIsAlive->setObjectName("IsAliveProcess"); m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels); - connect(m_psIsAlive.get(), &Process::done, this, [this] { onProcessIdChanged({-1, -1}); }); + connect(m_psIsAlive.get(), &Process::done, this, [this] { + m_psIsAlive.release()->deleteLater(); + onProcessIdChanged({-1, -1}); + }); } } From 4dcba2ad259514fe21cda500120c05e0f7d1f094 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 27 Feb 2024 08:27:06 +0100 Subject: [PATCH 05/38] Core: Correct log view thread handling Fixes a crash when log messages are received from multiple threads. Fixes: QTCREATORBUG-30444 Change-Id: I51c78656da1dd30bcb51a801083d1714e474d8e5 Reviewed-by: Marcus Tillmanns --- src/plugins/coreplugin/loggingviewer.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/loggingviewer.cpp b/src/plugins/coreplugin/loggingviewer.cpp index 5e83c76df3e..d6aad897148 100644 --- a/src/plugins/coreplugin/loggingviewer.cpp +++ b/src/plugins/coreplugin/loggingviewer.cpp @@ -559,10 +559,16 @@ private: const QString timestamp = QDateTime::currentDateTime().toString("HH:mm:ss.zzz"); - if (rowCount() >= 1000000) // limit log to 1000000 items - destroyItem(itemForIndex(index(0, 0))); + auto append = [this, timestamp, type, category, msg] { + if (rowCount() >= 1000000) // limit log to 1000000 items + destroyItem(itemForIndex(index(0, 0))); + appendItem(LogEntry{timestamp, messageTypeToString(type), category, msg}); + }; - appendItem(LogEntry{timestamp, messageTypeToString(type), category, msg}); + if (QThread::currentThread() != thread()) + QMetaObject::invokeMethod(this, append, Qt::QueuedConnection); + else + append(); } private: From 82399ac9c54dcdbe03e4240c5b2ffe6850a95afd Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 27 Feb 2024 08:34:28 +0100 Subject: [PATCH 06/38] ClangFormat: Fix compile against latest llvm main branch Change-Id: I6fe414721103d00eb3212040c1aafa2ef123b9d1 Reviewed-by: Artem Sokolovskii Reviewed-by: --- src/plugins/clangformat/clangformatutils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 4036d34f6dc..747c30c2a57 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -59,9 +59,14 @@ clang::format::FormatStyle calculateQtcStyle() style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; style.AllowShortLoopsOnASingleLine = false; - style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; style.AlwaysBreakBeforeMultilineStrings = false; +#if LLVM_VERSION_MAJOR >= 19 + style.BreakAfterReturnType = FormatStyle::RTBS_None; + style.BreakTemplateDeclarations = FormatStyle::BTDS_Yes; +#else + style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; +#endif style.BinPackArguments = false; style.BinPackParameters = false; style.BraceWrapping.AfterClass = true; From 5152a35048b7800ff8b10e1f254357a046a9543e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 27 Feb 2024 12:00:51 +0100 Subject: [PATCH 07/38] Axivion: Change the credential key Make it user @ server. Change-Id: I62e2c88ade5cc984ba11f718c3db292e4075e5e4 Reviewed-by: Andreas Loth Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index c559e2b7d3a..20e7871b14e 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -122,7 +122,7 @@ static QString credentialKey() QString escaped = string; return escaped.replace('\\', "\\\\").replace('@', "\\@"); }; - return escape(settings().server.dashboard) + '@' + escape(settings().server.username); + return escape(settings().server.username) + '@' + escape(settings().server.dashboard); } static DashboardInfo toDashboardInfo(const QUrl &source, const Dto::DashboardInfoDto &infoDto) From a57a925b76785c1269ca5bcbacd553f01c0f238d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 12 Feb 2024 14:03:00 +0100 Subject: [PATCH 08/38] Debugger: defer type look up Change-Id: I425c2bfc3c88ebf46af161c5434c0c05a3bb9c97 Reviewed-by: Christian Stenger --- share/qtcreator/debugger/cdbbridge.py | 493 +++++++++++++++++++++++-- share/qtcreator/debugger/dumper.py | 68 ++-- share/qtcreator/debugger/lldbbridge.py | 2 +- src/libs/qtcreatorcdbext/pytype.cpp | 46 +-- src/libs/qtcreatorcdbext/pytype.h | 1 + 5 files changed, 533 insertions(+), 77 deletions(-) diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py index d323714ba44..b5fc683cbae 100644 --- a/share/qtcreator/debugger/cdbbridge.py +++ b/share/qtcreator/debugger/cdbbridge.py @@ -11,7 +11,7 @@ from utils import TypeCode sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) -from dumper import DumperBase, SubItem +from dumper import DumperBase, SubItem, Children, DisplayFormat, UnnamedSubItem class FakeVoidType(cdbext.Type): @@ -84,10 +84,9 @@ class Dumper(DumperBase): self.check(isinstance(nativeValue, cdbext.Value)) val = self.Value(self) val.name = nativeValue.name() - val._type = self.fromNativeType(nativeValue.type()) # There is no cdb api for the size of bitfields. # Workaround this issue by parsing the native debugger text for integral types. - if val._type.code == TypeCode.Integral: + if nativeValue.type().code() == TypeCode.Integral: try: integerString = nativeValue.nativeDebuggerValue() except UnicodeDecodeError: @@ -106,16 +105,18 @@ class Dumper(DumperBase): base = 16 else: base = 10 - signed = not val._type.name.startswith('unsigned') + signed = not nativeValue.type().name().startswith('unsigned') try: - val.ldata = int(integerString, base).to_bytes(val._type.size(), + val.ldata = int(integerString, base).to_bytes((nativeValue.type().bitsize() +7) // 8, byteorder='little', signed=signed) except: # read raw memory in case the integerString can not be interpreted pass - if val._type.code == TypeCode.Enum: + if nativeValue.type().code() == TypeCode.Enum: val.ldisplay = self.enumValue(nativeValue) - val.isBaseClass = val.name == val._type.name + elif not nativeValue.type().resolved and nativeValue.type().code() == TypeCode.Struct and not nativeValue.hasChildren(): + val.ldisplay = self.enumValue(nativeValue) + val.isBaseClass = val.name == nativeValue.type().name() val.nativeValue = nativeValue val.laddress = nativeValue.address() val.lbitsize = nativeValue.bitsize() @@ -136,6 +137,9 @@ class Dumper(DumperBase): for f in nativeType.fields()]) return typeId + def nativeValueType(self, nativeValue): + return self.fromNativeType(nativeValue.type()) + def fromNativeType(self, nativeType): self.check(isinstance(nativeType, cdbext.Type)) typeId = self.nativeTypeId(nativeType) @@ -150,51 +154,66 @@ class Dumper(DumperBase): if nativeType.name().startswith(''): code = TypeCode.Function elif nativeType.targetName() != nativeType.name(): - targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId()) - if targetType is not None and targetType is not nativeType: - return self.createPointerType(targetType) + return self.createPointerType(nativeType.targetName()) if code == TypeCode.Array: # cdb reports virtual function tables as arrays those ar handled separetly by # the DumperBase. Declare those types as structs prevents a lookup to a # none existing type if not nativeType.name().startswith('__fptr()') and not nativeType.name().startswith(' 0: namespace = name[:namespaceIndex + 2] + self.qtNamespace = lambda: namespace self.qtCustomEventFunc = self.parseAndEvaluate( '%s!%sQObject::customEvent' % (self.qtCoreModuleName(), namespace)).address() @@ -498,7 +518,7 @@ class Dumper(DumperBase): else: val = self.Value(self) val.laddress = value.pointer() - val._type = value.type.dereference() + val._type = DumperBase.Type(self, value.type.targetName) val.nativeValue = value.nativeValue return val @@ -519,3 +539,424 @@ class Dumper(DumperBase): def symbolAddress(self, symbolName): res = self.nativeParseAndEvaluate(symbolName) return None if res is None else res.address() + + def putItemX(self, value): + #DumperBase.warn('PUT ITEM: %s' % value.stringify()) + + typeobj = value.type # unqualified() + typeName = typeobj.name + + self.addToCache(typeobj) # Fill type cache + + if not value.lIsInScope: + self.putSpecialValue('optimizedout') + #self.putType(typeobj) + #self.putSpecialValue('outofscope') + self.putNumChild(0) + return + + if not isinstance(value, self.Value): + raise RuntimeError('WRONG TYPE IN putItem: %s' % type(self.Value)) + + # Try on possibly typedefed type first. + if self.tryPutPrettyItem(typeName, value): + if typeobj.code == TypeCode.Pointer: + self.putOriginalAddress(value.address()) + else: + self.putAddress(value.address()) + return + + if typeobj.code == TypeCode.Pointer: + self.putFormattedPointer(value) + return + + self.putAddress(value.address()) + if value.lbitsize is not None: + self.putField('size', value.lbitsize // 8) + + if typeobj.code == TypeCode.Function: + #DumperBase.warn('FUNCTION VALUE: %s' % value) + self.putType(typeobj) + self.putSymbolValue(value.pointer()) + self.putNumChild(0) + return + + if typeobj.code == TypeCode.Enum: + #DumperBase.warn('ENUM VALUE: %s' % value.stringify()) + self.putType(typeobj.name) + self.putValue(value.display()) + self.putNumChild(0) + return + + if typeobj.code == TypeCode.Array: + #DumperBase.warn('ARRAY VALUE: %s' % value) + self.putCStyleArray(value) + return + + if typeobj.code == TypeCode.Integral: + #DumperBase.warn('INTEGER: %s %s' % (value.name, value)) + val = value.value() + self.putNumChild(0) + self.putValue(val) + self.putType(typeName) + return + + if typeobj.code == TypeCode.Float: + #DumperBase.warn('FLOAT VALUE: %s' % value) + self.putValue(value.value()) + self.putNumChild(0) + self.putType(typeobj.name) + return + + if typeobj.code in (TypeCode.Reference, TypeCode.RValueReference): + #DumperBase.warn('REFERENCE VALUE: %s' % value) + val = value.dereference() + if val.laddress != 0: + self.putItem(val) + else: + self.putSpecialValue('nullreference') + self.putBetterType(typeName) + return + + if typeobj.code == TypeCode.Complex: + self.putType(typeobj) + self.putValue(value.display()) + self.putNumChild(0) + return + + self.putType(typeName) + + if value.summary is not None and self.useFancy: + self.putValue(self.hexencode(value.summary), 'utf8:1:0') + self.putNumChild(0) + return + + self.putExpandable() + self.putEmptyValue() + #DumperBase.warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address())) + if self.showQObjectNames: + #with self.timer(self.currentIName): + self.putQObjectNameValue(value) + if self.isExpanded(): + self.putField('sortable', 1) + with Children(self): + baseIndex = 0 + for item in self.listValueChildren(value): + if item.name.startswith('__vfptr'): + with SubItem(self, '[vptr]'): + # int (**)(void) + self.putType(' ') + self.putSortGroup(20) + self.putValue(item.name) + n = 100 + if self.isExpanded(): + with Children(self): + n = self.putVTableChildren(item, n) + self.putNumChild(n) + continue + + if item.isBaseClass: + baseIndex += 1 + # We cannot use nativeField.name as part of the iname as + # it might contain spaces and other strange characters. + with UnnamedSubItem(self, "@%d" % baseIndex): + self.putField('iname', self.currentIName) + self.putField('name', '[%s]' % item.name) + self.putSortGroup(1000 - baseIndex) + self.putAddress(item.address()) + self.putItem(item) + continue + + + with SubItem(self, item.name): + self.putItem(item) + if self.showQObjectNames: + self.tryPutQObjectGuts(value) + + + def putFormattedPointerX(self, value: DumperBase.Value): + self.putOriginalAddress(value.address()) + pointer = value.pointer() + self.putAddress(pointer) + if pointer == 0: + self.putType(value.type) + self.putValue('0x0') + return + + typeName = value.type.name + + try: + self.readRawMemory(pointer, 1) + except: + # Failure to dereference a pointer should at least + # show the value of a pointer. + #DumperBase.warn('BAD POINTER: %s' % value) + self.putValue('0x%x' % pointer) + self.putType(typeName) + return + + if self.currentIName.endswith('.this'): + self.putDerefedPointer(value) + return + + displayFormat = self.currentItemFormat(value.type.name) + + if value.type.targetName == 'void': + #DumperBase.warn('VOID POINTER: %s' % displayFormat) + self.putType(typeName) + self.putSymbolValue(pointer) + return + + if displayFormat == DisplayFormat.Raw: + # Explicitly requested bald pointer. + #DumperBase.warn('RAW') + self.putType(typeName) + self.putValue('0x%x' % pointer) + self.putExpandable() + if self.currentIName in self.expandedINames: + with Children(self): + with SubItem(self, '*'): + self.putItem(value.dereference()) + return + + limit = self.displayStringLimit + if displayFormat in (DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String): + limit = 1000000 + if self.tryPutSimpleFormattedPointer(pointer, typeName, + value.type.targetName, displayFormat, limit): + self.putExpandable() + return + + if DisplayFormat.Array10 <= displayFormat and displayFormat <= DisplayFormat.Array10000: + n = (10, 100, 1000, 10000)[displayFormat - DisplayFormat.Array10] + self.putType(typeName) + self.putItemCount(n) + self.putArrayData(value.pointer(), n, value.type.targetName) + return + + #DumperBase.warn('AUTODEREF: %s' % self.autoDerefPointers) + #DumperBase.warn('INAME: %s' % self.currentIName) + if self.autoDerefPointers: + # Generic pointer type with AutomaticFormat, but never dereference char types: + if value.type.targetName not in ( + 'char', + 'signed char', + 'int8_t', + 'qint8', + 'unsigned char', + 'uint8_t', + 'quint8', + 'wchar_t', + 'CHAR', + 'WCHAR', + 'char8_t', + 'char16_t', + 'char32_t' + ): + self.putDerefedPointer(value) + return + + #DumperBase.warn('GENERIC PLAIN POINTER: %s' % value.type) + #DumperBase.warn('ADDR PLAIN POINTER: 0x%x' % value.laddress) + self.putType(typeName) + self.putSymbolValue(pointer) + self.putExpandable() + if self.currentIName in self.expandedINames: + with Children(self): + with SubItem(self, '*'): + self.putItem(value.dereference()) + + + def putCStyleArray(self, value): + arrayType = value.type + innerType = arrayType.ltarget + address = value.address() + if address: + self.putValue('@0x%x' % address, priority=-1) + else: + self.putEmptyValue() + self.putType(arrayType) + + displayFormat = self.currentItemFormat() + arrayByteSize = arrayType.size() + n = self.arrayItemCountFromTypeName(value.type.name, 100) + + p = value.address() + if displayFormat != DisplayFormat.Raw and p: + if innerType.name in ( + 'char', + 'int8_t', + 'qint8', + 'wchar_t', + 'unsigned char', + 'uint8_t', + 'quint8', + 'signed char', + 'CHAR', + 'WCHAR', + 'char8_t', + 'char16_t', + 'char32_t' + ): + self.putCharArrayHelper(p, n, innerType, self.currentItemFormat(), + makeExpandable=False) + else: + self.tryPutSimpleFormattedPointer(p, arrayType, innerType, + displayFormat, arrayByteSize) + self.putNumChild(n) + + if self.isExpanded(): + if n > 100: + addrStep = innerType.size() + with Children(self, n, innerType, addrBase=address, addrStep=addrStep): + for i in self.childRange(): + self.putSubItem(i, self.createValue(address + i * addrStep, innerType)) + else: + with Children(self): + n = 0 + for item in self.listValueChildren(value): + with SubItem(self, n): + n += 1 + self.putItem(item) + + + def putArrayData(self, base, n, innerType, childNumChild=None): + self.checkIntType(base) + self.checkIntType(n) + addrBase = base + innerType = self.createType(innerType) + innerSize = innerType.size() + self.putNumChild(n) + #DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType)) + enc = innerType.simpleEncoding() + maxNumChild = self.maxArrayCount() + if enc: + self.put('childtype="%s",' % innerType.name) + self.put('addrbase="0x%x",' % addrBase) + self.put('addrstep="0x%x",' % innerSize) + self.put('arrayencoding="%s",' % enc) + self.put('endian="%s",' % self.packCode) + if n > maxNumChild: + self.put('childrenelided="%s",' % n) + n = maxNumChild + self.put('arraydata="') + self.put(self.readMemory(addrBase, n * innerSize)) + self.put('",') + else: + with Children(self, n, innerType, childNumChild, maxNumChild, + addrBase=addrBase, addrStep=innerSize): + for i in self.childRange(): + self.putSubItem(i, self.createValue(addrBase + i * innerSize, innerType)) + + def tryPutSimpleFormattedPointer(self, ptr, typeName, innerType, displayFormat, limit): + if isinstance(innerType, self.Type): + innerType = innerType.name + if displayFormat == DisplayFormat.Automatic: + if innerType in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'): + # Use UTF-8 as default for char *. + self.putType(typeName) + (length, shown, data) = self.readToFirstZero(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + if self.isExpanded(): + self.putArrayData(ptr, shown, innerType) + return True + + if innerType in ('wchar_t', 'WCHAR'): + self.putType(typeName) + charSize = self.lookupType('wchar_t').size() + (length, data) = self.encodeCArray(ptr, charSize, limit) + if charSize == 2: + self.putValue(data, 'utf16', length=length) + else: + self.putValue(data, 'ucs4', length=length) + return True + + if displayFormat == DisplayFormat.Latin1String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) + return True + + if displayFormat == DisplayFormat.SeparateLatin1String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) + self.putDisplay('latin1:separate', data) + return True + + if displayFormat == DisplayFormat.Utf8String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + return True + + if displayFormat == DisplayFormat.SeparateUtf8String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + self.putDisplay('utf8:separate', data) + return True + + if displayFormat == DisplayFormat.Local8BitString: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'local8bit', length=length) + return True + + if displayFormat == DisplayFormat.Utf16String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 2, limit) + self.putValue(data, 'utf16', length=length) + return True + + if displayFormat == DisplayFormat.Ucs4String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 4, limit) + self.putValue(data, 'ucs4', length=length) + return True + + return False + + def putDerefedPointer(self, value): + derefValue = value.dereference() + savedCurrentChildType = self.currentChildType + self.currentChildType = value.type.targetName + self.putType(value.type.targetName) + derefValue.name = '*' + derefValue.autoDerefCount = value.autoDerefCount + 1 + + if derefValue.type.code == TypeCode.Pointer: + self.putField('autoderefcount', '{}'.format(derefValue.autoDerefCount)) + + self.putItem(derefValue) + self.currentChildType = savedCurrentChildType + + def extractPointer(self, value): + code = 'I' if self.ptrSize() == 4 else 'Q' + return self.extractSomething(value, code, 8 * self.ptrSize()) + + def createValue(self, datish, typish): + if self.isInt(datish): # Used as address. + return self.createValueFromAddressAndType(datish, typish) + if isinstance(datish, bytes): + val = self.Value(self) + if isinstance(typish, self.Type): + val._type = typish + else: + val._type = self.Type(self, typish) + #DumperBase.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish))) + val.ldata = datish + val.check() + return val + raise RuntimeError('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish)) + + def createValueFromAddressAndType(self, address, typish): + val = self.Value(self) + if isinstance(typish, self.Type): + val._type = typish + else: + val._type = self.Type(self, typish) + val.laddress = address + if self.useDynamicType: + val._type = val.type.dynamicType(address) + return val diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 2fa7d31da50..836b1860cb2 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -3041,7 +3041,7 @@ class DumperBase(): or self.type.name.startswith('unsigned ') \ or self.type.name.find(' unsigned ') != -1 if bitsize is None: - bitsize = self.type.bitsize() + bitsize = self.type.lbitsize return self.extractInteger(bitsize, unsigned) def floatingPoint(self): @@ -3512,26 +3512,40 @@ class DumperBase(): tdata.moduleName = self.moduleName return tdata + @property + def bitsize(self): + if callable(self.lbitsize): + self.lbitsize = self.lbitsize() + return self.lbitsize + class Type(): def __init__(self, dumper, typeId): - self.typeId = typeId + self.typeId = typeId.replace('@', dumper.qtNamespace()) self.dumper = dumper - self.tdata = dumper.typeData.get(typeId, None) - if self.tdata is None: - #DumperBase.warn('USING : %s' % self.typeId) - self.dumper.lookupType(self.typeId) - self.tdata = self.dumper.typeData.get(self.typeId) + self.initialized = False def __str__(self): #return self.typeId return self.stringify() + @property + def tdata(self): + if not self.initialized: + self.initialized = True + self.data = self.dumper.typeData.get(self.typeId, None) + if self.data is None: + #DumperBase.warn('USING : %s' % self.typeId) + self.dumper.lookupType(self.typeId) + self.data = self.dumper.typeData.get(self.typeId) + return self.data + + def setTdata(self, tdata): + self.initialized = True + self.data = tdata + @property def name(self): - tdata = self.dumper.typeData.get(self.typeId) - if tdata is None: - return self.typeId - return tdata.name + return self.typeId if self.tdata is None else self.tdata.name @property def code(self): @@ -3539,7 +3553,7 @@ class DumperBase(): @property def lbitsize(self): - return self.tdata.lbitsize + return self.tdata.bitsize @property def lbitpos(self): @@ -3547,15 +3561,25 @@ class DumperBase(): @property def ltarget(self): + if isinstance(self.tdata.ltarget, str): + self.tdata.ltarget = self.dumper.createType(self.tdata.ltarget) return self.tdata.ltarget + @property + def targetName(self): + if self.tdata.ltarget is None: + return '' + return self.tdata.ltarget if isinstance(self.tdata.ltarget, str) else self.tdata.ltarget.name + @property def moduleName(self): + if callable(self.tdata.moduleName): + self.tdata.moduleName = self.tdata.moduleName() return self.tdata.moduleName def stringify(self): return 'Type(name="%s",bsize=%s,code=%s)' \ - % (self.tdata.name, self.tdata.lbitsize, self.tdata.code) + % (self.tdata.name, self.lbitsize, self.tdata.code) def __getitem__(self, index): if self.dumper.isInt(index): @@ -3659,7 +3683,7 @@ class DumperBase(): def alignment(self): if self.tdata.code == TypeCode.Typedef: - return self.tdata.ltarget.alignment() + return self.ltarget.alignment() if self.tdata.code in (TypeCode.Integral, TypeCode.Float, TypeCode.Enum): if self.tdata.name in ('double', 'long long', 'unsigned long long'): # Crude approximation. @@ -3678,7 +3702,7 @@ class DumperBase(): return self.dumper.createPointerType(self) def target(self): - return self.tdata.ltarget + return self.ltarget def stripTypedefs(self): if isinstance(self, self.dumper.Type) and self.code != TypeCode.Typedef: @@ -3687,7 +3711,7 @@ class DumperBase(): return self.ltarget def size(self): - bs = self.bitsize() + bs = self.lbitsize if bs % 8 != 0: DumperBase.warn('ODD SIZE: %s' % self) return (7 + bs) >> 3 @@ -3797,12 +3821,12 @@ class DumperBase(): return val def createPointerType(self, targetType): - if not isinstance(targetType, self.Type): - raise RuntimeError('Expected type in createPointerType(), got %s' + if not isinstance(targetType, (str, self.Type)): + raise RuntimeError('Expected type or str in createPointerType(), got %s' % type(targetType)) - typeId = targetType.typeId + ' *' + typeId = (targetType if isinstance(targetType, str) else targetType.typeId) + ' *' tdata = self.TypeData(self, typeId) - tdata.name = targetType.name + '*' + tdata.name = (targetType if isinstance(targetType, str) else targetType.name) + '*' tdata.lbitsize = 8 * self.ptrSize() tdata.code = TypeCode.Pointer tdata.ltarget = targetType @@ -3927,7 +3951,7 @@ class DumperBase(): tdata = self.typeData.get(typish, None) if tdata is not None: if tdata.lbitsize is not None: - if tdata.lbitsize > 0: + if callable(tdata.lbitsize) or tdata.lbitsize > 0: return self.Type(self, typish) knownType = self.lookupType(typish) @@ -3944,7 +3968,7 @@ class DumperBase(): if typish.endswith('*'): tdata.code = TypeCode.Pointer tdata.lbitsize = 8 * self.ptrSize() - tdata.ltarget = self.createType(typish[:-1].strip()) + tdata.ltarget = typish[:-1].strip() typeobj = self.Type(self, tdata.typeId) #DumperBase.warn('CREATE TYPE: %s' % typeobj.stringify()) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 7558bcdfa47..c6aae0c2e48 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -419,7 +419,7 @@ class Dumper(DumperBase): targetTypeName = typeName[0:pos1].strip() #DumperBase.warn("TARGET TYPENAME: %s" % targetTypeName) targetType = self.fromNativeType(nativeTargetType) - targetType.tdata = targetType.tdata.copy() + targetType.setTdata(targetType.tdata.copy()) targetType.tdata.name = targetTypeName return self.createArrayType(targetType, count) if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x diff --git a/src/libs/qtcreatorcdbext/pytype.cpp b/src/libs/qtcreatorcdbext/pytype.cpp index 0621793b7e0..9345c1d91af 100644 --- a/src/libs/qtcreatorcdbext/pytype.cpp +++ b/src/libs/qtcreatorcdbext/pytype.cpp @@ -121,6 +121,9 @@ static std::string stripPointerType(const std::string &typeNameIn) std::string typeName = typeNameIn; if (typeName.back() == '*') { typeName.pop_back(); + trimBack(typeName); + if (endsWith(typeName, "const")) + typeName = typeName.erase(typeName.size() - 5, 5); } else { const auto arrayPosition = typeName.find_first_of('['); if (arrayPosition != std::string::npos @@ -296,35 +299,19 @@ int PyType::code() const return std::nullopt; }; - if (!resolve()) - return parseTypeName(name()).value_or(TypeCodeUnresolvable); - - if (m_tag < 0) { - if (const std::optional typeCode = parseTypeName(name())) - return *typeCode; - - IDebugSymbolGroup2 *sg = 0; - if (FAILED(ExtensionCommandContext::instance()->symbols()->CreateSymbolGroup2(&sg))) - return TypeCodeStruct; - - const std::string helperValueName = SymbolGroupValue::pointedToSymbolName(0, name(true)); - ULONG index = DEBUG_ANY_ID; - if (SUCCEEDED(sg->AddSymbol(helperValueName.c_str(), &index))) - m_tag = PyValue(index, sg).tag(); - sg->Release(); + if (m_tag >= 0) { + switch (m_tag) { + case SymTagUDT: return TypeCodeStruct; + case SymTagEnum: return TypeCodeEnum; + case SymTagTypedef: return TypeCodeTypedef; + case SymTagFunctionType: return TypeCodeFunction; + case SymTagPointerType: return TypeCodePointer; + case SymTagArrayType: return TypeCodeArray; + case SymTagBaseType: return isIntegralType(name()) ? TypeCodeIntegral : TypeCodeFloat; + default: break; + } } - switch (m_tag) { - case SymTagUDT: return TypeCodeStruct; - case SymTagEnum: return TypeCodeEnum; - case SymTagTypedef: return TypeCodeTypedef; - case SymTagFunctionType: return TypeCodeFunction; - case SymTagPointerType: return TypeCodePointer; - case SymTagArrayType: return TypeCodeArray; - case SymTagBaseType: return isIntegralType(name()) ? TypeCodeIntegral : TypeCodeFloat; - default: break; - } - - return TypeCodeStruct; + return parseTypeName(name()).value_or(TypeCodeStruct); } PyType PyType::target() const @@ -533,6 +520,7 @@ PY_FUNC_RET_OBJECT_LIST(fields, PY_OBJ_NAME) PY_FUNC_RET_STD_STRING(module, PY_OBJ_NAME) PY_FUNC(moduleId, PY_OBJ_NAME, "K") PY_FUNC(arrayElements, PY_OBJ_NAME, "k") +PY_FUNC_RET_BOOL(resolved, PY_OBJ_NAME) PY_FUNC_DECL(templateArguments, PY_OBJ_NAME) { PY_IMPL_GUARD; @@ -568,6 +556,8 @@ static PyMethodDef typeMethods[] = { "Returns the number of elements in an array or 0 for non array types"}, {"templateArguments", PyCFunction(templateArguments), METH_NOARGS, "Returns all template arguments."}, + {"resolved", PyCFunction(resolved), METH_NOARGS, + "Returns whether the type is resolved"}, {NULL} /* Sentinel */ }; diff --git a/src/libs/qtcreatorcdbext/pytype.h b/src/libs/qtcreatorcdbext/pytype.h index 8b05fffe0ad..b71eae1ab02 100644 --- a/src/libs/qtcreatorcdbext/pytype.h +++ b/src/libs/qtcreatorcdbext/pytype.h @@ -29,6 +29,7 @@ public: std::string module() const; ULONG64 moduleId() const; int arrayElements() const; + bool resolved() const { return m_resolved.value_or(false); } struct TemplateArgument { From 226806e0fbbd01d9967b34567dfdb10b1a170d87 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 27 Feb 2024 12:53:59 +0100 Subject: [PATCH 09/38] RemoteLinux: Make deployment downgrade warning less spammy Keep the message, but make it a warning only for the "generic copy" case, which almost no one ever wants. Otherwise, it will annoy Windows users, who typically have no rsync installed. Change-Id: I2044b9ea2b199e03dc4e9421d05a2698d92ad76a Reviewed-by: hjk --- src/plugins/remotelinux/genericdeploystep.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/plugins/remotelinux/genericdeploystep.cpp b/src/plugins/remotelinux/genericdeploystep.cpp index bddc7bfcd3d..6071c4c8cae 100644 --- a/src/plugins/remotelinux/genericdeploystep.cpp +++ b/src/plugins/remotelinux/genericdeploystep.cpp @@ -155,11 +155,16 @@ GroupItem GenericDeployStep::transferTask(const Storage &storag } } if (!m_emittedDowngradeWarning && transferMethod != preferredTransferMethod) { - addWarningMessage(Tr::tr("Transfer method was downgraded from \"%1\" to \"%2\". If " - "this is unexpected, please re-test device \"%3\".") - .arg(FileTransfer::transferMethodName(preferredTransferMethod), - FileTransfer::transferMethodName(transferMethod), - deviceConfiguration()->displayName())); + const QString message + = Tr::tr("Transfer method was downgraded from \"%1\" to \"%2\". If " + "this is unexpected, please re-test device \"%3\".") + .arg(FileTransfer::transferMethodName(preferredTransferMethod), + FileTransfer::transferMethodName(transferMethod), + deviceConfiguration()->displayName()); + if (transferMethod == FileTransferMethod::GenericCopy) + addWarningMessage(message); + else + addProgressMessage(message); m_emittedDowngradeWarning = true; } transfer.setTransferMethod(transferMethod); From c536712707d5ba42eeebddcf78702fc7e06dc984 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 27 Feb 2024 11:07:28 +0100 Subject: [PATCH 10/38] Android: Remove command line and version numbers from translations Change-Id: Ib4fcd6cbf0a023e074aaad4b265c0ab60edac01a Reviewed-by: Marcus Tillmanns --- src/plugins/android/androidsettingswidget.cpp | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 0001c37de5f..c75ba299c5b 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -209,16 +209,20 @@ static expected_str testJavaC(const FilePath &jdkPath) if (!jdkPath.isReadableDir()) return make_unexpected(Tr::tr("The selected path does not exist or is not readable.")); - const FilePath bin = jdkPath.pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX); + const QString javacCommand("javac"); + const QString versionParameter("-version"); + constexpr int requiredMajorVersion = 17; + const FilePath bin = jdkPath / "bin" / (javacCommand + QTC_HOST_EXE_SUFFIX); if (!bin.isExecutableFile()) return make_unexpected( - Tr::tr("The selected path does not contain an executable bin/javac.")); + Tr::tr("Could not find \"%1\" in the selected path.") + .arg(bin.toUserOutput())); QVersionNumber jdkVersion; Process javacProcess; - CommandLine cmd(bin, {"-version"}); + const CommandLine cmd(bin, {versionParameter}); javacProcess.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels); javacProcess.setCommand(cmd); javacProcess.runBlocking(); @@ -227,17 +231,22 @@ static expected_str testJavaC(const FilePath &jdkPath) if (javacProcess.exitCode() != 0) return make_unexpected( - Tr::tr("The selected path does not contain a valid JDK. (javac -version failed: %1)") + Tr::tr("The selected path does not contain a valid JDK. (%1 failed: %2)") + .arg(cmd.toUserOutput()) .arg(stdOut)); // We expect "javac " where is "major.minor.patch" - if (!stdOut.startsWith("javac ")) - return make_unexpected(Tr::tr("Unexpected output from \"javac -version\": %1").arg(stdOut)); + const QString outputPrefix = javacCommand + " "; + if (!stdOut.startsWith(outputPrefix)) + return make_unexpected(Tr::tr("Unexpected output from \"%1\": %2") + .arg(cmd.toUserOutput()) + .arg(stdOut)); - jdkVersion = QVersionNumber::fromString(stdOut.mid(6).split('\n').first()); + jdkVersion = QVersionNumber::fromString(stdOut.mid(outputPrefix.length()).split('\n').first()); - if (jdkVersion.isNull() || jdkVersion.majorVersion() != 17) { - return make_unexpected(Tr::tr("Unsupported JDK version (needs to be 17): %1 (parsed: %2)") + if (jdkVersion.isNull() || jdkVersion.majorVersion() != requiredMajorVersion) { + return make_unexpected(Tr::tr("Unsupported JDK version (needs to be %1): %2 (parsed: %3)") + .arg(requiredMajorVersion) .arg(stdOut) .arg(jdkVersion.toString())); } From b60e0cfee7e346adc934d910216bbc0e47ccffb6 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 27 Feb 2024 12:45:36 +0100 Subject: [PATCH 11/38] Update change log for 13.0.0 Change-Id: I7760acdfeb1b0a309e8d939bf37494aa3a0a7a36 Reviewed-by: Leena Miettinen --- dist/changelog/changes-13.0.0.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dist/changelog/changes-13.0.0.md b/dist/changelog/changes-13.0.0.md index b8aa6aa1160..6ca281668ff 100644 --- a/dist/changelog/changes-13.0.0.md +++ b/dist/changelog/changes-13.0.0.md @@ -39,6 +39,8 @@ General for searching in `Files in File System` * Added `Copy to Clipboard` to the `About Qt Creator` dialog ([QTCREATORBUG-29886](https://bugreports.qt.io/browse/QTCREATORBUG-29886)) +* Fixed issues with the window actions + ([QTCREATORBUG-30381](https://bugreports.qt.io/browse/QTCREATORBUG-30381)) Editing ------- @@ -78,6 +80,8 @@ Editing * Clangd * Fixed that `Follow Symbol Under Cursor` only worked for exact matches ([QTCREATORBUG-29814](https://bugreports.qt.io/browse/QTCREATORBUG-29814)) + * Fixed the version check for remote `clangd` executables + ([QTCREATORBUG-30374](https://bugreports.qt.io/browse/QTCREATORBUG-30374)) ### QML @@ -133,6 +137,8 @@ Projects ([QTCREATORBUG-29530](https://bugreports.qt.io/browse/QTCREATORBUG-29530)) * Added a file wizard for Qt translation (`.ts`) files ([QTCREATORBUG-29775](https://bugreports.qt.io/browse/QTCREATORBUG-29775)) +* Added an optional warning for special characters in build directories + ([QTCREATORBUG-20834](https://bugreports.qt.io/browse/QTCREATORBUG-20834)) * Improved the environment settings by making the changes explicit in a separate, text-based editor * Increased the maximum width of the target selector @@ -184,6 +190,9 @@ Debugging ### C++ * Added a pretty printer for `std::tuple` +* Improved the display of size information for the pretty printer of + `QByteArray` + ([QTCREATORBUG-30065](https://bugreports.qt.io/browse/QTCREATORBUG-30065)) * Fixed that breakpoints were not hit while the message dialog about missing debug information was shown ([QTCREATORBUG-30168](https://bugreports.qt.io/browse/QTCREATORBUG-30168)) @@ -270,6 +279,7 @@ Andre Hartmann André Pönitz Andreas Loth Artem Sokolovskii +Assam Boudjelthia Brook Cronin Burak Hancerli Christian Kandeler @@ -306,6 +316,7 @@ Robert Löhning Sami Shalayel Samuel Jose Raposo Vieira Mira Samuel Mira +Semih Yavuz Serg Kryvonos Shrief Gabr Sivert Krøvel From e8b3887dbf584460973ed0212a66f9b400bcc464 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 27 Feb 2024 13:51:54 +0100 Subject: [PATCH 12/38] Axivion: Make use of Dto::IssueKind enum Use Dto::IssueKindMeta::enumToStr() to convert it to string. Rename icons accordingly. Change-Id: I8a955f2f0075793eea761cd4a41374a65d2aaea2 Reviewed-by: hjk --- src/plugins/axivion/axivion.qrc | 24 +++++++++--------- src/plugins/axivion/axivionoutputpane.cpp | 2 +- src/plugins/axivion/axivionplugin.cpp | 20 ++++++++------- src/plugins/axivion/axivionplugin.h | 2 +- .../images/{button-av.png => button-AV.png} | Bin .../{button-av@2x.png => button-AV@2x.png} | Bin .../images/{button-cl.png => button-CL.png} | Bin .../{button-cl@2x.png => button-CL@2x.png} | Bin .../images/{button-cy.png => button-CY.png} | Bin .../{button-cy@2x.png => button-CY@2x.png} | Bin .../images/{button-de.png => button-DE.png} | Bin .../{button-de@2x.png => button-DE@2x.png} | Bin .../images/{button-mv.png => button-MV.png} | Bin .../{button-mv@2x.png => button-MV@2x.png} | Bin .../images/{button-sv.png => button-SV.png} | Bin .../{button-sv@2x.png => button-SV@2x.png} | Bin src/tools/icons/qtcreatoricons.svg | 12 ++++----- 17 files changed, 31 insertions(+), 29 deletions(-) rename src/plugins/axivion/images/{button-av.png => button-AV.png} (100%) rename src/plugins/axivion/images/{button-av@2x.png => button-AV@2x.png} (100%) rename src/plugins/axivion/images/{button-cl.png => button-CL.png} (100%) rename src/plugins/axivion/images/{button-cl@2x.png => button-CL@2x.png} (100%) rename src/plugins/axivion/images/{button-cy.png => button-CY.png} (100%) rename src/plugins/axivion/images/{button-cy@2x.png => button-CY@2x.png} (100%) rename src/plugins/axivion/images/{button-de.png => button-DE.png} (100%) rename src/plugins/axivion/images/{button-de@2x.png => button-DE@2x.png} (100%) rename src/plugins/axivion/images/{button-mv.png => button-MV.png} (100%) rename src/plugins/axivion/images/{button-mv@2x.png => button-MV@2x.png} (100%) rename src/plugins/axivion/images/{button-sv.png => button-SV.png} (100%) rename src/plugins/axivion/images/{button-sv@2x.png => button-SV@2x.png} (100%) diff --git a/src/plugins/axivion/axivion.qrc b/src/plugins/axivion/axivion.qrc index fa3ad146d37..d1e41e3cdb3 100644 --- a/src/plugins/axivion/axivion.qrc +++ b/src/plugins/axivion/axivion.qrc @@ -2,18 +2,18 @@ images/axivion.png images/axivion@2x.png - images/button-av.png - images/button-av@2x.png - images/button-cl.png - images/button-cl@2x.png - images/button-cy.png - images/button-cy@2x.png - images/button-de.png - images/button-de@2x.png - images/button-mv.png - images/button-mv@2x.png - images/button-sv.png - images/button-sv@2x.png + images/button-AV.png + images/button-AV@2x.png + images/button-CL.png + images/button-CL@2x.png + images/button-CY.png + images/button-CY@2x.png + images/button-DE.png + images/button-DE@2x.png + images/button-MV.png + images/button-MV@2x.png + images/button-SV.png + images/button-SV@2x.png images/sortAsc.png images/sortAsc@2x.png images/sortDesc.png diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 31a03f0d569..70e44057e9f 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -564,7 +564,7 @@ void IssuesWidget::updateBasicProjectInfo(std::optional inf int buttonId = 0; for (const Dto::IssueKindInfoDto &kind : issueKinds) { auto button = new QToolButton(this); - button->setIcon(iconForIssue(kind.prefix)); + button->setIcon(iconForIssue(kind.getOptionalPrefixEnum())); button->setToolTip(kind.nicePluralName); button->setCheckable(true); connect(button, &QToolButton::clicked, this, [this, prefix = kind.prefix]{ diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 20e7871b14e..6e04af7e30d 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -63,16 +63,18 @@ using namespace Utils; namespace Axivion::Internal { -QIcon iconForIssue(const QString &prefix) +QIcon iconForIssue(const std::optional &issueKind) { - static QHash prefixToIcon; - auto it = prefixToIcon.find(prefix); + if (!issueKind) + return {}; - if (it == prefixToIcon.end()) { - Icon icon({{FilePath::fromString(":/axivion/images/button-" + prefix.toLower() + ".png"), - Theme::PaletteButtonText}}, - Icon::Tint); - it = prefixToIcon.insert(prefix, icon.icon()); + static QHash prefixToIcon; + auto it = prefixToIcon.constFind(*issueKind); + if (it == prefixToIcon.constEnd()) { + const auto prefix = Dto::IssueKindMeta::enumToStr(*issueKind); + const Icon icon({{FilePath::fromString(":/axivion/images/button-" + prefix + ".png"), + Theme::PaletteButtonText}}, Icon::Tint); + it = prefixToIcon.insert(*issueKind, icon.icon()); } return it.value(); } @@ -226,7 +228,7 @@ public: const QString markText = issue.description; const QString id = issue.kind + QString::number(issue.id.value_or(-1)); setToolTip(id + '\n' + markText); - setIcon(iconForIssue(issue.kind)); + setIcon(iconForIssue(issue.getOptionalKindEnum())); if (color) setColor(*color); setPriority(TextMark::NormalPriority); diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index c60aad6e9e9..18cdae6dded 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -71,7 +71,7 @@ void fetchProjectInfo(const QString &projectName); std::optional projectInfo(); bool handleCertificateIssue(); -QIcon iconForIssue(const QString &prefix); +QIcon iconForIssue(const std::optional &issueKind); QString anyToSimpleString(const Dto::Any &any); void fetchIssueInfo(const QString &id); diff --git a/src/plugins/axivion/images/button-av.png b/src/plugins/axivion/images/button-AV.png similarity index 100% rename from src/plugins/axivion/images/button-av.png rename to src/plugins/axivion/images/button-AV.png diff --git a/src/plugins/axivion/images/button-av@2x.png b/src/plugins/axivion/images/button-AV@2x.png similarity index 100% rename from src/plugins/axivion/images/button-av@2x.png rename to src/plugins/axivion/images/button-AV@2x.png diff --git a/src/plugins/axivion/images/button-cl.png b/src/plugins/axivion/images/button-CL.png similarity index 100% rename from src/plugins/axivion/images/button-cl.png rename to src/plugins/axivion/images/button-CL.png diff --git a/src/plugins/axivion/images/button-cl@2x.png b/src/plugins/axivion/images/button-CL@2x.png similarity index 100% rename from src/plugins/axivion/images/button-cl@2x.png rename to src/plugins/axivion/images/button-CL@2x.png diff --git a/src/plugins/axivion/images/button-cy.png b/src/plugins/axivion/images/button-CY.png similarity index 100% rename from src/plugins/axivion/images/button-cy.png rename to src/plugins/axivion/images/button-CY.png diff --git a/src/plugins/axivion/images/button-cy@2x.png b/src/plugins/axivion/images/button-CY@2x.png similarity index 100% rename from src/plugins/axivion/images/button-cy@2x.png rename to src/plugins/axivion/images/button-CY@2x.png diff --git a/src/plugins/axivion/images/button-de.png b/src/plugins/axivion/images/button-DE.png similarity index 100% rename from src/plugins/axivion/images/button-de.png rename to src/plugins/axivion/images/button-DE.png diff --git a/src/plugins/axivion/images/button-de@2x.png b/src/plugins/axivion/images/button-DE@2x.png similarity index 100% rename from src/plugins/axivion/images/button-de@2x.png rename to src/plugins/axivion/images/button-DE@2x.png diff --git a/src/plugins/axivion/images/button-mv.png b/src/plugins/axivion/images/button-MV.png similarity index 100% rename from src/plugins/axivion/images/button-mv.png rename to src/plugins/axivion/images/button-MV.png diff --git a/src/plugins/axivion/images/button-mv@2x.png b/src/plugins/axivion/images/button-MV@2x.png similarity index 100% rename from src/plugins/axivion/images/button-mv@2x.png rename to src/plugins/axivion/images/button-MV@2x.png diff --git a/src/plugins/axivion/images/button-sv.png b/src/plugins/axivion/images/button-SV.png similarity index 100% rename from src/plugins/axivion/images/button-sv.png rename to src/plugins/axivion/images/button-SV.png diff --git a/src/plugins/axivion/images/button-sv@2x.png b/src/plugins/axivion/images/button-SV@2x.png similarity index 100% rename from src/plugins/axivion/images/button-sv@2x.png rename to src/plugins/axivion/images/button-SV@2x.png diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index ddec488f3cb..07452dc8c1e 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -3813,7 +3813,7 @@ r="1.5" /> Date: Tue, 27 Feb 2024 15:34:32 +0100 Subject: [PATCH 13/38] Axivion: Fix clazy warning about mixing const and mutable iterators Change-Id: Ief898ff2febb958f3f68a64ddcb614479854600f Reviewed-by: Christian Stenger Reviewed-by: Jarek Kobus Reviewed-by: Andreas Loth --- src/plugins/axivion/axivionplugin.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 6e04af7e30d..43316c4f8b7 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -69,14 +69,15 @@ QIcon iconForIssue(const std::optional &issueKind) return {}; static QHash prefixToIcon; + auto it = prefixToIcon.constFind(*issueKind); - if (it == prefixToIcon.constEnd()) { - const auto prefix = Dto::IssueKindMeta::enumToStr(*issueKind); - const Icon icon({{FilePath::fromString(":/axivion/images/button-" + prefix + ".png"), - Theme::PaletteButtonText}}, Icon::Tint); - it = prefixToIcon.insert(*issueKind, icon.icon()); - } - return it.value(); + if (it != prefixToIcon.constEnd()) + return *it; + + const QLatin1String prefix = Dto::IssueKindMeta::enumToStr(*issueKind); + const Icon icon({{FilePath::fromString(":/axivion/images/button-" + prefix + ".png"), + Theme::PaletteButtonText}}, Icon::Tint); + return prefixToIcon.insert(*issueKind, icon.icon()).value(); } QString anyToSimpleString(const Dto::Any &any) From fdb1fa2a3b868ced9075b6e40527364f209edbed Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 26 Feb 2024 17:13:01 +0100 Subject: [PATCH 14/38] Python: Fix capitalization of Python in UI text Change-Id: I55beeb658eb583a74c4d79f3dc2f121010080101 Reviewed-by: Reviewed-by: David Schulz Reviewed-by: Eike Ziller --- src/plugins/python/pythonkitaspect.cpp | 12 ++++++------ src/plugins/python/pythonproject.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/python/pythonkitaspect.cpp b/src/plugins/python/pythonkitaspect.cpp index 26ad44bad48..254a720d7cc 100644 --- a/src/plugins/python/pythonkitaspect.cpp +++ b/src/plugins/python/pythonkitaspect.cpp @@ -117,11 +117,11 @@ public: if (!pipIsUsable(path)) { result << BuildSystemTask( Task::Warning, - Tr::tr("Python \"%1\" does not contain a usable pip. Pip is used to install " - "python " - "packages from the Python Package Index, like PySide and the python " - "language server. If you want to use any of that functionality " - "ensure pip is installed for that python.") + Tr::tr("Python \"%1\" does not contain a usable pip. pip is needed to install " + "Python " + "packages from the Python Package Index, like PySide and the Python " + "language server. To use any of that functionality " + "ensure that pip is installed for that Python.") .arg(path.toUserOutput())); } if (!venvIsUsable(path)) { @@ -130,7 +130,7 @@ public: Tr::tr( "Python \"%1\" does not contain a usable venv. venv is the recommended way " "to isolate a development environment for a project from the globally " - "installed python.") + "installed Python.") .arg(path.toUserOutput())); } } diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp index 129782773d3..db0831005f1 100644 --- a/src/plugins/python/pythonproject.cpp +++ b/src/plugins/python/pythonproject.cpp @@ -35,7 +35,7 @@ Tasks PythonProject::projectIssues(const Kit *k) const return {}; return { BuildSystemTask{Task::Error, - Tr::tr("No python interpreter set for kit \"%1\"").arg(k->displayName())}}; + Tr::tr("No Python interpreter set for kit \"%1\"").arg(k->displayName())}}; } PythonProjectNode::PythonProjectNode(const FilePath &path) From 97077f4d263c3da34d360e2509daf273d1cecefd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 27 Feb 2024 13:56:47 +0100 Subject: [PATCH 15/38] Axivion: Raise the size of issues packet Change-Id: I4a60649982b1ffa50c2c85f4db3d57f88186a211 Reviewed-by: hjk Reviewed-by: Andreas Loth --- src/plugins/axivion/axivionplugin.h | 4 +++- src/plugins/axivion/dynamiclistmodel.cpp | 17 ++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index 18cdae6dded..39783a956da 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -23,6 +23,8 @@ namespace Utils { class FilePath; } namespace Axivion::Internal { +constexpr int DefaultSearchLimit = 2048; + struct IssueListSearch { QString kind; @@ -33,7 +35,7 @@ struct IssueListSearch QString filter_path; QString sort; int offset = 0; - int limit = 150; + int limit = DefaultSearchLimit; bool computeTotalRowCount = false; QString toQuery() const; diff --git a/src/plugins/axivion/dynamiclistmodel.cpp b/src/plugins/axivion/dynamiclistmodel.cpp index 70abe087bdb..7c5262132b8 100644 --- a/src/plugins/axivion/dynamiclistmodel.cpp +++ b/src/plugins/axivion/dynamiclistmodel.cpp @@ -3,6 +3,7 @@ #include "dynamiclistmodel.h" +#include "axivionplugin.h" #include "axiviontr.h" #include @@ -10,8 +11,6 @@ namespace Axivion::Internal { -constexpr int pageSize = 150; - DynamicListModel::DynamicListModel(QObject *parent) : QAbstractItemModel(parent) { @@ -161,7 +160,7 @@ QModelIndex DynamicListModel::indexForItem(const ListItem *item) const void DynamicListModel::onNeedFetch(int row) { m_fetchStart = row; - m_fetchEnd = row + pageSize; + m_fetchEnd = row + DefaultSearchLimit; if (m_fetchStart < 0) return; m_fetchMoreTimer.start(); @@ -171,14 +170,14 @@ void DynamicListModel::fetchNow() { const int old = m_lastFetch; m_lastFetch = m_fetchStart; // we need the "original" fetch request to avoid endless loop - m_lastFetchEnd = m_fetchStart + pageSize; + m_lastFetchEnd = m_fetchStart + DefaultSearchLimit; if (old != -1) { const int diff = old - m_fetchStart; - if (0 < diff && diff < pageSize) { - m_fetchStart = qMax(old - pageSize, 0); - } else if (0 > diff && diff > -pageSize) { - m_fetchStart = old + pageSize; + if (0 < diff && diff < DefaultSearchLimit) { + m_fetchStart = qMax(old - DefaultSearchLimit, 0); + } else if (0 > diff && diff > - DefaultSearchLimit) { + m_fetchStart = old + DefaultSearchLimit; if (m_expectedRowCount && m_fetchStart > *m_expectedRowCount) m_fetchStart = *m_expectedRowCount; } @@ -186,7 +185,7 @@ void DynamicListModel::fetchNow() QTC_CHECK(m_expectedRowCount ? m_fetchStart <= *m_expectedRowCount : m_fetchStart >= m_children.size()); - emit fetchRequested(m_fetchStart, pageSize); + emit fetchRequested(m_fetchStart, DefaultSearchLimit); m_fetchStart = -1; m_fetchEnd = -1; } From e2a0dd2cefe5265a9d3ba59de766f73302cf0082 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 27 Feb 2024 15:51:46 +0100 Subject: [PATCH 16/38] Axivion: Fix the condition inside onUnauthorizedGroupSetup We should execute this branch just once, when the server access is unknown. Introduce isServerAccessEstablished() helper. Change-Id: I28953f468be39ca49f088032aebb3fa81b814f3f Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 43316c4f8b7..2152755fd14 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -333,11 +333,17 @@ static constexpr int httpStatusCodeOk = 200; constexpr char s_htmlContentType[] = "text/html"; constexpr char s_jsonContentType[] = "application/json"; +static bool isServerAccessEstablished() +{ + return dd->m_serverAccess == ServerAccess::NoAuthorization + || (dd->m_serverAccess == ServerAccess::WithAuthorization && dd->m_apiToken); +} + static Group fetchHtmlRecipe(const QUrl &url, const std::function &handler) { // TODO: Refactor so that it's a common code with fetchDataRecipe(). const auto onQuerySetup = [url](NetworkQuery &query) { - if (dd->m_serverAccess == ServerAccess::Unknown) + if (!isServerAccessEstablished()) return SetupResult::StopWithError; // TODO: start authorizationRecipe()? QNetworkRequest request(url); @@ -506,7 +512,7 @@ static Group authorizationRecipe() { const Storage> unauthorizedDashboardStorage; const auto onUnauthorizedGroupSetup = [unauthorizedDashboardStorage] { - if (dd->m_serverAccess != ServerAccess::NoAuthorization) + if (isServerAccessEstablished()) return SetupResult::StopWithSuccess; unauthorizedDashboardStorage->url = QUrl(settings().server.dashboard); @@ -636,10 +642,11 @@ static Group fetchDataRecipe(const QUrl &url, const std::function> dtoStorage; const auto onDtoSetup = [dtoStorage, url] { - if (!dd->m_apiToken) + if (!isServerAccessEstablished()) return SetupResult::StopWithError; - dtoStorage->credential = "AxToken " + *dd->m_apiToken; + if (dd->m_serverAccess == ServerAccess::WithAuthorization && dd->m_apiToken) + dtoStorage->credential = "AxToken " + *dd->m_apiToken; dtoStorage->url = url; return SetupResult::Continue; }; From 903d01b93459d0f1ee70e6ca74a8c01af5e0981b Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 12 Feb 2024 17:19:41 +0100 Subject: [PATCH 17/38] Welcome: Implement new design 2024 redesign Change-Id: I6629849921272d856f201693973a8e29c6465e94 Reviewed-by: hjk Reviewed-by: Alessandro Portale --- share/qtcreator/themes/dark.creatortheme | 34 +- share/qtcreator/themes/dark.figmatokens | 31 + share/qtcreator/themes/default.creatortheme | 34 +- .../themes/design-light.creatortheme | 34 +- share/qtcreator/themes/design.creatortheme | 34 +- share/qtcreator/themes/flat-dark.creatortheme | 34 +- .../qtcreator/themes/flat-light.creatortheme | 34 +- share/qtcreator/themes/flat.creatortheme | 34 +- share/qtcreator/themes/light.figmatokens | 31 + src/libs/utils/stylehelper.cpp | 24 +- src/libs/utils/stylehelper.h | 31 +- src/libs/utils/theme/theme.h | 12 - src/plugins/coreplugin/core.qrc | 4 + src/plugins/coreplugin/images/expandarrow.png | Bin 0 -> 169 bytes .../coreplugin/images/expandarrow@2x.png | Bin 0 -> 209 bytes src/plugins/coreplugin/images/search.png | Bin 0 -> 179 bytes src/plugins/coreplugin/images/search@2x.png | Bin 0 -> 361 bytes src/plugins/coreplugin/iwelcomepage.cpp | 184 ----- src/plugins/coreplugin/iwelcomepage.h | 44 +- src/plugins/coreplugin/session.cpp | 5 + src/plugins/coreplugin/session.h | 1 + src/plugins/coreplugin/welcomepagehelper.cpp | 717 ++++++++++++++---- src/plugins/coreplugin/welcomepagehelper.h | 126 ++- .../extensionmanagerwidget.cpp | 20 +- .../extensionmanager/extensionsbrowser.cpp | 26 +- .../extensionmanager/extensionsbrowser.h | 12 +- src/plugins/marketplace/productlistmodel.cpp | 2 +- .../marketplace/qtmarketplacewelcomepage.cpp | 39 +- .../projectexplorer/projectwelcomepage.cpp | 660 ++++++++++------ src/plugins/qtsupport/exampleslistmodel.cpp | 2 +- .../qtsupport/gettingstartedwelcomepage.cpp | 53 +- src/plugins/welcome/images/expandarrow.png | Bin 106 -> 0 bytes src/plugins/welcome/images/expandarrow@2x.png | Bin 148 -> 0 bytes src/plugins/welcome/images/link.png | Bin 0 -> 186 bytes src/plugins/welcome/images/link@2x.png | Bin 0 -> 236 bytes src/plugins/welcome/images/project.png | Bin 106 -> 175 bytes src/plugins/welcome/images/project@2x.png | Bin 112 -> 225 bytes src/plugins/welcome/images/session.png | Bin 118 -> 192 bytes src/plugins/welcome/images/session@2x.png | Bin 161 -> 255 bytes src/plugins/welcome/welcome.qrc | 4 +- src/plugins/welcome/welcomeplugin.cpp | 324 ++++---- src/tools/icons/qtcreatoricons.svg | 115 ++- .../uifonts/tst_manual_widgets_uifonts.cpp | 8 +- 43 files changed, 1517 insertions(+), 1196 deletions(-) create mode 100644 share/qtcreator/themes/dark.figmatokens create mode 100644 share/qtcreator/themes/light.figmatokens create mode 100644 src/plugins/coreplugin/images/expandarrow.png create mode 100644 src/plugins/coreplugin/images/expandarrow@2x.png create mode 100644 src/plugins/coreplugin/images/search.png create mode 100644 src/plugins/coreplugin/images/search@2x.png delete mode 100644 src/plugins/welcome/images/expandarrow.png delete mode 100644 src/plugins/welcome/images/expandarrow@2x.png create mode 100644 src/plugins/welcome/images/link.png create mode 100644 src/plugins/welcome/images/link@2x.png diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index a7dcedd104a..c2846fa0940 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=dark.figmatokens ThemeName=Dark PreferredStyles= DefaultTextEditorColorScheme=dark.xml @@ -406,39 +407,6 @@ Debugger_WatchItem_ValueChanged=ffff6666 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - dark mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff8f8f8 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ff1f1f1f -Token_Background_Muted=ff262626 -Token_Background_Subtle=ff2e2e2e -Token_Foreground_Default=ff5a5a5a -Token_Foreground_Muted=ff3e3e3e -Token_Foreground_Subtle=ff303030 -Token_Text_Default=fff8f8f8 -Token_Text_Muted=ffaeaeae -Token_Text_Subtle=ff595959 -Token_Stroke_Strong=ffeeeeee -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ff3a3a3a -Token_Notification_Alert=ffc98014 -Token_Notification_Success=ff1f9b5d -Token_Notification_Neutral=ff016876 -Token_Notification_Danger=ffb22245 - -Welcome_TextColor=text -Welcome_ForegroundPrimaryColor=ffa3a3a3 -Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundPrimaryColor=normalBackground -Welcome_BackgroundSecondaryColor=shadowBackground -Welcome_HoverColor=ff404040 -Welcome_AccentColor=ff57d658 -Welcome_LinkColor=ff67e668 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=ff444444 diff --git a/share/qtcreator/themes/dark.figmatokens b/share/qtcreator/themes/dark.figmatokens new file mode 100644 index 00000000000..fdd98e80c10 --- /dev/null +++ b/share/qtcreator/themes/dark.figmatokens @@ -0,0 +1,31 @@ +; Qt Creator Color Tokens - dark mode + +[Colors] + +Token_Basic_Black=ff131313 +Token_Basic_White=fff8f8f8 + +Token_Accent_Default=ff23b26a +Token_Accent_Muted=ff1f9b5d +Token_Accent_Subtle=ff1a8550 + +Token_Background_Default=ff1f1f1f +Token_Background_Muted=ff262626 +Token_Background_Subtle=ff2e2e2e + +Token_Foreground_Default=ff5a5a5a +Token_Foreground_Muted=ff3e3e3e +Token_Foreground_Subtle=ff303030 + +Token_Text_Default=fff8f8f8 +Token_Text_Muted=ffaeaeae +Token_Text_Subtle=ff595959 + +Token_Stroke_Strong=ffeeeeee +Token_Stroke_Muted=ff727272 +Token_Stroke_Subtle=ff3a3a3a + +Token_Notification_Alert=ffc98014 +Token_Notification_Success=ff1f9b5d +Token_Notification_Neutral=ff016876 +Token_Notification_Danger=ffb22245 diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 2dee7ab2469..f2c4c7f7a43 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=light.figmatokens ThemeName=Classic PreferredStyles= @@ -398,39 +399,6 @@ Debugger_WatchItem_ValueChanged=ffc80000 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - light mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff2f2f2 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ffe3e3e3 -Token_Background_Muted=ffeeeeee -Token_Background_Subtle=fffbfbfb -Token_Foreground_Default=ffcdcdcd -Token_Foreground_Muted=ffd5d5d5 -Token_Foreground_Subtle=ffdddddd -Token_Text_Default=ff393939 -Token_Text_Muted=ff7c7c7c -Token_Text_Subtle=ffbebebe -Token_Stroke_Strong=ff464646 -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ffcdcdcd -Token_Notification_Alert=ffeb991f -Token_Notification_Success=ff23b26a -Token_Notification_Neutral=ff0e7887 -Token_Notification_Danger=ffdc1343 - -Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=shadowBackground -Welcome_ForegroundSecondaryColor=ff939393 -Welcome_BackgroundPrimaryColor=fffafafa -Welcome_BackgroundSecondaryColor=ffffffff -Welcome_HoverColor=ffefefef -Welcome_AccentColor=ff45ce55 -Welcome_LinkColor=ff20a020 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=darkText Timeline_BackgroundColor1=ffffffff Timeline_BackgroundColor2=fff6f6f6 diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index 8931b620424..41a9f07ba84 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=light.figmatokens ThemeName=Design Light PreferredStyles= @@ -410,39 +411,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - light mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff2f2f2 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ffe3e3e3 -Token_Background_Muted=ffeeeeee -Token_Background_Subtle=fffbfbfb -Token_Foreground_Default=ffcdcdcd -Token_Foreground_Muted=ffd5d5d5 -Token_Foreground_Subtle=ffdddddd -Token_Text_Default=ff393939 -Token_Text_Muted=ff7c7c7c -Token_Text_Subtle=ffbebebe -Token_Stroke_Strong=ff464646 -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ffcdcdcd -Token_Notification_Alert=ffeb991f -Token_Notification_Success=ff23b26a -Token_Notification_Neutral=ff0e7887 -Token_Notification_Danger=ffdc1343 - -Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=ff404040 -Welcome_ForegroundSecondaryColor=ff727272 -Welcome_BackgroundPrimaryColor=ffeaeaea -Welcome_BackgroundSecondaryColor=ffefefef -Welcome_HoverColor=ffe1e1e1 -Welcome_AccentColor=ff25709a -Welcome_LinkColor=ff104090 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=fff6f6f6 diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme index e29240a3cf6..11022bd7e5d 100644 --- a/share/qtcreator/themes/design.creatortheme +++ b/share/qtcreator/themes/design.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=dark.figmatokens ThemeName=Design Dark PreferredStyles= DefaultTextEditorColorScheme=creator-dark.xml @@ -414,39 +415,6 @@ Debugger_WatchItem_ValueChanged=ffff6666 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - dark mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff8f8f8 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ff1f1f1f -Token_Background_Muted=ff262626 -Token_Background_Subtle=ff2e2e2e -Token_Foreground_Default=ff5a5a5a -Token_Foreground_Muted=ff3e3e3e -Token_Foreground_Subtle=ff303030 -Token_Text_Default=fff8f8f8 -Token_Text_Muted=ffaeaeae -Token_Text_Subtle=ff595959 -Token_Stroke_Strong=ffeeeeee -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ff3a3a3a -Token_Notification_Alert=ffc98014 -Token_Notification_Success=ff1f9b5d -Token_Notification_Neutral=ff016876 -Token_Notification_Danger=ffb22245 - -Welcome_TextColor=text -Welcome_ForegroundPrimaryColor=ffa3a3a3 -Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundPrimaryColor=ff242424 -Welcome_BackgroundSecondaryColor=ff1c1c1c -Welcome_HoverColor=ff2b2a2a -Welcome_AccentColor=ff3f8ccc -Welcome_LinkColor=ff5fafef -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=ff444444 diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index 7e94645b743..9737e9cd53e 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=dark.figmatokens ThemeName=Flat Dark PreferredStyles= DefaultTextEditorColorScheme=creator-dark.xml @@ -410,39 +411,6 @@ Debugger_WatchItem_ValueChanged=ffff6666 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - dark mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff8f8f8 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ff1f1f1f -Token_Background_Muted=ff262626 -Token_Background_Subtle=ff2e2e2e -Token_Foreground_Default=ff5a5a5a -Token_Foreground_Muted=ff3e3e3e -Token_Foreground_Subtle=ff303030 -Token_Text_Default=fff8f8f8 -Token_Text_Muted=ffaeaeae -Token_Text_Subtle=ff595959 -Token_Stroke_Strong=ffeeeeee -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ff3a3a3a -Token_Notification_Alert=ffc98014 -Token_Notification_Success=ff1f9b5d -Token_Notification_Neutral=ff016876 -Token_Notification_Danger=ffb22245 - -Welcome_TextColor=text -Welcome_ForegroundPrimaryColor=ff999999 -Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundPrimaryColor=normalBackground -Welcome_BackgroundSecondaryColor=ff242628 -Welcome_HoverColor=ff404243 -Welcome_AccentColor=ff36c148 -Welcome_LinkColor=ff5fcf4f -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=ff444444 diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index eddf38971d2..1ff8a7a3ff4 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=light.figmatokens ThemeName=Flat Light PreferredStyles= @@ -407,39 +408,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - light mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff2f2f2 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ffe3e3e3 -Token_Background_Muted=ffeeeeee -Token_Background_Subtle=fffbfbfb -Token_Foreground_Default=ffcdcdcd -Token_Foreground_Muted=ffd5d5d5 -Token_Foreground_Subtle=ffdddddd -Token_Text_Default=ff393939 -Token_Text_Muted=ff7c7c7c -Token_Text_Subtle=ffbebebe -Token_Stroke_Strong=ff464646 -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ffcdcdcd -Token_Notification_Alert=ffeb991f -Token_Notification_Success=ff23b26a -Token_Notification_Neutral=ff0e7887 -Token_Notification_Danger=ffdc1343 - -Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=ff232323 -Welcome_ForegroundSecondaryColor=ff939393 -Welcome_BackgroundPrimaryColor=fffafafa -Welcome_BackgroundSecondaryColor=ffffffff -Welcome_HoverColor=ffefefef -Welcome_AccentColor=ff45ce55 -Welcome_LinkColor=ff20a020 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=fff6f6f6 diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 08697334f40..f479077889e 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=light.figmatokens ThemeName=Flat PreferredStyles= @@ -405,39 +406,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - light mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff2f2f2 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ffe3e3e3 -Token_Background_Muted=ffeeeeee -Token_Background_Subtle=fffbfbfb -Token_Foreground_Default=ffcdcdcd -Token_Foreground_Muted=ffd5d5d5 -Token_Foreground_Subtle=ffdddddd -Token_Text_Default=ff393939 -Token_Text_Muted=ff7c7c7c -Token_Text_Subtle=ffbebebe -Token_Stroke_Strong=ff464646 -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ffcdcdcd -Token_Notification_Alert=ffeb991f -Token_Notification_Success=ff23b26a -Token_Notification_Neutral=ff0e7887 -Token_Notification_Danger=ffdc1343 - -Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=shadowBackground -Welcome_ForegroundSecondaryColor=ff939393 -Welcome_BackgroundPrimaryColor=fffafafa -Welcome_BackgroundSecondaryColor=ffffffff -Welcome_HoverColor=ffefefef -Welcome_AccentColor=ff45ce55 -Welcome_LinkColor=ff20a020 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=fff6f6f6 diff --git a/share/qtcreator/themes/light.figmatokens b/share/qtcreator/themes/light.figmatokens new file mode 100644 index 00000000000..a4d1bfcaa8d --- /dev/null +++ b/share/qtcreator/themes/light.figmatokens @@ -0,0 +1,31 @@ +; Qt Creator Color Tokens - light mode + +[Colors] + +Token_Basic_Black=ff131313 +Token_Basic_White=fff2f2f2 + +Token_Accent_Default=ff23b26a +Token_Accent_Muted=ff1f9b5d +Token_Accent_Subtle=ff1a8550 + +Token_Background_Default=fffcfcfc +Token_Background_Muted=ffefefef +Token_Background_Subtle=ffe7e7e7 + +Token_Foreground_Default=ffcdcdcd +Token_Foreground_Muted=ffd5d5d5 +Token_Foreground_Subtle=ffdddddd + +Token_Text_Default=ff393939 +Token_Text_Muted=ff6a6a6a +Token_Text_Subtle=ffbebebe + +Token_Stroke_Strong=ff464646 +Token_Stroke_Muted=ff727272 +Token_Stroke_Subtle=ffcdcdcd + +Token_Notification_Alert=ffeb991f +Token_Notification_Success=ff23b26a +Token_Notification_Neutral=ff0e7887 +Token_Notification_Danger=ffdc1343 diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index ffb7efc417c..991b43df528 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -933,7 +933,17 @@ QColor StyleHelper::ensureReadableOn(const QColor &background, const QColor &des return foreground; } -static QStringList brandFontFamilies() +static const QStringList &applicationFontFamilies() +{ + const static QStringList families = [] { + constexpr QLatin1String familyName("Inter"); + // Font is either installed in the system, or was loaded from share/qtcreator/fonts/ + return QFontDatabase::hasFamily(familyName) ? QStringList(familyName) : QStringList(); + }(); + return families; +} + +static const QStringList &brandFontFamilies() { const static QStringList families = []{ const int id = QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf"); @@ -959,10 +969,14 @@ static const UiFontMetrics& uiFontMetrics(StyleHelper::UiElement element) {StyleHelper::UiElementH5, {14, 16, QFont::DemiBold}}, {StyleHelper::UiElementH6, {12, 14, QFont::DemiBold}}, {StyleHelper::UiElementH6Capital, {12, 14, QFont::DemiBold}}, + {StyleHelper::UiElementBody1, {14, 20, QFont::Light}}, + {StyleHelper::UiElementBody2, {12, 20, QFont::Light}}, + {StyleHelper::UiElementButtonMedium, {12, 16, QFont::Bold}}, + {StyleHelper::UiElementButtonSmall, {10, 12, QFont::Bold}}, {StyleHelper::UiElementCaptionStrong, {10, 12, QFont::DemiBold}}, {StyleHelper::UiElementCaption, {10, 12, QFont::Normal}}, - {StyleHelper::UIElementIconStandard, {12, 16, QFont::Normal}}, - {StyleHelper::UIElementIconActive, {12, 16, QFont::DemiBold}}, + {StyleHelper::UiElementIconStandard, {12, 16, QFont::Medium}}, + {StyleHelper::UiElementIconActive, {12, 16, QFont::DemiBold}}, }; QTC_ASSERT(metrics.count(element) > 0, return metrics.at(StyleHelper::UiElementCaptionStrong)); return metrics.at(element); @@ -983,8 +997,10 @@ QFont StyleHelper::uiFont(UiElement element) case UiElementH3: case UiElementH6Capital: font.setCapitalization(QFont::AllUppercase); - break; + [[fallthrough]]; default: + if (!applicationFontFamilies().isEmpty()) + font.setFamilies(applicationFontFamilies()); break; } diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h index 4b986c68313..7d434925e66 100644 --- a/src/libs/utils/stylehelper.h +++ b/src/libs/utils/stylehelper.h @@ -42,15 +42,15 @@ constexpr char C_TOOLBAR_ACTIONWIDGET[] = "toolbar_actionWidget"; constexpr char C_QT_SCALE_FACTOR_ROUNDING_POLICY[] = "QT_SCALE_FACTOR_ROUNDING_POLICY"; namespace SpacingTokens { - constexpr int VPaddingXXS = 4; // Top and bottom padding within the component - constexpr int HPaddingXXS = 4; // Left and right padding within the component - constexpr int VGapXXS = 4; // Vertical Space between TEXT LINE within the Component - constexpr int HGapXXS = 4; // Horizontal Space between elements within the Component + constexpr int VPaddingXxs = 4; // Top and bottom padding within the component + constexpr int HPaddingXxs = 4; // Left and right padding within the component + constexpr int VGapXxs = 4; // Vertical Space between TEXT LINE within the Component + constexpr int HGapXxs = 4; // Horizontal Space between elements within the Component - constexpr int VPaddingXS = 8; - constexpr int HPaddingXS = 8; - constexpr int VGapXS = 4; - constexpr int HGapXS = 8; + constexpr int VPaddingXs = 8; + constexpr int HPaddingXs = 8; + constexpr int VGapXs = 4; + constexpr int HGapXs = 8; constexpr int VPaddingS = 8; constexpr int HPaddingS = 16; @@ -62,10 +62,15 @@ namespace SpacingTokens { constexpr int VGapM = 4; constexpr int HGapM = 16; - constexpr int VPaddingL = 12; + constexpr int VPaddingL = 16; constexpr int HPaddingL = 24; constexpr int VGapL = 8; constexpr int HGapL = 16; + + constexpr int ExPaddingGapS = 2; + constexpr int ExPaddingGapM = 6; + constexpr int ExPaddingGapL = 12; + constexpr int ExVPaddingGapXl = 24; } enum ToolbarStyle { @@ -82,10 +87,14 @@ enum UiElement { UiElementH5, UiElementH6, UiElementH6Capital, + UiElementBody1, + UiElementBody2, + UiElementButtonMedium, + UiElementButtonSmall, UiElementCaptionStrong, UiElementCaption, - UIElementIconStandard, - UIElementIconActive, + UiElementIconStandard, + UiElementIconActive, }; // Height of the project explorer navigation bar diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 2e4d61d943b..65d0ee91eaf 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -247,18 +247,6 @@ public: Token_Notification_Neutral, Token_Notification_Danger, - /* Welcome Plugin */ - - Welcome_TextColor, - Welcome_ForegroundPrimaryColor, - Welcome_ForegroundSecondaryColor, - Welcome_BackgroundPrimaryColor, - Welcome_BackgroundSecondaryColor, - Welcome_HoverColor, - Welcome_AccentColor, - Welcome_LinkColor, - Welcome_DisabledLinkColor, - /* Timeline Library */ Timeline_TextColor, Timeline_BackgroundColor1, diff --git a/src/plugins/coreplugin/core.qrc b/src/plugins/coreplugin/core.qrc index ff855e3f4b8..239bd946121 100644 --- a/src/plugins/coreplugin/core.qrc +++ b/src/plugins/coreplugin/core.qrc @@ -1,5 +1,9 @@ + images/expandarrow.png + images/expandarrow@2x.png + images/search.png + images/search@2x.png images/settingscategory_core.png images/settingscategory_core@2x.png images/settingscategory_design.png diff --git a/src/plugins/coreplugin/images/expandarrow.png b/src/plugins/coreplugin/images/expandarrow.png new file mode 100644 index 0000000000000000000000000000000000000000..c463d0236d17b03893fb92d06cc9fc0acbe33b08 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd7G?$phPQVgfdo_nd_r8s#KgqK#U&&pq@<*R zgM+VJxpMvb^&2;C+`M`7<;$0^UcLJN|9?rr!*5!0~3bQg8t(#I469)(ed5RMWOdMXT-C^q>OIG709&FDH_Xt>^sA z+Eu+uT3GmxHpi{$H(ivXbJ(LDBg!ILf;r6(9%ofLckf@*cb*5PZI@pzc*i(%BJZK% zfc{_KHL^4{&gcZNecg5Lc5uK{g@Om3)9$gD3oPJW9@V75FU#0J*B*!%VGX~sKJ zoN259XI-bgaCH22n<;Gyo?BlH)QWk*PoXECQjxp^ZDOq-oFhGoY{T1@=xAB2Cd7w?BzDI QB|%~6>FVdQ&MBb@0NoOr5dZ)H literal 0 HcmV?d00001 diff --git a/src/plugins/coreplugin/iwelcomepage.cpp b/src/plugins/coreplugin/iwelcomepage.cpp index 3eb63d80312..beef33f40d6 100644 --- a/src/plugins/coreplugin/iwelcomepage.cpp +++ b/src/plugins/coreplugin/iwelcomepage.cpp @@ -3,25 +3,8 @@ #include "iwelcomepage.h" -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -using namespace Utils; - namespace Core { -const char WITHACCENTCOLOR_PROPERTY_NAME[] = "_withAccentColor"; - static QList g_welcomePages; const QList IWelcomePage::allWelcomePages() @@ -39,171 +22,4 @@ IWelcomePage::~IWelcomePage() g_welcomePages.removeOne(this); } -QPalette WelcomePageFrame::buttonPalette(bool isActive, bool isCursorInside, bool forText) -{ - QPalette pal; - pal.setBrush(QPalette::Window, {}); - pal.setBrush(QPalette::WindowText, {}); - - Theme *theme = Utils::creatorTheme(); - if (isActive) { - if (forText) { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_BackgroundPrimaryColor)); - } else { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_AccentColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_AccentColor)); - } - } else { - if (isCursorInside) { - if (forText) { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_HoverColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_TextColor)); - } else { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_HoverColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_ForegroundSecondaryColor)); - } - } else { - if (forText) { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_TextColor)); - } else { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_BackgroundPrimaryColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_ForegroundSecondaryColor)); - } - } - } - return pal; -} - -WelcomePageFrame::WelcomePageFrame(QWidget *parent) - : QWidget(parent) -{ - setContentsMargins(1, 1, 1, 1); -} - -void WelcomePageFrame::paintEvent(QPaintEvent *event) -{ - QWidget::paintEvent(event); - QPainter p(this); - - qDrawPlainRect(&p, rect(), palette().color(QPalette::WindowText), 1); - - if (property(WITHACCENTCOLOR_PROPERTY_NAME).toBool()) { - const int accentRectWidth = 10; - const QRect accentRect = rect().adjusted(width() - accentRectWidth, 0, 0, 0); - p.fillRect(accentRect, creatorTheme()->color(Theme::Welcome_AccentColor)); - } -} - -class WelcomePageButtonPrivate -{ -public: - explicit WelcomePageButtonPrivate(WelcomePageButton *parent) - : q(parent) {} - bool isActive() const; - void doUpdate(bool cursorInside); - - WelcomePageButton *q; - QHBoxLayout *m_layout = nullptr; - QLabel *m_label = nullptr; - - std::function onClicked; - std::function activeChecker; -}; - -WelcomePageButton::WelcomePageButton(QWidget *parent) - : WelcomePageFrame(parent), d(new WelcomePageButtonPrivate(this)) -{ - setAutoFillBackground(true); - setPalette(buttonPalette(false, false, false)); - setContentsMargins(0, 1, 0, 1); - - d->m_label = new QLabel(this); - d->m_label->setPalette(buttonPalette(false, false, true)); - d->m_label->setAlignment(Qt::AlignCenter); - - d->m_layout = new QHBoxLayout; - d->m_layout->setSpacing(0); - d->m_layout->addWidget(d->m_label); - setSize(SizeLarge); - setLayout(d->m_layout); -} - -WelcomePageButton::~WelcomePageButton() -{ - delete d; -} - -void WelcomePageButton::mousePressEvent(QMouseEvent *) -{ - if (d->onClicked) - d->onClicked(); -} - -void WelcomePageButton::enterEvent(QEnterEvent *) -{ - d->doUpdate(true); -} - -void WelcomePageButton::leaveEvent(QEvent *) -{ - d->doUpdate(false); -} - -bool WelcomePageButtonPrivate::isActive() const -{ - return activeChecker && activeChecker(); -} - -void WelcomePageButtonPrivate::doUpdate(bool cursorInside) -{ - const bool active = isActive(); - q->setPalette(WelcomePageFrame::buttonPalette(active, cursorInside, false)); - const QPalette lpal = WelcomePageFrame::buttonPalette(active, cursorInside, true); - m_label->setPalette(lpal); - q->update(); -} - -void WelcomePageButton::setText(const QString &text) -{ - d->m_label->setText(text); -} - -void WelcomePageButton::setSize(Size size) -{ - const int hMargin = size == SizeSmall ? 12 : 26; - const int vMargin = size == SizeSmall ? 2 : 4; - d->m_layout->setContentsMargins(hMargin, vMargin, hMargin, vMargin); -} - -void WelcomePageButton::setWithAccentColor(bool withAccent) -{ - setProperty(WITHACCENTCOLOR_PROPERTY_NAME, withAccent); -} - -void WelcomePageButton::setActiveChecker(const std::function &value) -{ - d->activeChecker = value; -} - -void WelcomePageButton::recheckActive() -{ - bool isActive = d->isActive(); - d->doUpdate(isActive); -} - -void WelcomePageButton::click() -{ - if (d->onClicked) - d->onClicked(); -} - -void WelcomePageButton::setOnClicked(const std::function &value) -{ - d->onClicked = value; - if (d->isActive()) - click(); -} - } // namespace Core diff --git a/src/plugins/coreplugin/iwelcomepage.h b/src/plugins/coreplugin/iwelcomepage.h index 9a64dd3a701..1f59a791195 100644 --- a/src/plugins/coreplugin/iwelcomepage.h +++ b/src/plugins/coreplugin/iwelcomepage.h @@ -7,13 +7,10 @@ #include -#include #include -#include - QT_BEGIN_NAMESPACE -class QPixmap; +class QWidget; QT_END_NAMESPACE namespace Core { @@ -37,43 +34,4 @@ public: static const QList allWelcomePages(); }; -class WelcomePageButtonPrivate; - -class CORE_EXPORT WelcomePageFrame : public QWidget -{ -public: - WelcomePageFrame(QWidget *parent); - - void paintEvent(QPaintEvent *event) override; - - static QPalette buttonPalette(bool isActive, bool isCursorInside, bool forText); -}; - -class CORE_EXPORT WelcomePageButton : public WelcomePageFrame -{ -public: - enum Size { - SizeSmall, - SizeLarge, - }; - - explicit WelcomePageButton(QWidget *parent = nullptr); - ~WelcomePageButton() override; - - void mousePressEvent(QMouseEvent *) override; - void enterEvent(QEnterEvent *) override; - void leaveEvent(QEvent *) override; - - void setText(const QString &text); - void setSize(enum Size); - void setWithAccentColor(bool withAccent); - void setOnClicked(const std::function &value); - void setActiveChecker(const std::function &value); - void recheckActive(); - void click(); - -private: - WelcomePageButtonPrivate *d; -}; - } // Core diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index c188f6812c3..921046ffed4 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -267,6 +267,11 @@ QDateTime SessionManager::lastActiveTime(const QString &session) return d->m_lastActiveTimes.value(session); } +int SessionManager::sessionsCount() +{ + return d->m_sessions.count(); +} + FilePath SessionManager::sessionNameToFileName(const QString &session) { return ICore::userResourcePath(session + ".qws"); diff --git a/src/plugins/coreplugin/session.h b/src/plugins/coreplugin/session.h index 962db5172b5..ef51228b018 100644 --- a/src/plugins/coreplugin/session.h +++ b/src/plugins/coreplugin/session.h @@ -34,6 +34,7 @@ public: static QStringList sessions(); static QDateTime sessionDateTime(const QString &session); static QDateTime lastActiveTime(const QString &session); + static int sessionsCount(); static bool createSession(const QString &session); diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 44fc75270dd..636888d6b47 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -26,36 +27,34 @@ #include + +QT_BEGIN_NAMESPACE +void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); +QT_END_NAMESPACE + using namespace Utils; namespace Core { using namespace WelcomePageHelpers; +using namespace StyleHelper::SpacingTokens; static QColor themeColor(Theme::Color role) { return creatorTheme()->color(role); } -static QFont sizedFont(int size, const QWidget *widget) -{ - QFont f = widget->font(); - f.setPixelSize(size); - return f; -} - namespace WelcomePageHelpers { -QWidget *panelBar(QWidget *parent) +void setBackgroundColor(QWidget *widget, Theme::Color colorRole) { - auto frame = new QWidget(parent); - frame->setAutoFillBackground(true); - frame->setMinimumWidth(WelcomePageHelpers::HSpacing); - QPalette pal; - pal.setBrush(QPalette::Window, {}); - pal.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundPrimaryColor)); - frame->setPalette(pal); - return frame; + QPalette palette = creatorTheme()->palette(); + const QPalette::ColorRole role = QPalette::Window; + palette.setBrush(role, {}); + palette.setColor(role, creatorTheme()->color(colorRole)); + widget->setPalette(palette); + widget->setBackgroundRole(role); + widget->setAutoFillBackground(true); } void drawCardBackground(QPainter *painter, const QRectF &rect, @@ -77,30 +76,351 @@ void drawCardBackground(QPainter *painter, const QRectF &rect, painter->restore(); } +QWidget *createRule(Qt::Orientation orientation, QWidget *parent) +{ + auto rule = new QWidget(parent); + if (orientation == Qt::Horizontal) + rule->setFixedHeight(1); + else + rule->setFixedWidth(1); + setBackgroundColor(rule, Theme::Token_Stroke_Subtle); + return rule; +} + } // namespace WelcomePageHelpers -SearchBox::SearchBox(QWidget *parent) - : WelcomePageFrame(parent) +enum WidgetState { + WidgetStateDefault, + WidgetStateChecked, + WidgetStateHovered, +}; + +static const TextFormat &buttonTF(Button::Role role, WidgetState state) { - setAutoFillBackground(true); + using namespace WelcomePageHelpers; + static const TextFormat mediumPrimaryTF + {Theme::Token_Basic_White, StyleHelper::UiElement::UiElementButtonMedium, + Qt::AlignCenter | Qt::TextDontClip}; + static const TextFormat mediumSecondaryTF + {Theme::Token_Text_Default, mediumPrimaryTF.uiElement, mediumPrimaryTF.drawTextFlags}; + static const TextFormat smallPrimaryTF + {mediumPrimaryTF.themeColor, StyleHelper::UiElement::UiElementButtonSmall, + mediumPrimaryTF.drawTextFlags}; + static const TextFormat smallSecondaryTF + {mediumSecondaryTF.themeColor, smallPrimaryTF.uiElement, smallPrimaryTF.drawTextFlags}; + static const TextFormat smallListDefaultTF + {Theme::Token_Text_Default, StyleHelper::UiElement::UiElementIconStandard, + Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip}; + static const TextFormat smallListCheckedTF + {smallListDefaultTF.themeColor, StyleHelper::UiElement::UiElementIconActive, + smallListDefaultTF.drawTextFlags}; + static const TextFormat smallLinkDefaultTF + {Theme::Token_Text_Default, smallListDefaultTF.uiElement, smallListDefaultTF.drawTextFlags}; + static const TextFormat smallLinkHoveredTF + {Theme::Token_Accent_Default, smallListCheckedTF.uiElement, + smallLinkDefaultTF.drawTextFlags}; - m_lineEdit = new FancyLineEdit; - m_lineEdit->setFiltering(true); - m_lineEdit->setFrame(false); - m_lineEdit->setMinimumHeight(33); - m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false); + switch (role) { + case Button::MediumPrimary: return mediumPrimaryTF; + case Button::MediumSecondary: return mediumSecondaryTF; + case Button::SmallPrimary: return smallPrimaryTF; + case Button::SmallSecondary: return smallSecondaryTF; + case Button::SmallList: return (state == WidgetStateDefault) ? smallListDefaultTF + : smallListCheckedTF; + case Button::SmallLink: return (state == WidgetStateDefault) ? smallLinkDefaultTF + : smallLinkHoveredTF; + } + return mediumPrimaryTF; +} - QPalette pal = buttonPalette(false, false, true); - // for the margins - pal.setColor(QPalette::Window, m_lineEdit->palette().color(QPalette::Base)); - // for macOS dark mode - pal.setColor(QPalette::WindowText, themeColor(Theme::Welcome_ForegroundPrimaryColor)); - pal.setColor(QPalette::Text, themeColor(Theme::Welcome_TextColor)); +Button::Button(const QString &text, Role role, QWidget *parent) + : QPushButton(text, parent) + , m_role(role) +{ + // Prevent QMacStyle::subElementRect(SE_PushButtonLayoutItem) from changing our geometry + setFlat(true); + + updateMargins(); + if (m_role == SmallList) + setCheckable(true); + else if (m_role == SmallLink) + setCursor(Qt::PointingHandCursor); +} + +QSize Button::minimumSizeHint() const +{ + const TextFormat &tf = buttonTF(m_role, WidgetStateHovered); + const QFontMetrics fm(tf.font()); + const QSize textS = fm.size(Qt::TextShowMnemonic, text()); + const QMargins margins = contentsMargins(); + return {margins.left() + textS.width() + margins.right(), + margins.top() + tf.lineHeight() + margins.bottom()}; +} + +void Button::paintEvent(QPaintEvent *event) +{ + // Without pixmap + // +----------------+----------------+----------------+ + // | |(VPadding[S|XS])| | + // | +----------------+----------------+ + // |(HPadding[S|XS])|