diff options
author | The Qt Project <[email protected]> | 2024-11-20 09:05:36 +0000 |
---|---|---|
committer | The Qt Project <[email protected]> | 2024-11-20 09:05:36 +0000 |
commit | ceeeba5667948920fe62c06579ea9c670c55f1fe (patch) | |
tree | 79416c5841a49770a046965c0be02e03ae80cb06 /src | |
parent | 2af6e0e9843b1673c390f234c04590733b94da20 (diff) | |
parent | f4e75e1acbd1b44fc066fccc5e3f78409fa309f0 (diff) |
Merge "Merge remote-tracking branch 'origin/15.0'"
Diffstat (limited to 'src')
39 files changed, 422 insertions, 179 deletions
diff --git a/src/app/main.cpp b/src/app/main.cpp index f090c3e2d35..9617037e3e6 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -933,8 +933,13 @@ int main(int argc, char **argv) // shutdown plugin manager on the exit QObject::connect(&app, &QCoreApplication::aboutToQuit, &pluginManager, &PluginManager::shutdown); - if (Utils::HostOsInfo::isWindowsHost()) // Workaround for QTBUG-130696 and QTCREATORBUG-31890 + if (Utils::HostOsInfo::isWindowsHost()) { + // Workaround for QTBUG-130696 and QTCREATORBUG-31890 QApplication::setEffectEnabled(Qt::UI_FadeMenu, false); + // Disable menu animation which just looks bad + QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false); + } + return restarter.restartOrExit(app.exec()); } diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.cpp b/src/libs/3rdparty/libptyqt/conptyprocess.cpp index c957e0bdd9e..d8f0608ef16 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/conptyprocess.cpp @@ -988,8 +988,11 @@ bool ConPtyProcess::startProcess(const QString &executable, GetExitCodeProcess(hEvent, &exitCode); m_exitCode = exitCode; // Do not respawn if the object is about to be destructed - if (!m_aboutToDestruct) - emit notifier()->aboutToClose(); + if (!m_aboutToDestruct) { + ConptyClosePseudoConsole(m_ptyHandler); + m_ptyHandler = INVALID_HANDLE_VALUE; + emit notifier() -> aboutToClose(); + } m_shellCloseWaitNotifier->setEnabled(false); }, Qt::QueuedConnection); @@ -1028,7 +1031,7 @@ bool ConPtyProcess::startProcess(const QString &executable, bool ConPtyProcess::resize(qint16 cols, qint16 rows) { - if (m_ptyHandler == nullptr) + if (m_ptyHandler == INVALID_HANDLE_VALUE) { return false; } @@ -1047,49 +1050,45 @@ bool ConPtyProcess::resize(qint16 cols, qint16 rows) bool ConPtyProcess::kill() { - bool exitCode = false; - if (m_ptyHandler != INVALID_HANDLE_VALUE) { m_aboutToDestruct = true; // Close ConPTY - this will terminate client process if running WindowsContext::instance().closePseudoConsole(m_ptyHandler); + } - // Clean-up the pipes - if (INVALID_HANDLE_VALUE != m_hPipeOut) - CloseHandle(m_hPipeOut); - if (INVALID_HANDLE_VALUE != m_hPipeIn) - CloseHandle(m_hPipeIn); - - if (m_readThread) { - m_readThread->requestInterruption(); - if (!m_readThread->wait(1000)) - m_readThread->terminate(); - m_readThread->deleteLater(); - m_readThread = nullptr; - } - - delete m_shellCloseWaitNotifier; - m_shellCloseWaitNotifier = nullptr; + // Clean-up the pipes + if (INVALID_HANDLE_VALUE != m_hPipeOut) + CloseHandle(m_hPipeOut); + if (INVALID_HANDLE_VALUE != m_hPipeIn) + CloseHandle(m_hPipeIn); + + if (m_readThread) { + m_readThread->requestInterruption(); + if (!m_readThread->wait(1000)) + m_readThread->terminate(); + m_readThread->deleteLater(); + m_readThread = nullptr; + } - m_pid = 0; - m_ptyHandler = INVALID_HANDLE_VALUE; - m_hPipeIn = INVALID_HANDLE_VALUE; - m_hPipeOut = INVALID_HANDLE_VALUE; + delete m_shellCloseWaitNotifier; + m_shellCloseWaitNotifier = nullptr; - CloseHandle(m_shellProcessInformation.hThread); - CloseHandle(m_shellProcessInformation.hProcess); + m_pid = 0; + m_ptyHandler = INVALID_HANDLE_VALUE; + m_hPipeIn = INVALID_HANDLE_VALUE; + m_hPipeOut = INVALID_HANDLE_VALUE; - // Cleanup attribute list - if (m_shellStartupInfo.lpAttributeList) { - DeleteProcThreadAttributeList(m_shellStartupInfo.lpAttributeList); - HeapFree(GetProcessHeap(), 0, m_shellStartupInfo.lpAttributeList); - } + CloseHandle(m_shellProcessInformation.hThread); + CloseHandle(m_shellProcessInformation.hProcess); - exitCode = true; + // Cleanup attribute list + if (m_shellStartupInfo.lpAttributeList) { + DeleteProcThreadAttributeList(m_shellStartupInfo.lpAttributeList); + HeapFree(GetProcessHeap(), 0, m_shellStartupInfo.lpAttributeList); } - return exitCode; + return true; } IPtyProcess::PtyType ConPtyProcess::type() diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index ef87925be0e..c47c648c88a 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -731,7 +731,7 @@ Result FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &t if (srcModified == tgtModified) { // TODO: Create FilePath::hashFromContents() and compare hashes. const expected_str<QByteArray> srcContents = srcFilePath.fileContents(); - const expected_str<QByteArray> tgtContents = srcFilePath.fileContents(); + const expected_str<QByteArray> tgtContents = tgtFilePath.fileContents(); if (srcContents && srcContents == tgtContents) return Result::Ok; } diff --git a/src/libs/utils/icondisplay.cpp b/src/libs/utils/icondisplay.cpp index 1c9f9f6520f..93999708905 100644 --- a/src/libs/utils/icondisplay.cpp +++ b/src/libs/utils/icondisplay.cpp @@ -15,7 +15,6 @@ namespace Utils class IconDisplayPrivate { public: - QSize m_iconSize; QIcon m_icon; }; @@ -52,7 +51,10 @@ QSize IconDisplay::sizeHint() const if (d->m_icon.isNull()) return {}; - return d->m_icon.availableSizes().first(); + if (auto sizes = d->m_icon.availableSizes(); !sizes.isEmpty()) + return sizes.first(); + + return {}; } void IconDisplay::setIcon(const Icon &icon) diff --git a/src/libs/utils/mimetypes2/mimedatabase.cpp b/src/libs/utils/mimetypes2/mimedatabase.cpp index 68d513b5ff9..ff6346dae3d 100644 --- a/src/libs/utils/mimetypes2/mimedatabase.cpp +++ b/src/libs/utils/mimetypes2/mimedatabase.cpp @@ -126,6 +126,27 @@ void MimeDatabasePrivate::loadProviders() if (!m_additionalData.contains("utilslib.mimetypes")) { m_additionalData.insert("utilslib.mimetypes", QByteArray(R"--(<?xml version="1.0"?> <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> + <mime-type type="text/plain"> + <magic priority="20"> + <match value="This is TeX," type="string" offset="0"/> + <match value="This is METAFONT," type="string" offset="0"/> + <match value="/*" type="string" offset="0"/> + <match value="//" type="string" offset="0"/> + <match value=";;" type="string" offset="0"/> + <!-- UTF-16BE BOM --> + <match value="\xfe\xff" type="string" offset="0"/> + <!-- UTF-16LE BOM --> + <match value="\xff\xfe" type="string" offset="0"/> + <!-- UTF-8 BOM --> + <match value="\xef\xbb\xbf" type="string" offset="0"/> + </magic> + + <glob pattern="*.txt"/> + <glob pattern="*.text"/> + <glob pattern="*.def"/> + <glob pattern="*.list"/> + <glob pattern="*.in"/> + </mime-type> <mime-type type="application/x-compressed-tar"> <comment>Tar archive (gzip-compressed)</comment> <sub-class-of type="application/gzip"/> diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index af4833c3ff2..4bcaad92a15 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -403,13 +403,22 @@ public: static_cast<Pty::PtyInputFlag>(m_inputFlags.toInt())); } - emit readyRead(m_ptyProcess->readAll(), {}); + const QByteArray data = m_ptyProcess->readAll(); + if (!data.isEmpty()) + emit readyRead(data, {}); }); connect(m_ptyProcess->notifier(), &QIODevice::aboutToClose, this, [this] { if (m_ptyProcess) { const ProcessResultData result = {m_ptyProcess->exitCode(), QProcess::NormalExit, QProcess::UnknownError, {}}; + + const QByteArray restOfOutput = m_ptyProcess->readAll(); + if (!restOfOutput.isEmpty()) { + emit readyRead(restOfOutput, {}); + m_ptyProcess->notifier()->disconnect(); + } + emit done(result); return; } diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index 2aa2f760427..dae35b817ba 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -106,100 +106,132 @@ QTCREATOR_UTILS_EXPORT bool readMultiLineString(const QJsonValue &value, QString return true; } +enum class Base { Dec, Hex }; + +static bool isHex(const QChar &c) +{ + return (c >= 'a' && c <= 'f') || (c >= 'A' && c < 'F'); +} + +static bool isDigit(const QChar &c, Base base) +{ + if (base == Base::Hex && isHex(c)) + return true; + return c.isDigit(); +} + +static int trailingNumber(const QString &line, Base base = Base::Dec) +{ + int lastNumberPos = line.size(); + while (lastNumberPos > 0) { + if (!isDigit(line.at(lastNumberPos - 1), base)) + break; + --lastNumberPos; + } + bool ok = true; + const int port = line.mid(lastNumberPos).toInt(&ok, base == Base::Dec ? 10 : 16); + return ok ? port : -1; +} + +/* + +Parsing algo is simple: +Depending on the value of 1st column we detect whether it's Win, Mac / Android / Qnx, or Linux +output. + +In case of Win or Linux, we select the 2nd column for port parsing, otherwise we select +the 4th column. + +For selected column we parse the trailing digits. In case of Linux we take into account hex digits. + +Expected output (see tst_StringUtils::testParseUsedPortFromNetstatOutput_data()): + + === Windows === + + Active Connections + + Proto Local Address Foreign Address State + TCP 0.0.0.0:80 0.0.0.0:0 LISTENING + TCP 0.0.0.0:113 0.0.0.0:0 LISTENING + [...] + TCP 10.9.78.4:14714 0.0.0.0:0 LISTENING + TCP 10.9.78.4:50233 12.13.135.180:993 ESTABLISHED + [...] + TCP [::]:445 [::]:0 LISTENING + TCP 192.168.0.80:51905 169.55.74.50:443 ESTABLISHED + UDP [fe80::880a:2932:8dff:a858%6]:1900 *:* + + === Mac === + + Active Internet connections (including servers) + Proto Recv-Q Send-Q Local Address Foreign Address (state) + tcp4 0 0 192.168.1.12.55687 88.198.14.66.443 ESTABLISHED + tcp6 0 0 2a01:e34:ee42:d0.55684 2a02:26f0:ff::5c.443 ESTABLISHED + [...] + tcp4 0 0 *.631 *.* LISTEN + tcp6 0 0 *.631 *.* LISTEN + [...] + udp4 0 0 192.168.79.1.123 *.* + udp4 0 0 192.168.8.1.123 *.* + + === QNX === + + Active Internet connections (including servers) + Proto Recv-Q Send-Q Local Address Foreign Address State + tcp 0 0 10.9.7.5.22 10.9.7.4.46592 ESTABLISHED + tcp 0 0 *.8000 *.* LISTEN + tcp 0 0 *.22 *.* LISTEN + udp 0 0 *.* *.* + udp 0 0 *.* *.* + Active Internet6 connections (including servers) + Proto Recv-Q Send-Q Local Address Foreign Address (state) + tcp6 0 0 *.22 *.* LISTEN + + === Android === + + tcp 0 0 10.0.2.16:49088 142.250.180.74:443 ESTABLISHED + tcp 0 0 10.0.2.16:48380 142.250.186.196:443 CLOSE_WAIT + tcp6 0 0 [::]:5555 [::]:* LISTEN + tcp6 0 0 ::ffff:127.0.0.1:39417 [::]:* LISTEN + tcp6 0 0 ::ffff:10.0.2.16:35046 ::ffff:142.250.203.:443 ESTABLISHED + tcp6 0 0 ::ffff:127.0.0.1:46265 ::ffff:127.0.0.1:33155 TIME_WAIT + udp 0 0 10.0.2.16:50950 142.250.75.14:443 ESTABLISHED + udp 2560 0 10.0.2.16:68 10.0.2.2:67 ESTABLISHED + udp 0 0 0.0.0.0:5353 0.0.0.0:* + udp6 0 0 [::]:36662 [::]:* + + === Linux === + + sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ... + 0: 00000000:2805 00000000:0000 0A 00000000:00000000 00:00000000 00000000 ... +*/ QTCREATOR_UTILS_EXPORT int parseUsedPortFromNetstatOutput(const QByteArray &line) { - const QByteArray trimmed = line.trimmed(); - int base = 0; - QByteArray portString; - - if (trimmed.startsWith("TCP") || trimmed.startsWith("UDP")) { - // Windows. Expected output is something like - // - // Active Connections - // - // Proto Local Address Foreign Address State - // TCP 0.0.0.0:80 0.0.0.0:0 LISTENING - // TCP 0.0.0.0:113 0.0.0.0:0 LISTENING - // [...] - // TCP 10.9.78.4:14714 0.0.0.0:0 LISTENING - // TCP 10.9.78.4:50233 12.13.135.180:993 ESTABLISHED - // [...] - // TCP [::]:445 [::]:0 LISTENING - // TCP 192.168.0.80:51905 169.55.74.50:443 ESTABLISHED - // UDP [fe80::880a:2932:8dff:a858%6]:1900 *:* - const int firstBracketPos = trimmed.indexOf('['); - int colonPos = -1; - if (firstBracketPos == -1) { - colonPos = trimmed.indexOf(':'); // IPv4 - } else { - // jump over host part - const int secondBracketPos = trimmed.indexOf(']', firstBracketPos + 1); - colonPos = trimmed.indexOf(':', secondBracketPos); - } - const int firstDigitPos = colonPos + 1; - const int spacePos = trimmed.indexOf(' ', firstDigitPos); - if (spacePos < 0) - return -1; - const int len = spacePos - firstDigitPos; - base = 10; - portString = trimmed.mid(firstDigitPos, len); - } else if (trimmed.startsWith("tcp") || trimmed.startsWith("udp")) { - // macOS. Expected output is something like - // - // Active Internet connections (including servers) - // Proto Recv-Q Send-Q Local Address Foreign Address (state) - // tcp4 0 0 192.168.1.12.55687 88.198.14.66.443 ESTABLISHED - // tcp6 0 0 2a01:e34:ee42:d0.55684 2a02:26f0:ff::5c.443 ESTABLISHED - // [...] - // tcp4 0 0 *.631 *.* LISTEN - // tcp6 0 0 *.631 *.* LISTEN - // [...] - // udp4 0 0 192.168.79.1.123 *.* - // udp4 0 0 192.168.8.1.123 *.* - int firstDigitPos = -1; - int spacePos = -1; - if (trimmed[3] == '6') { - // IPV6 - firstDigitPos = trimmed.indexOf('.') + 1; - spacePos = trimmed.indexOf(' ', firstDigitPos); - } else { - // IPV4 - firstDigitPos = trimmed.indexOf('.') + 1; - spacePos = trimmed.indexOf(' ', firstDigitPos); - firstDigitPos = trimmed.lastIndexOf('.', spacePos) + 1; - } - if (spacePos < 0) - return -1; - base = 10; - portString = trimmed.mid(firstDigitPos, spacePos - firstDigitPos); - if (portString == "*") + const QStringList columns = QString::fromUtf8(line).split(' ', Qt::SkipEmptyParts); + if (columns.size() < 3) + return -1; + + const QString firstColumn = columns.first(); + QString columnToParse; + Base base = Base::Dec; + + if (firstColumn.startsWith("TCP") || firstColumn.startsWith("UDP")) { // Windows + columnToParse = columns.at(1); + } else if (firstColumn.startsWith("tcp") || firstColumn.startsWith("udp")) { // Mac, Android, Qnx + if (columns.size() < 4) return -1; + columnToParse = columns.at(3); + } else if (firstColumn.size() > 1 && firstColumn.at(1) == ':') { // Linux + columnToParse = columns.at(1); + base = Base::Hex; } else { - // Expected output on Linux something like - // - // sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ... - // 0: 00000000:2805 00000000:0000 0A 00000000:00000000 00:00000000 00000000 ... - // - const int firstColonPos = trimmed.indexOf(':'); - if (firstColonPos < 0) - return -1; - const int secondColonPos = trimmed.indexOf(':', firstColonPos + 1); - if (secondColonPos < 0) - return -1; - const int spacePos = trimmed.indexOf(' ', secondColonPos + 1); - if (spacePos < 0) - return -1; - const int len = spacePos - secondColonPos - 1; - base = 16; - portString = trimmed.mid(secondColonPos + 1, len); + return -1; } - bool ok = true; - const int port = portString.toInt(&ok, base); - if (!ok) { + const int port = trailingNumber(columnToParse, base); + if (port == -1) { qWarning("%s: Unexpected string '%s' is not a port. Tried to read from '%s'", - Q_FUNC_INFO, line.data(), portString.data()); - return -1; + Q_FUNC_INFO, line.data(), columnToParse.toUtf8().data()); } return port; } diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index d8f5044ad36..a683eda32a3 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -44,6 +44,7 @@ #include <QNetworkReply> #include <QUrlQuery> +#include <cmath> #include <memory> constexpr char s_axivionTextMarkId[] = "AxivionTextMark"; @@ -79,8 +80,14 @@ QString anyToSimpleString(const Dto::Any &any) return any.getString(); if (any.isBool()) return QString("%1").arg(any.getBool()); - if (any.isDouble()) - return QString::number(any.getDouble()); + if (any.isDouble()) { + const double value = any.getDouble(); + double intPart; + const double fragPart = std::modf(value, &intPart); + if (fragPart != 0) + return QString::number(value); + return QString::number(value, 'f', 0); + } if (any.isNull()) return QString(); // or NULL?? if (any.isList()) { diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index e511b2f4a52..617ece82771 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -827,6 +827,16 @@ QMainWindow *ICore::mainWindow() /*! Returns a widget pointer suitable to use as parent for QDialogs. + + Especially for modal dialogs it is important to use the current modal + dialog as a parent (if there is one) for the new dialog, because + otherwise the new dialog can open behind the old one, while also + blocking interaction with that. Using dialogParent() ensures this. + + Also use dialogParent() for non-modal dialogs that do not need any + specific lifetime management. If you need to control the lifetime of + a non-modal dialog (for example because another part of the + application depends on it), use a more specific parent instead. */ QWidget *ICore::dialogParent() { diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index f04883446aa..6d32e8e1d8a 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -243,6 +243,7 @@ signals: void repositoryChanged(const Utils::FilePath &repository); void filesChanged(const QStringList &files); void updateFileStatus(const Utils::FilePath &repository, const QStringList &files); + void clearFileStatus(const Utils::FilePath &repository); void configurationChanged(); private: diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index 565e996c483..e6f9fad6712 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -23,6 +23,7 @@ #include <QCursor> #include <QElapsedTimer> #include <QHash> +#include <QLoggingCategory> #include <QMenu> #include <QMimeData> #include <QPair> @@ -47,8 +48,9 @@ const int minChunkSize = 1000; const auto defaultInterval = 10ms; const auto maxInterval = 1000ms; -namespace Core { +static Q_LOGGING_CATEGORY(chunkLog, "qtc.core.outputChunking", QtWarningMsg) +namespace Core { namespace Internal { class OutputWindowPrivate @@ -515,11 +517,14 @@ void OutputWindow::handleNextOutputChunk() } } + qCDebug(chunkLog) << "next queued chunk has" << chunk.first.size() << "bytes"; if (actualChunkSize == chunk.first.size()) { - handleOutputChunk(chunk.first, chunk.second); + qCDebug(chunkLog) << "chunk can be written in one go"; + handleOutputChunk(chunk.first, chunk.second, ChunkCompleteness::Complete); d->queuedOutput.removeFirst(); } else { - handleOutputChunk(chunk.first.left(actualChunkSize), chunk.second); + qCDebug(chunkLog) << "chunk needs to be split"; + handleOutputChunk(chunk.first.left(actualChunkSize), chunk.second, ChunkCompleteness::Split); chunk.first.remove(0, actualChunkSize); } if (!d->queuedOutput.isEmpty()) @@ -530,7 +535,8 @@ void OutputWindow::handleNextOutputChunk() } } -void OutputWindow::handleOutputChunk(const QString &output, OutputFormat format) +void OutputWindow::handleOutputChunk( + const QString &output, OutputFormat format, ChunkCompleteness completeness) { QString out = output; if (out.size() > d->maxCharCount) { @@ -562,9 +568,18 @@ void OutputWindow::handleOutputChunk(const QString &output, OutputFormat format) formatterTimer.start(); d->formatter.appendMessage(out, format); ++d->formatterCalls; + qCDebug(chunkLog) << "formatter took" << formatterTimer.elapsed() << "ms"; if (formatterTimer.elapsed() > d->queueTimer.interval()) { d->queueTimer.setInterval(std::min(maxInterval, d->queueTimer.intervalAsDuration() * 2)); d->chunkSize = std::max(minChunkSize, d->chunkSize / 2); + qCDebug(chunkLog) << "increasing interval to" << d->queueTimer.interval() + << "ms and lowering chunk size to" << d->chunkSize << "bytes"; + } else if (completeness == ChunkCompleteness::Split + && formatterTimer.elapsed() < d->queueTimer.interval() / 2) { + d->queueTimer.setInterval(std::max(1ms, d->queueTimer.intervalAsDuration() * 2 / 3)); + d->chunkSize = d->chunkSize * 1.5; + qCDebug(chunkLog) << "lowering interval to" << d->queueTimer.interval() + << "ms and increasing chunk size to" << d->chunkSize << "bytes"; } if (d->scrollToBottom) { @@ -594,6 +609,8 @@ void OutputWindow::discardExcessiveOutput() d->queuedSizeHistory.clear(); d->queuedSizeHistory << queuedSize; bool discard = d->queuedSizeHistory.size() > int(10) && queuedSize > 5 * d->chunkSize; + if (discard) + qCDebug(chunkLog) << "discarding output due to size"; // Criterion 2: Are we too slow? // If it would take longer than a minute to print the pending output and we have @@ -601,6 +618,8 @@ void OutputWindow::discardExcessiveOutput() if (!discard) { discard = d->formatterCalls >= 10 && (queuedSize / d->chunkSize) * d->queueTimer.intervalAsDuration() > 60s; + if (discard) + qCDebug(chunkLog) << "discarding output due to time"; } if (discard) { @@ -733,7 +752,7 @@ void OutputWindow::flush() } d->queueTimer.stop(); for (const auto &chunk : std::as_const(d->queuedOutput)) - handleOutputChunk(chunk.first, chunk.second); + handleOutputChunk(chunk.first, chunk.second, ChunkCompleteness::Complete); d->queuedOutput.clear(); d->formatter.flush(); } diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h index dc5bde19f8f..1ecd5abff74 100644 --- a/src/plugins/coreplugin/outputwindow.h +++ b/src/plugins/coreplugin/outputwindow.h @@ -98,7 +98,11 @@ private: void enableUndoRedo(); void filterNewContent(); void handleNextOutputChunk(); - void handleOutputChunk(const QString &output, Utils::OutputFormat format); + + enum class ChunkCompleteness { Complete, Split }; + void handleOutputChunk( + const QString &output, Utils::OutputFormat format, ChunkCompleteness completeness); + void discardExcessiveOutput(); void discardPendingToolOutput(); void updateAutoScroll(); diff --git a/src/plugins/coreplugin/secretaspect.cpp b/src/plugins/coreplugin/secretaspect.cpp index 3017f6458bb..4e70380affd 100644 --- a/src/plugins/coreplugin/secretaspect.cpp +++ b/src/plugins/coreplugin/secretaspect.cpp @@ -76,8 +76,9 @@ void SecretAspect::readSecret(const std::function<void(Utils::expected_str<QStri qWarning() << "No Keychain available, reading from plaintext"; qtcSettings()->beginGroup("Secrets"); auto value = qtcSettings()->value(settingsKey()); - d->callReadCallbacks(fromSettingsValue(value).toString()); qtcSettings()->endGroup(); + + d->callReadCallbacks(fromSettingsValue(value).toString()); return; } @@ -126,7 +127,7 @@ void SecretAspect::writeSettings() const if (!QKeychain::isAvailable()) { qtcSettings()->beginGroup("Secrets"); - qtcSettings()->setValue(settingsKey(), toSettingsValue(variantValue())); + qtcSettings()->setValue(settingsKey(), toSettingsValue(d->value)); qtcSettings()->endGroup(); d->wasEdited = false; return; @@ -198,8 +199,7 @@ void SecretAspect::addToLayoutImpl(Layouting::Layout &parent) })); connect(showPasswordButton, &ShowPasswordButton::toggled, edit, [showPasswordButton, edit] { - edit->setEchoMode( - showPasswordButton->isChecked() ? QLineEdit::Normal : QLineEdit::PasswordEchoOnEdit); + edit->setEchoMode(showPasswordButton->isChecked() ? QLineEdit::Normal : QLineEdit::Password); }); connect(edit, &FancyLineEdit::textChanged, this, [this](const QString &text) { diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp index f61f0276410..9aa99a8c479 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp @@ -333,7 +333,7 @@ Link attemptDeclDef(const QTextCursor &cursor, Snapshot snapshot, if (decl->postfix_declarator_list && decl->postfix_declarator_list->value) funcDecl = decl->postfix_declarator_list->value->asFunctionDeclarator(); if (funcDecl) - target = symbolFinder->findMatchingDefinition(funcDecl->symbol, snapshot); + target = symbolFinder->findMatchingDefinition(funcDecl->symbol, snapshot, false); else if (simpleDecl->symbols) target = symbolFinder->findMatchingVarDefinition(simpleDecl->symbols->value, snapshot); } @@ -365,7 +365,7 @@ Symbol *findDefinition(Symbol *symbol, const Snapshot &snapshot, SymbolFinder *s if (!symbol->type()->asFunctionType()) return nullptr; // not a function declaration - return symbolFinder->findMatchingDefinition(symbol, snapshot); + return symbolFinder->findMatchingDefinition(symbol, snapshot, false); } bool maybeAppendArgumentOrParameterList(QString *expression, const QTextCursor &textCursor) @@ -816,7 +816,8 @@ void FollowSymbolUnderCursor::switchDeclDef( // Link to function definition/declaration Utils::Link symbolLink; if (functionDeclarationSymbol) { - Symbol *symbol = symbolFinder->findMatchingDefinition(functionDeclarationSymbol, snapshot); + Symbol *symbol + = symbolFinder->findMatchingDefinition(functionDeclarationSymbol, snapshot, false); if (symbol) symbolLink = symbol->toLink(); } else if (declarationSymbol) { diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp index 7ae02294588..7575b00caf2 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp +++ b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp @@ -131,7 +131,7 @@ public: private: Function *maybeDefinitionFor(Function *func) const { - if (Function *definition = m_finder.findMatchingDefinition(func, m_params.snapshot)) + if (Function *definition = m_finder.findMatchingDefinition(func, m_params.snapshot, true)) return definition; return func; } diff --git a/src/plugins/cppeditor/insertionpointlocator.cpp b/src/plugins/cppeditor/insertionpointlocator.cpp index e957ae77bf9..b0d2414f44b 100644 --- a/src/plugins/cppeditor/insertionpointlocator.cpp +++ b/src/plugins/cppeditor/insertionpointlocator.cpp @@ -562,7 +562,7 @@ static InsertionLocation nextToSurroundingDefinitions(Symbol *declaration, if (s->isGenerated() || !(surroundingFunctionDecl = isNonVirtualFunctionDeclaration(s))) continue; if ((definitionFunction = symbolFinder.findMatchingDefinition(surroundingFunctionDecl, - changes.snapshot()))) + changes.snapshot(), true))) { if (destinationFile.isEmpty() || destinationFile == definitionFunction->filePath()) { prefix = QLatin1String("\n\n"); @@ -578,9 +578,8 @@ static InsertionLocation nextToSurroundingDefinitions(Symbol *declaration, surroundingFunctionDecl = isNonVirtualFunctionDeclaration(s); if (!surroundingFunctionDecl) continue; - if ((definitionFunction = symbolFinder.findMatchingDefinition(surroundingFunctionDecl, - changes.snapshot()))) - { + if ((definitionFunction = symbolFinder.findMatchingDefinition( + surroundingFunctionDecl, changes.snapshot(), true))) { if (destinationFile.isEmpty() || destinationFile == definitionFunction->filePath()) { suffix = QLatin1String("\n\n"); break; diff --git a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp index aa475c4f124..0f9f8461380 100644 --- a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp +++ b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp @@ -345,7 +345,7 @@ private: QList<Symbol *> unimplemented; SymbolFinder symbolFinder; for (Symbol * const s : std::as_const(m_declarations)) { - if (!symbolFinder.findMatchingDefinition(s, snapshot())) + if (!symbolFinder.findMatchingDefinition(s, snapshot(), true)) unimplemented << s; } if (unimplemented.isEmpty()) diff --git a/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp b/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp index 6b982decc78..2d7dd65a2bc 100644 --- a/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp +++ b/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp @@ -1384,6 +1384,23 @@ auto Derived::func() const && noexcept -> void {} QuickFixOperationTest(testDocuments, &factory); } + void testUnimplementedOverload() + { + const QByteArray original = + "struct S {\n" + " S();\n" + " @S(const S &) {}\n" + "};\n"; + const QByteArray expected = + "struct S {\n" + " S();\n" + " S(const S &);\n" + "};\n\n" + "S::S(const S &) {}\n"; + + MoveFuncDefOutside factory; + QuickFixOperationTest(singleDocument(original, expected), &factory); + } }; class MoveAllFuncDefOutsideTest : public QObject diff --git a/src/plugins/cppeditor/symbolfinder.h b/src/plugins/cppeditor/symbolfinder.h index 10591b38d4f..37481a08158 100644 --- a/src/plugins/cppeditor/symbolfinder.h +++ b/src/plugins/cppeditor/symbolfinder.h @@ -13,8 +13,6 @@ #include <QSet> #include <QStringList> -#include <set> - namespace CPlusPlus { class Class; class Declaration; @@ -33,7 +31,7 @@ public: CPlusPlus::Function *findMatchingDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot, - bool strict = false); + bool strict); QList<CPlusPlus::Function *> findMatchingDefinitions( CPlusPlus::Symbol *declaration, const CPlusPlus::Snapshot &snapshot, bool strict, diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index 0c367adc5ea..a6a284d80fd 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -32,7 +32,9 @@ #include <utils/infolabel.h> #include <utils/layoutbuilder.h> #include <utils/markdownbrowser.h> +#include <utils/mimeutils.h> #include <utils/networkaccessmanager.h> +#include <utils/stringutils.h> #include <utils/styledbar.h> #include <utils/stylehelper.h> #include <utils/temporarydirectory.h> @@ -243,6 +245,17 @@ private: const char kRestartSetting[] = "RestartAfterPluginEnabledChanged"; +// Copy paste from Core::Internal::CorePlugin::loadMimeFromPlugin +// TODO make code usable by other plugins. +static void loadMimeFromPlugin(const ExtensionSystem::PluginSpec *plugin) +{ + const QJsonObject metaData = plugin->metaData(); + const QJsonValue mimetypes = metaData.value("Mimetypes"); + QString mimetypeString; + if (Utils::readMultiLineString(mimetypes, &mimetypeString)) + Utils::addMimeTypes(plugin->name() + ".mimetypes", mimetypeString.trimmed().toUtf8()); +} + class PluginStatusWidget : public QWidget { public: @@ -266,17 +279,19 @@ public: return; const bool doIt = m_pluginView.data().setPluginsEnabled({spec}, checked); if (doIt) { - if (!ICore::infoBar()->canInfoBeAdded(kRestartSetting)) - return; - - Utils::InfoBarEntry info( - kRestartSetting, - Core::Tr::tr("Plugin changes will take effect after restart.")); - info.addCustomButton(Tr::tr("Restart Now"), [] { - ICore::infoBar()->removeInfo(kRestartSetting); - QTimer::singleShot(0, ICore::instance(), &ICore::restart); - }); - ICore::infoBar()->addInfo(info); + if (checked && spec->isEffectivelySoftloadable()) { + ExtensionSystem::PluginManager::loadPluginsAtRuntime({spec}); + loadMimeFromPlugin(spec); + } else if (ICore::infoBar()->canInfoBeAdded(kRestartSetting)) { + Utils::InfoBarEntry info( + kRestartSetting, + Core::Tr::tr("Plugin changes will take effect after restart.")); + info.addCustomButton(Tr::tr("Restart Now"), [] { + ICore::infoBar()->removeInfo(kRestartSetting); + QTimer::singleShot(0, ICore::instance(), &ICore::restart); + }); + ICore::infoBar()->addInfo(info); + } ExtensionSystem::PluginManager::writeSettings(); } else { diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 0b35a79e310..f80ed6bd858 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -38,6 +38,7 @@ #include <utils/temporaryfile.h> #include <utils/theme/theme.h> +#include <vcsbase/commonvcssettings.h> #include <vcsbase/submitfilemodel.h> #include <vcsbase/vcsbasediffeditorcontroller.h> #include <vcsbase/vcsbaseeditor.h> @@ -805,15 +806,27 @@ GitClient &gitClient() GitClient::GitClient() : VcsBase::VcsBaseClientImpl(&Internal::settings()) - , m_timer(new QTimer) { m_gitQtcEditor = QString::fromLatin1("\"%1\" -client -block -pid %2") .arg(QCoreApplication::applicationFilePath()) .arg(QCoreApplication::applicationPid()); - connect(m_timer.get(), &QTimer::timeout, this, &GitClient::updateModificationInfos); - using namespace std::chrono_literals; - m_timer->setInterval(10s); + if (VcsBase::Internal::commonSettings().vcsShowStatus()) + setupTimer(); + connect(&VcsBase::Internal::commonSettings().vcsShowStatus, &Utils::BaseAspect::changed, + [this] { + bool enable = VcsBase::Internal::commonSettings().vcsShowStatus(); + QTC_CHECK(enable == bool(!m_timer)); + if (enable) { + setupTimer(); + } else { + m_timer.reset(); + for (auto fp : std::as_const(m_modifInfos)) { + m_modifInfos[fp.rootPath].modifiedFiles.clear(); + emitClearFileStatus(fp.rootPath); + } + } + }); } GitClient::~GitClient() = default; @@ -904,7 +917,7 @@ void GitClient::stopMonitoring(const Utils::FilePath &path) for (const FilePath &subModule : subPaths) m_modifInfos.remove(subModule); m_modifInfos.remove(directory); - if (m_modifInfos.isEmpty()) + if (m_modifInfos.isEmpty() && m_timer) m_timer->stop(); } @@ -918,8 +931,10 @@ void GitClient::monitorDirectory(const Utils::FilePath &path) const QList<FilePath> subPaths = submoduleDataToAbsolutePath(submoduleList(directory), directory); for (const FilePath &subModule : subPaths) m_modifInfos.insert(subModule, {subModule, {}}); - if (!m_timer->isActive()) - m_timer->start(); + + if (!m_timer) + return; + updateModificationInfos(); } @@ -971,7 +986,8 @@ void GitClient::updateModificationInfos() emitFileStatusChanged(info.rootPath, statusChangedFiles); }; - vcsExecWithHandler(path, {"status", "-s", "--porcelain"}, this, command, RunFlags::NoOutput); + vcsExecWithHandler(path, {"status", "-s", "--porcelain", "--ignore-submodules"}, + this, command, RunFlags::NoOutput); } } @@ -3894,6 +3910,16 @@ ColorNames GitClient::colorNames() return result; } +void GitClient::setupTimer() +{ + QTC_ASSERT(!m_timer, return); + m_timer.reset(new QTimer); + connect(m_timer.get(), &QTimer::timeout, this, &GitClient::updateModificationInfos); + using namespace std::chrono_literals; + m_timer->setInterval(10s); + m_timer->start(); +} + } // Git::Internal #include "gitclient.moc" diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 1429469ca79..ca2ed56d78d 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -406,6 +406,7 @@ private: QString msgBoxText, const QString &buttonName, const QString &gitCommand, ContinueCommandMode continueMode); + void setupTimer(); mutable Utils::FilePath m_gitVersionForBinary; mutable QVersionNumber m_cachedGitVersion; mutable QMap<Utils::FilePath, Utils::FilePath> m_gitExecutableCache; diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 38b3b344710..fc0d69bef60 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -1909,6 +1909,11 @@ void emitFileStatusChanged(const FilePath &repository, const QStringList &files) emit dd->updateFileStatus(repository, files); } +void emitClearFileStatus(const FilePath &repository) +{ + emit dd->clearFileStatus(repository); +} + void startRebaseFromCommit(const FilePath &workingDirectory, const QString &commit) { dd->startRebaseFromCommit(workingDirectory, commit); diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index a6658fbf8d4..705807bbacc 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -23,6 +23,7 @@ bool isCommitEditorOpen(); void emitFilesChanged(const QStringList &); void emitRepositoryChanged(const Utils::FilePath &); void emitFileStatusChanged(const Utils::FilePath &repository, const QStringList &files); +void emitClearFileStatus(const Utils::FilePath &repository); void startRebaseFromCommit(const Utils::FilePath &workingDirectory, const QString &commit); void manageRemotes(); void initRepository(); diff --git a/src/plugins/lua/bindings/texteditor.cpp b/src/plugins/lua/bindings/texteditor.cpp index 2fc4e3b0e88..0ca9a7f4e93 100644 --- a/src/plugins/lua/bindings/texteditor.cpp +++ b/src/plugins/lua/bindings/texteditor.cpp @@ -52,6 +52,12 @@ TextEditor::TextEditorWidget *getSuggestionReadyEditorWidget(TextEditor::TextDoc std::unique_ptr<EmbeddedWidgetInterface> addEmbeddedWidget( BaseTextEditor *editor, QWidget *widget, std::variant<int, Position> cursorPosition) { + if (!widget) + throw sol::error("No widget provided"); + + if (!editor) + throw sol::error("No editor provided"); + if (!editor->textDocument() || !editor->textDocument()->document()) throw sol::error("No text document set"); diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index cecd14b9c3a..73c7dac7588 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -144,6 +144,11 @@ QIcon KitManagerConfigWidget::displayIcon() const return m_modifiedKit->displayIcon(); } +void KitManagerConfigWidget::clearCachedDisplayName() +{ + m_cachedDisplayName.clear(); +} + void KitManagerConfigWidget::setFocusToName() { m_nameEdit->selectAll(); diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.h b/src/plugins/projectexplorer/kitmanagerconfigwidget.h index d23ab59cb70..a2aaec581b8 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.h +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.h @@ -32,6 +32,7 @@ public: QString displayName() const; QIcon displayIcon() const; + void clearCachedDisplayName(); // FIXME: Remove cached name? void setFocusToName(); void apply(); diff --git a/src/plugins/projectexplorer/kitoptionspage.cpp b/src/plugins/projectexplorer/kitoptionspage.cpp index 2cdc1451757..37a74517246 100644 --- a/src/plugins/projectexplorer/kitoptionspage.cpp +++ b/src/plugins/projectexplorer/kitoptionspage.cpp @@ -143,6 +143,7 @@ public: void setHasUniqueName(bool on) { m_hasUniqueName = on; + update(); } void ensureWidget(); @@ -354,6 +355,7 @@ Kit *KitModel::markForAddition(Kit *baseKit) } else { k->setup(); } + node->widget()->clearCachedDisplayName(); k->setUnexpandedDisplayName(newName); if (!m_defaultNode) diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 833643197de..ace041c9e75 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -463,6 +463,7 @@ void FlatModel::handleProjectAdded(Project *project) if (vc) { vc->monitorDirectory(rootPath); connect(vc, &IVersionControl::updateFileStatus, this, &FlatModel::updateVCStatusFor); + connect(vc, &IVersionControl::clearFileStatus, this, &FlatModel::clearVCStatusFor); } addOrRebuildProjectModel(project); @@ -485,6 +486,20 @@ void FlatModel::updateVCStatusFor(const Utils::FilePath root, const QStringList }); } +void FlatModel::clearVCStatusFor(const Utils::FilePath &root) +{ + ProjectTree::forEachNode([this, root](Node *n) { + FileNode *fileNode = n->asFileNode(); + if (!fileNode) + return; + if (fileNode->filePath().isChildOf(root)) { + fileNode->resetModificationState(); + const QModelIndex index = indexForNode(fileNode); + emit dataChanged(index, index, {Qt::ForegroundRole}); + } + }); +} + void FlatModel::handleProjectRemoved(Project *project) { destroyItem(nodeForProject(project)); diff --git a/src/plugins/projectexplorer/projectmodels.h b/src/plugins/projectexplorer/projectmodels.h index a07279388a4..8cee63309bc 100644 --- a/src/plugins/projectexplorer/projectmodels.h +++ b/src/plugins/projectexplorer/projectmodels.h @@ -86,6 +86,7 @@ private: void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen); bool trimEmptyDirectories(WrapperNode *parent); void updateVCStatusFor(const Utils::FilePath root, const QStringList &files); + void clearVCStatusFor(const Utils::FilePath &root); ExpandData expandDataForNode(const Node *node) const; void loadExpandData(); diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp index 8fe63773ecc..c3f09d1fecd 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.cpp +++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp @@ -101,6 +101,8 @@ public: ToolchainTreeItem(bundle), changed(c), m_parentWidget(parentWidget) {} + ~ExtendedToolchainTreeItem() override { delete m_widget; } + QVariant data(int column, int role) const override { switch (role) { diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp index 64ad03052d7..5854b92d3de 100644 --- a/src/plugins/python/pythoneditor.cpp +++ b/src/plugins/python/pythoneditor.cpp @@ -297,7 +297,8 @@ PythonDocument::PythonDocument() void PythonDocument::updateCurrentPython() { - updatePython(detectPython(filePath())); + if (Core::DocumentModel::entryForDocument(this)) + updatePython(detectPython(filePath())); } void PythonDocument::updatePython(const FilePath &python) diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index 3c05b8f87ed..bbfb5c75474 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -334,8 +334,10 @@ void PyLSConfigureAssistant::installPythonLanguageServer(const FilePath &python, void PyLSConfigureAssistant::openDocument(const FilePath &python, TextEditor::TextDocument *document) { resetEditorInfoBar(document); - if (!PythonSettings::pylsEnabled() || !python.exists()) + if (!PythonSettings::pylsEnabled() || !python.exists() + || !Core::DocumentModel::entryForDocument(document)) { return; + } if (auto client = pythonClients().value(python)) { LanguageClientManager::openDocumentWithClient(document, client); diff --git a/src/plugins/qmlprofiler/quick3dframeview.cpp b/src/plugins/qmlprofiler/quick3dframeview.cpp index 3d0141d0ed9..64f51c9970f 100644 --- a/src/plugins/qmlprofiler/quick3dframeview.cpp +++ b/src/plugins/qmlprofiler/quick3dframeview.cpp @@ -54,13 +54,13 @@ Quick3DFrameView::Quick3DFrameView(QmlProfilerModelManager *profilerModelManager connect(m_compareFrameView.get(), &Quick3DMainView::gotoSourceLocation, this, &Quick3DFrameView::gotoSourceLocation); - auto groupLayout = new QVBoxLayout(this); + auto groupLayout = new QVBoxLayout; groupLayout->setContentsMargins(0,0,0,0); groupLayout->setSpacing(0); - auto hMainLayout = new QHBoxLayout(this); + auto hMainLayout = new QHBoxLayout; hMainLayout->setContentsMargins(0,0,0,0); hMainLayout->setSpacing(0); - auto hFrameLayout = new QHBoxLayout(this); + auto hFrameLayout = new QHBoxLayout; hFrameLayout->setContentsMargins(0,0,0,0); hFrameLayout->setSpacing(0); auto view3DComboBox = new QComboBox(this); diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index f5f1fe091f1..4a411c1f456 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -129,6 +129,27 @@ void FileSystemAccessTest::initTestCase() QVERIFY(m_localRemoteDestDir.exists()); QVERIFY(m_remoteLocalDestDir.exists()); QVERIFY(m_remoteRemoteDestDir.exists()); + + const FilePath localPath = localTempDir / "sourceChildDir" / "grandchildDir"; + const FilePath remotePath = remoteTempDir / "destChildDir" / "grandchildDir"; + if (localPath.exists()) + localPath.parentDir().removeRecursively(); + if (remotePath.exists()) + remotePath.parentDir().removeRecursively(); + QVERIFY(!localPath.exists()); + QVERIFY(!remotePath.exists()); + QVERIFY(!localPath.parentDir().exists()); + QVERIFY(!remotePath.parentDir().exists()); + QVERIFY(localPath.ensureWritableDir()); + QVERIFY(remotePath.ensureWritableDir()); + QVERIFY(localPath.exists()); + QVERIFY(remotePath.exists()); + QVERIFY(localPath.parentDir().removeRecursively()); + QVERIFY(remotePath.parentDir().removeRecursively()); + QVERIFY(!localPath.exists()); + QVERIFY(!remotePath.exists()); + QVERIFY(!localPath.parentDir().exists()); + QVERIFY(!remotePath.parentDir().exists()); } void FileSystemAccessTest::cleanupTestCase() diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index 1cab9f82924..83eb9c7d13d 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -367,9 +367,14 @@ QString CodeAssistantPrivate::proposalPrefix() const void CodeAssistantPrivate::invalidateCurrentRequestData() { m_processor = nullptr; - disconnect( - m_requestProvider, &QObject::destroyed, this, &CodeAssistantPrivate::cancelCurrentRequest); - m_requestProvider = nullptr; + if (m_requestProvider) { + disconnect( + m_requestProvider, + &QObject::destroyed, + this, + &CodeAssistantPrivate::cancelCurrentRequest); + m_requestProvider = nullptr; + } m_receivedContentWhileWaiting = false; } diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index 5f009487108..f546ae4154b 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -80,9 +80,16 @@ CommonVcsSettings::CommonVcsSettings() lineWrapWidth.setSuffix(Tr::tr(" characters")); lineWrapWidth.setDefaultValue(72); + vcsShowStatus.setSettingsKey("ShowVcsStatus"); + vcsShowStatus.setDefaultValue(false); + vcsShowStatus.setLabelText(Tr::tr("Show VCS file status")); + vcsShowStatus.setToolTip(Tr::tr("Request file status updates from files and reflect them " + "on the project tree.")); + setLayouter([this] { using namespace Layouting; return Column { + vcsShowStatus, br, Row { lineWrap, lineWrapWidth, st }, Form { submitMessageCheckScript, br, diff --git a/src/plugins/vcsbase/commonvcssettings.h b/src/plugins/vcsbase/commonvcssettings.h index ced68d31b97..da962bca643 100644 --- a/src/plugins/vcsbase/commonvcssettings.h +++ b/src/plugins/vcsbase/commonvcssettings.h @@ -3,11 +3,13 @@ #pragma once +#include "vcsbase_global.h" + #include <utils/aspects.h> namespace VcsBase::Internal { -class CommonVcsSettings final : public Utils::AspectContainer +class VCSBASE_EXPORT CommonVcsSettings final : public Utils::AspectContainer { public: CommonVcsSettings(); @@ -22,8 +24,9 @@ public: Utils::BoolAspect lineWrap{this}; Utils::IntegerAspect lineWrapWidth{this}; + Utils::BoolAspect vcsShowStatus{this}; }; -CommonVcsSettings &commonSettings(); +VCSBASE_EXPORT CommonVcsSettings &commonSettings(); } // VcsBase::Internal diff --git a/src/shared/qbs b/src/shared/qbs -Subproject 862deed5ec60c36c603d5ac84546804ea67cc67 +Subproject e44a761b3b2081bb3ac4ee320d868310bd37312 |