Merge "Merge remote-tracking branch 'origin/9.0' into qds/dev" into qds/dev

This commit is contained in:
The Qt Project
2022-11-09 15:42:39 +00:00
149 changed files with 89684 additions and 74780 deletions

View File

@@ -488,7 +488,7 @@ void AndroidDeployQtStep::gatherFilesToPull()
void AndroidDeployQtStep::doRun()
{
runInThread([this] { return runImpl(); });
m_synchronizer.addFuture(runInThread([this] { return runImpl(); }));
}
void AndroidDeployQtStep::runCommand(const CommandLine &command)

View File

@@ -12,6 +12,7 @@
#include <utils/commandline.h>
#include <utils/environment.h>
#include <utils/futuresynchronizer.h>
namespace Utils { class QtcProcess; }
@@ -91,6 +92,8 @@ private:
Utils::FilePath m_workingDirectory;
Utils::Environment m_environment;
AndroidDeviceInfo m_deviceInfo;
Utils::FutureSynchronizer m_synchronizer;
};
}

View File

@@ -512,7 +512,7 @@ void AndroidDeviceManager::setupWifiForDevice(const IDevice::Ptr &device, QWidge
return;
}
QTimer::singleShot(2000, parent, [adbSelector, &parent]() {
QTimer::singleShot(2000, parent, [adbSelector, parent]() {
// Get device IP address
QStringList args = adbSelector;
args.append({"shell", "ip", "route"});

View File

@@ -18,6 +18,9 @@ namespace CatchXml {
const char TestCaseElement[] = "TestCase";
const char SectionElement[] = "Section";
const char ExceptionElement[] = "Exception";
const char InfoElement[] = "Info";
const char WarningElement[] = "Warning";
const char FailureElement[] = "Failure";
const char ExpressionElement[] = "Expression";
const char ExpandedElement[] = "Expanded";
const char BenchmarkResults[] = "BenchmarkResults";
@@ -102,6 +105,13 @@ void CatchOutputReader::processOutputLine(const QByteArray &outputLineWithNewLin
m_currentResult = m_shouldFail ? ResultType::UnexpectedPass : ResultType::Pass;
else
m_currentResult = m_mayFail || m_shouldFail ? ResultType::ExpectedFail : ResultType::Fail;
} else if (m_currentTagName == CatchXml::WarningElement) {
m_currentResult = ResultType::MessageWarn;
} else if (m_currentTagName == CatchXml::InfoElement) {
m_currentResult = ResultType::MessageInfo;
} else if (m_currentTagName == CatchXml::FailureElement) {
m_currentResult = ResultType::Fail;
recordTestInformation(m_xmlReader.attributes());
} else if (m_currentTagName == CatchXml::BenchmarkResults) {
recordBenchmarkInformation(m_xmlReader.attributes());
m_currentResult = ResultType::Benchmark;
@@ -121,7 +131,10 @@ void CatchOutputReader::processOutputLine(const QByteArray &outputLineWithNewLin
const auto text = m_xmlReader.text();
if (m_currentTagName == CatchXml::ExpandedElement) {
m_currentExpression.append(text);
} else if (m_currentTagName == CatchXml::ExceptionElement) {
} else if (m_currentTagName == CatchXml::ExceptionElement
|| m_currentTagName == CatchXml::InfoElement
|| m_currentTagName == CatchXml::WarningElement
|| m_currentTagName == CatchXml::FailureElement) {
m_currentExpression.append('\n').append(text.trimmed());
}
break;
@@ -138,10 +151,15 @@ void CatchOutputReader::processOutputLine(const QByteArray &outputLineWithNewLin
} else if (currentTag == QLatin1String(CatchXml::GroupElement)) {
testOutputNodeFinished(GroupNode);
} else if (currentTag == QLatin1String(CatchXml::ExpressionElement)
|| currentTag == QLatin1String(CatchXml::FailureElement)
|| currentTag == QLatin1String(CatchXml::BenchmarkResults)) {
sendResult(m_currentResult);
m_currentExpression.clear();
m_testCaseInfo.pop();
} else if (currentTag == QLatin1String(CatchXml::WarningElement)
|| currentTag == QLatin1String(CatchXml::InfoElement)) {
sendResult(m_currentResult);
m_currentExpression.clear();
}
break;
}
@@ -255,6 +273,8 @@ void CatchOutputReader::sendResult(const ResultType result)
.arg(catchResult->description()));
} else if (result == ResultType::Benchmark || result == ResultType::MessageFatal) {
catchResult->setDescription(m_currentExpression);
} else if (result == ResultType::MessageWarn || result == ResultType::MessageInfo) {
catchResult->setDescription(m_currentExpression.trimmed());
}
reportResult(catchResult);

View File

@@ -417,6 +417,7 @@ IAssistProposal *CustomAssistProcessor::perform(const AssistInterface *interface
break;
}
}
delete interface;
GenericProposalModelPtr model(new GenericProposalModel);
model->loadContent(completions);
const auto proposal = new GenericProposal(m_position, model);

View File

@@ -12,6 +12,7 @@
#include <languageclient/languageclientsymbolsupport.h>
#include <languageserverprotocol/lsptypes.h>
#include <languageserverprotocol/jsonrpcmessages.h>
#include <texteditor/codeassist/assistinterface.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/codeassist/iassistprovider.h>
#include <texteditor/textdocument.h>
@@ -41,8 +42,9 @@ public:
void resetData(bool resetFollowSymbolData);
private:
IAssistProposal *perform(const AssistInterface *) override
IAssistProposal *perform(const AssistInterface *interface) override
{
delete interface;
return nullptr;
}

View File

@@ -164,9 +164,15 @@ void doSemanticHighlighting(
const Position endPos = startPos.withOffset(token.length, &doc);
return Range(startPos, endPos);
};
const auto isOutputParameter = [&ast, &tokenRange](const ExpandedSemanticToken &token) {
const int clangdMajorVersion = clangdVersion.majorVersion();
const auto isOutputParameter = [&ast, &tokenRange, clangdMajorVersion]
(const ExpandedSemanticToken &token) {
if (token.modifiers.contains(QLatin1String("usedAsMutableReference")))
return true;
if (token.modifiers.contains(QLatin1String("usedAsMutablePointer")))
return true;
if (clangdMajorVersion >= 16)
return false;
if (token.type != "variable" && token.type != "property" && token.type != "parameter")
return false;
const Range range = tokenRange(token);
@@ -260,7 +266,7 @@ void doSemanticHighlighting(
};
const std::function<HighlightingResult(const ExpandedSemanticToken &)> toResult
= [&ast, &isOutputParameter, &tokenRange, ver = clangdVersion.majorVersion()]
= [&ast, &isOutputParameter, &tokenRange, clangdMajorVersion]
(const ExpandedSemanticToken &token) {
TextStyles styles;
if (token.type == "variable") {
@@ -277,7 +283,7 @@ void doSemanticHighlighting(
? C_VIRTUAL_METHOD : C_FUNCTION;
if (token.modifiers.contains("definition")) {
styles.mixinStyles.push_back(C_FUNCTION_DEFINITION);
} else if (ver < 16 && ast.isValid()) {
} else if (clangdMajorVersion < 16 && ast.isValid()) {
const ClangdAstPath path = getAstPath(ast, tokenRange(token));
if (path.length() > 1) {
const ClangdAstNode declNode = path.at(path.length() - 2);
@@ -291,7 +297,7 @@ void doSemanticHighlighting(
styles.mainStyle = C_TYPE;
if (token.modifiers.contains("constructorOrDestructor")) {
styles.mainStyle = C_FUNCTION;
} else if (ver < 16 && ast.isValid()) {
} else if (clangdMajorVersion < 16 && ast.isValid()) {
const ClangdAstPath path = getAstPath(ast, tokenRange(token));
if (!path.isEmpty()) {
if (path.last().kind() == "CXXConstructor") {

View File

@@ -13,6 +13,7 @@
#include <utils/qtcassert.h>
#include <QApplication>
#include <QMetaObject>
#include <QTextCursor>
#include <optional>
@@ -68,6 +69,7 @@ ClangdSwitchDeclDef::ClangdSwitchDeclDef(ClangdClient *client, TextDocument *doc
[this](const DocumentUri &uri, const DocumentSymbolsResult &symbols) {
if (uri != d->uri)
return;
d->client->documentSymbolCache()->disconnect(this);
d->docSymbols = symbols;
if (d->ast)
d->handleDeclDefSwitchReplies();
@@ -108,7 +110,7 @@ void ClangdSwitchDeclDef::emitDone()
return;
d->done = true;
emit done();
QMetaObject::invokeMethod(this, &ClangdSwitchDeclDef::done, Qt::QueuedConnection);
}
std::optional<ClangdAstNode> ClangdSwitchDeclDef::Private::getFunctionNode() const

View File

@@ -1012,12 +1012,6 @@ void ClangdTestHighlighting::test_data()
<< QList<int>{C_LOCAL} << 0;
QTest::newRow("const pointer argument") << 491 << 26 << 491 << 27
<< QList<int>{C_LOCAL, C_OUTPUT_ARGUMENT} << 0;
QTest::newRow("non-const reference via member function call as output argument (object)")
<< 580 << 29 << 580 << 30
<< QList<int>{C_LOCAL, C_OUTPUT_ARGUMENT} << 0;
QTest::newRow("non-const reference via member function call as output argument (function)")
<< 580 << 31 << 580 << 37
<< QList<int>{C_FUNCTION, C_OUTPUT_ARGUMENT} << 0;
QTest::newRow("value argument") << 501 << 57 << 501 << 58
<< QList<int>{C_LOCAL} << 0;
QTest::newRow("non-const ref argument as second arg") << 501 << 61 << 501 << 62
@@ -1026,8 +1020,6 @@ void ClangdTestHighlighting::test_data()
<< QList<int>{C_PARAMETER, C_OUTPUT_ARGUMENT} << 0;
QTest::newRow("non-const pointer argument expression") << 513 << 30 << 513 << 31
<< QList<int>{C_LOCAL, C_OUTPUT_ARGUMENT} << 0;
QTest::newRow("non-const ref argument from qualified member (object)") << 525 << 31 << 525 << 39
<< QList<int>{C_LOCAL, C_OUTPUT_ARGUMENT} << 0;
QTest::newRow("non-const ref argument from qualified member (member)") << 525 << 40 << 525 << 46
<< QList<int>{C_FIELD, C_OUTPUT_ARGUMENT} << 0;
QTest::newRow("non-const ref argument to constructor") << 540 << 47 << 540 << 55
@@ -1394,14 +1386,6 @@ void ClangdTestHighlighting::test()
actualStyles << s;
}
QEXPECT_FAIL("non-const reference via member function call as output argument (object)",
"See below", Continue);
QEXPECT_FAIL("non-const reference via member function call as output argument (function)",
"Without punctuation and comment tokens from clangd, it's not possible "
"to highlight entire expressions. But do we really want this? What about nested "
"calls where the inner arguments are const?",
Continue);
QCOMPARE(actualStyles, expectedStyles);
QCOMPARE(result.kind, expectedKind);
}

View File

@@ -39,7 +39,11 @@ void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
// This is a separate pass, don't do it unless it's the full formatting.
style.FixNamespaceComments = false;
#if LLVM_VERSION_MAJOR >= 16
style.AlignTrailingComments = {clang::format::FormatStyle::TCAS_Never, 0};
#else
style.AlignTrailingComments = false;
#endif
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
return;

View File

@@ -49,7 +49,11 @@ clang::format::FormatStyle qtcStyle()
#else
style.AlignOperands = true;
#endif
#if LLVM_VERSION_MAJOR >= 16
style.AlignTrailingComments = {FormatStyle::TCAS_Always, 0};
#else
style.AlignTrailingComments = true;
#endif
style.AllowAllParametersOfDeclarationOnNextLine = true;
#if LLVM_VERSION_MAJOR >= 10
style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;

View File

@@ -88,6 +88,7 @@ const char DEVELOPMENT_TEAM_FLAG[] = "Ios:DevelopmentTeam:Flag";
const char PROVISIONING_PROFILE_FLAG[] = "Ios:ProvisioningProfile:Flag";
const char CMAKE_OSX_ARCHITECTURES_FLAG[] = "CMAKE_OSX_ARCHITECTURES:DefaultFlag";
const char QT_QML_DEBUG_FLAG[] = "Qt:QML_DEBUG_FLAG";
const char QT_QML_DEBUG_PARAM[] = "-DQT_QML_DEBUG";
const char CMAKE_QT6_TOOLCHAIN_FILE_ARG[]
= "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=%{Qt:QT_INSTALL_PREFIX}/lib/cmake/Qt6/qt.toolchain.cmake";
const char CMAKE_BUILD_TYPE[] = "CMake.Build.Type";
@@ -876,7 +877,7 @@ CMakeConfig CMakeBuildSettingsWidget::getQmlDebugCxxFlags()
"CMAKE_CXX_FLAGS_RELWITHDEBINFO",
"CMAKE_CXX_FLAGS_INIT"};
const QByteArrayList cxxFlags{"CMAKE_CXX_FLAGS_INIT", "CMAKE_CXX_FLAGS"};
const QByteArray qmlDebug("-DQT_QML_DEBUG");
const QByteArray qmlDebug(QT_QML_DEBUG_PARAM);
CMakeConfig changedConfig;
@@ -1446,8 +1447,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id)
[this] {
if (aspect<QtSupport::QmlDebuggingAspect>()->value()
== TriState::Enabled) {
return QLatin1String(
"-DQT_QML_DEBUG");
return QLatin1String(QT_QML_DEBUG_PARAM);
}
return QLatin1String();
});
@@ -1665,7 +1665,7 @@ bool CMakeBuildConfiguration::hasQmlDebugging(const CMakeConfig &config)
// such that in doubt we leave the QML Debugging setting at "Leave at default"
const QString cxxFlagsInit = config.stringValueOf("CMAKE_CXX_FLAGS_INIT");
const QString cxxFlags = config.stringValueOf("CMAKE_CXX_FLAGS");
return cxxFlagsInit.contains("-DQT_QML_DEBUG") && cxxFlags.contains("-DQT_QML_DEBUG");
return cxxFlagsInit.contains(QT_QML_DEBUG_PARAM) && cxxFlags.contains(QT_QML_DEBUG_PARAM);
}
void CMakeBuildConfiguration::buildTarget(const QString &buildTarget)

View File

@@ -1186,8 +1186,8 @@ void CMakeBuildSystem::updateQmlJSCodeModel(const QStringList &extraHeaderPaths,
return;
Project *p = project();
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager
->defaultProjectInfoForProject(p);
QmlJS::ModelManagerInterface::ProjectInfo projectInfo
= modelManager->defaultProjectInfoForProject(p, p->files(Project::HiddenRccFolders));
projectInfo.importPaths.clear();

View File

@@ -739,7 +739,8 @@ bool EditorManagerPrivate::skipOpeningBigTextFile(const FilePath &filePath)
if (!filePath.exists())
return false;
const MimeType mimeType = Utils::mimeTypeForFile(filePath);
const MimeType mimeType = Utils::mimeTypeForFile(filePath,
MimeMatchMode::MatchDefaultAndRemote);
if (!mimeType.inherits("text/plain"))
return false;

View File

@@ -166,7 +166,8 @@ const EditorTypeList EditorType::defaultEditorTypes(const MimeType &mimeType)
const EditorTypeList EditorType::preferredEditorTypes(const FilePath &filePath)
{
// default factories by mime type
const Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath);
const Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath,
MimeMatchMode::MatchDefaultAndRemote);
EditorTypeList factories = defaultEditorTypes(mimeType);
// user preferred factory to front
EditorType *userPreferred = Internal::userPreferredEditorTypes().value(mimeType);

View File

@@ -175,7 +175,9 @@ QList<IWizardFactory*> IWizardFactory::allWizardFactories()
QHash<Id, IWizardFactory *> sanityCheck;
for (const FactoryCreator &fc : std::as_const(s_factoryCreators)) {
IWizardFactory *newFactory = fc();
QTC_ASSERT(newFactory, continue);
// skip factories referencing wizard page generators provided by plugins not loaded
if (!newFactory)
continue;
IWizardFactory *existingFactory = sanityCheck.value(newFactory->id());
QTC_ASSERT(existingFactory != newFactory, continue);

View File

@@ -949,7 +949,8 @@ void MainWindow::openFile()
static IDocumentFactory *findDocumentFactory(const QList<IDocumentFactory*> &fileFactories,
const FilePath &filePath)
{
const QString typeName = Utils::mimeTypeForFile(filePath).name();
const QString typeName = Utils::mimeTypeForFile(filePath, MimeMatchMode::MatchDefaultAndRemote)
.name();
return Utils::findOrDefault(fileFactories, [typeName](IDocumentFactory *f) {
return f->mimeTypes().contains(typeName);
});

View File

@@ -112,7 +112,7 @@ void GdbMi::parseResultOrValue(DebuggerOutputParser &parser)
}
// Reads one \ooo entity.
static bool parseOctalEscapedHelper(DebuggerOutputParser &parser, QByteArray &buffer)
static bool parseOctalEscapedHelper(DebuggerOutputParser &parser, QString &buffer)
{
if (parser.remainingChars() < 4)
return false;
@@ -130,7 +130,7 @@ static bool parseOctalEscapedHelper(DebuggerOutputParser &parser, QByteArray &bu
return true;
}
static bool parseHexEscapedHelper(DebuggerOutputParser &parser, QByteArray &buffer)
static bool parseHexEscapedHelper(DebuggerOutputParser &parser, QString &buffer)
{
if (parser.remainingChars() < 4)
return false;
@@ -178,15 +178,16 @@ static void parseSimpleEscape(DebuggerOutputParser &parser, QString &result)
// *or* one escaped char, *or* one unescaped char.
static void parseCharOrEscape(DebuggerOutputParser &parser, QString &result)
{
QByteArray buffer;
while (parseOctalEscapedHelper(parser, buffer))
const int oldSize = result.size();
while (parseOctalEscapedHelper(parser, result))
;
while (parseHexEscapedHelper(parser, buffer))
while (parseHexEscapedHelper(parser, result))
;
if (!buffer.isEmpty()) {
result.append(QString::fromUtf8(buffer));
} else if (parser.isCurrent('\\')) {
if (result.size() != oldSize)
return;
if (parser.isCurrent('\\')) {
parser.advance();
parseSimpleEscape(parser, result);
} else {
@@ -254,7 +255,6 @@ void GdbMi::parseTuple_helper(DebuggerOutputParser &parser)
{
parser.skipCommas();
//qDebug() << "parseTuple_helper: " << parser.buffer();
QString buf = parser.buffer();
m_type = Tuple;
while (!parser.isAtEnd()) {
if (parser.isCurrent('}')) {

View File

@@ -16,6 +16,7 @@
#include <QGuiApplication>
#include <QScrollBar>
#include <QTimer>
#include <QToolTip>
#include <QVBoxLayout>
#include <QWheelEvent>
@@ -100,6 +101,11 @@ LiteHtmlHelpViewer::LiteHtmlHelpViewer(QWidget *parent)
&QLiteHtmlWidget::contextMenuRequested,
this,
&LiteHtmlHelpViewer::showContextMenu);
connect(m_viewer, &QLiteHtmlWidget::linkHighlighted, this, [this](const QUrl &url) {
m_highlightedLink = url;
if (!url.isValid())
QToolTip::hideText();
});
auto layout = new QVBoxLayout;
setLayout(layout);
layout->setContentsMargins(0, 0, 0, 0);
@@ -284,6 +290,12 @@ bool LiteHtmlHelpViewer::eventFilter(QObject *src, QEvent *e)
goForward(1);
return true;
}
} else if (e->type() == QEvent::ToolTip) {
auto he = static_cast<QHelpEvent *>(e);
if (m_highlightedLink.isValid())
QToolTip::showText(he->globalPos(),
m_highlightedLink.toDisplayString(),
m_viewer->viewport());
}
return HelpViewer::eventFilter(src, e);
}

View File

@@ -4,11 +4,11 @@
#pragma once
#include "helpviewer.h"
#include "openpagesmanager.h"
#include <qlitehtmlwidget.h>
#include <QTextBrowser>
#include <QUrl>
#include <optional>
@@ -68,6 +68,7 @@ private:
QLiteHtmlWidget *m_viewer;
std::vector<HistoryItem> m_backItems;
std::vector<HistoryItem> m_forwardItems;
QUrl m_highlightedLink;
};
} // namespace Internal

View File

@@ -293,7 +293,8 @@ LanguageClientCompletionAssistProcessor::~LanguageClientCompletionAssistProcesso
QTextDocument *LanguageClientCompletionAssistProcessor::document() const
{
return m_document;
QTC_ASSERT(m_assistInterface, return nullptr);
return m_assistInterface->textDocument();
}
QList<AssistProposalItemInterface *> LanguageClientCompletionAssistProcessor::generateCompletionItems(
@@ -315,6 +316,7 @@ static QString assistReasonString(AssistReason reason)
IAssistProposal *LanguageClientCompletionAssistProcessor::perform(const AssistInterface *interface)
{
m_assistInterface.reset(interface);
QTC_ASSERT(m_client, return nullptr);
m_pos = interface->position();
m_basePos = m_pos;
@@ -366,7 +368,6 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform(const AssistIn
m_client->sendMessage(completionRequest);
m_client->addAssistProcessor(this);
m_currentRequest = completionRequest.id();
m_document = interface->textDocument();
m_filePath = interface->filePath();
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime()
<< " : request completions at " << m_pos
@@ -425,7 +426,7 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse(
model->loadContent(proposalItems);
LanguageClientCompletionProposal *proposal = new LanguageClientCompletionProposal(m_basePos,
model);
proposal->m_document = m_document;
proposal->m_document = m_assistInterface->textDocument();
proposal->m_pos = m_pos;
proposal->setSupportsPrefix(false);
setAsyncProposalAvailable(proposal);

View File

@@ -11,6 +11,7 @@
#include <texteditor/codeassist/iassistprocessor.h>
#include <QPointer>
#include <QScopedPointer>
#include <functional>
#include <optional>
@@ -74,7 +75,7 @@ protected:
private:
void handleCompletionResponse(const LanguageServerProtocol::CompletionRequest::Response &response);
QPointer<QTextDocument> m_document;
QScopedPointer<const TextEditor::AssistInterface> m_assistInterface;
Utils::FilePath m_filePath;
QPointer<Client> m_client;
std::optional<LanguageServerProtocol::MessageId> m_currentRequest;

View File

@@ -10,6 +10,8 @@
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
#include <QScopedPointer>
using namespace TextEditor;
using namespace LanguageServerProtocol;
@@ -66,6 +68,7 @@ FunctionHintProcessor::FunctionHintProcessor(Client *client)
IAssistProposal *FunctionHintProcessor::perform(const AssistInterface *interface)
{
const QScopedPointer<const AssistInterface> deleter(interface);
QTC_ASSERT(m_client, return nullptr);
m_pos = interface->position();
QTextCursor cursor(interface->textDocument());

View File

@@ -196,12 +196,22 @@ public:
EnvironmentItems changes;
QStringList pathAdditions; // clazy:exclude=inefficient-qlist-soft
// The Desktop version depends on the Qt shared libs in Qul_DIR/bin.
// If CMake's fileApi is avaialble, we can rely on the "Add library search path to PATH"
// feature of the run configuration. Otherwise, we just prepend the path, here.
if (mcuTarget->toolChainPackage()->isDesktopToolchain()
&& !CMakeProjectManager::CMakeToolManager::defaultCMakeTool()->hasFileApi())
pathAdditions.append((qtForMCUsSdkPackage->path() / "bin").toUserOutput());
// The Desktop version depends on the Qt shared libs.
// As CMake's fileApi is available, we can rely on the "Add library search path to PATH"
// feature of the run configuration.
//
// Since MinGW support is added from Qul 2.3.0,
// the Qt shared libs for Windows desktop platform have been moved
// from Qul_DIR/bin to Qul_DIR/lib/(msvc|gnu)
// and the QPA plugin has been moved to the same location.
// So Windows host requires to add the path in this case.
if (mcuTarget->toolChainPackage()->isDesktopToolchain() && HostOsInfo::isWindowsHost()
&& !McuSupportOptions::isLegacyVersion(mcuTarget->qulVersion())) {
const FilePath libPath = (qtForMCUsSdkPackage->path() / "lib"
/ mcuTarget->desktopCompilerId());
pathAdditions.append(libPath.toUserOutput());
changes.append({"QT_QPA_PLATFORM_PLUGIN_PATH", libPath.toUserOutput()});
}
auto processPackage = [&pathAdditions](const McuPackagePtr &package) {
if (package->isAddToSystemPath())
@@ -261,6 +271,12 @@ public:
true);
}
if (!McuSupportOptions::isLegacyVersion(mcuTarget->qulVersion())
&& HostOsInfo::isWindowsHost()) {
// From 2.3.0, QUL_COMPILER_NAME needs to be set on Windows
// to select proper cmake files depending on the toolchain for Windows.
configMap.insert("QUL_COMPILER_NAME", mcuTarget->desktopCompilerId().toLatin1());
}
} else {
const FilePath cMakeToolchainFile = mcuTarget->toolChainFilePackage()->path();
@@ -287,7 +303,7 @@ public:
false);
}
configMap.insert("QUL_PLATFORM", mcuTarget->platform().name.toUtf8());
configMap.insert("QUL_PLATFORM", mcuTarget->platform().name.toLower().toUtf8());
if (mcuTarget->colorDepth() != McuTarget::UnspecifiedColorDepth)
configMap.insert("QUL_COLOR_DEPTH", QString::number(mcuTarget->colorDepth()).toLatin1());
@@ -593,6 +609,11 @@ void updatePathsInExistingKits(const SettingsHandler::Ptr &settingsHandler)
for (const auto &target : std::as_const(repo.mcuTargets)) {
if (target->isValid()) {
for (auto *kit : kitsWithMismatchedDependencies(target.get())) {
if (kitQulVersion(kit) != target->qulVersion()) {
//Do not update kits made for other Qt for MCUs SDK versions
continue;
}
auto changes = cMakeConfigToMap(CMakeConfigurationKitAspect::configuration(kit));
const auto updateForPackage = [&changes](const McuPackagePtr &package) {

View File

@@ -30,23 +30,45 @@ using namespace Utils;
namespace McuSupport::Internal {
static const Utils::FilePath expandWildcards(const Utils::FilePath& path)
// Utils::FileFilter do not support globbing with "*" placed in the middle of the path,
// since it is required for paths such as "Microsoft Visual Studio/2019/*/VC/Tools/MSVC/*/bin/Hostx64/x64"
// The filter is applied for each time a wildcard character is found in a path component.
// Returns a pair of the longest path if multiple ones exists and the number of components that were not found.
static const std::pair<Utils::FilePath, int> expandWildcards(
const FilePath path, const QList<QStringView> patternComponents)
{
if (!path.fileName().contains("*") && !path.fileName().contains("?"))
return path;
// Only absolute paths are currently supported
// Call FilePath::cleanPath on the path before calling this function
if (!path.exists() || path.isRelativePath())
return {path, patternComponents.size()};
const FilePath p = path.parentDir();
// All components are found
if (patternComponents.empty())
return {path, patternComponents.size()};
auto entries = p.dirEntries(
Utils::FileFilter({path.fileName()}, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot));
const QString currentComponent = patternComponents.front().toString();
FilePath currentPath = path / currentComponent;
if (entries.isEmpty())
return path;
if (!currentComponent.contains("*") && !currentComponent.contains("?") && currentPath.exists())
return expandWildcards(path / currentComponent,
{patternComponents.constBegin() + 1, patternComponents.constEnd()});
auto entries = path.dirEntries(
Utils::FileFilter({currentComponent}, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot));
std::pair<FilePath, int> retPair = {path, patternComponents.size()};
// Return the last match (can correspond to the latest version)
sort(entries, [](const FilePath &a, const FilePath &b) { return a.fileName() < b.fileName(); });
for (const auto &entry : entries) {
auto [entry_path, remaining_components] = expandWildcards(entry,
{patternComponents.constBegin()
+ 1,
patternComponents.constEnd()});
if (remaining_components <= retPair.second)
retPair = {entry_path, remaining_components};
}
return entries.last();
return retPair;
}
Macros *McuSdkRepository::globalMacros()
@@ -60,7 +82,32 @@ void McuSdkRepository::expandVariablesAndWildcards()
for (const auto &target : std::as_const(mcuTargets)) {
auto macroExpander = getMacroExpander(*target);
for (const auto &package : target->packages()) {
package->setPath(expandWildcards(macroExpander->expand(package->path())));
// Expand variables
const auto path = macroExpander->expand(package->path());
//expand wildcards
// Ignore expanding if no wildcards are found
if (!path.path().contains("*") && !path.path().contains("?")) {
package->setPath(path);
continue;
}
QStringList pathComponents = path.cleanPath().path().split("/");
// Path components example on linux: {"", "home", "username"}
// Path components example on windows: {"C:", "Users", "username"}
// 2 for empty_split_entry(linux)|root(windows) + at least one component
if (pathComponents.size() < 2) {
package->setPath(path);
continue;
}
// drop empty_split_entry(linux)|root(windows)
pathComponents.pop_front();
package->setPath(
expandWildcards(FilePath::fromString(QDir::rootPath()),
{pathComponents.constBegin(), pathComponents.constEnd()})
.first);
}
}
}

View File

@@ -362,15 +362,15 @@ McuPackagePtr createStm32CubeProgrammerPackage(const SettingsHandler::Ptr &setti
FilePath defaultPath;
const QString cubePath = "STMicroelectronics/STM32Cube/STM32CubeProgrammer";
if (HostOsInfo::isWindowsHost())
defaultPath = findInProgramFiles(cubePath) / "bin";
defaultPath = findInProgramFiles(cubePath);
else
defaultPath = FileUtils::homePath() / cubePath / "bin";
defaultPath = FileUtils::homePath() / cubePath;
if (!defaultPath.exists())
FilePath defaultPath = {};
const FilePath detectionPath = FilePath::fromUserInput(
QLatin1String(Utils::HostOsInfo::isWindowsHost() ? "STM32_Programmer_CLI.exe"
: "STM32_Programmer.sh"));
QLatin1String(Utils::HostOsInfo::isWindowsHost() ? "bin/STM32_Programmer_CLI.exe"
: "bin/STM32_Programmer.sh"));
return McuPackagePtr{
new McuPackage(settingsHandler,

View File

@@ -61,6 +61,26 @@ bool McuTarget::isValid() const
});
}
QString McuTarget::desktopCompilerId() const
{
// MinGW shares CMake configuration with GCC
// and it is distinguished from MSVC by CMake compiler ID.
// This provides the compiler ID to set up a different Qul configuration
// for MSVC and MinGW.
if (m_toolChainPackage) {
switch (m_toolChainPackage->toolchainType()) {
case McuToolChainPackage::ToolChainType::MSVC:
return QLatin1String("msvc");
case McuToolChainPackage::ToolChainType::GCC:
case McuToolChainPackage::ToolChainType::MinGW:
return QLatin1String("gnu");
default:
return QLatin1String("unsupported");
}
}
return QLatin1String("invalid");
}
void McuTarget::printPackageProblems() const
{
for (auto package : packages()) {

View File

@@ -53,6 +53,7 @@ public:
OS os() const;
int colorDepth() const;
bool isValid() const;
QString desktopCompilerId() const;
void printPackageProblems() const;
private:

View File

@@ -20,12 +20,12 @@ constexpr auto armgcc_stm32f469i_discovery_baremetal_json = R"(
"type": "path",
"setting": "Stm32CubeProgrammer",
"defaultValue": {
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
},
"detectionPath": {
"windows": "STM32_Programmer_CLI.exe",
"linux": "STM32_Programmer.sh"
"windows": "bin/STM32_Programmer_CLI.exe",
"linux": "bin/STM32_Programmer.sh"
},
"optional": false,
"addToSystemPath": true

View File

@@ -20,12 +20,12 @@ constexpr auto armgcc_stm32f769i_discovery_baremetal_json = R"(
"type": "path",
"setting": "Stm32CubeProgrammer",
"defaultValue": {
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
},
"detectionPath": {
"windows": "STM32_Programmer_CLI.exe",
"linux": "STM32_Programmer.sh"
"windows": "bin/STM32_Programmer_CLI.exe",
"linux": "bin/STM32_Programmer.sh"
},
"optional": false,
"addToSystemPath": true

View File

@@ -20,12 +20,12 @@ constexpr auto armgcc_stm32f769i_discovery_freertos_json = R"(
"type": "path",
"setting": "Stm32CubeProgrammer",
"defaultValue": {
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
},
"detectionPath": {
"windows": "STM32_Programmer_CLI.exe",
"linux": "STM32_Programmer.sh"
"windows": "bin/STM32_Programmer_CLI.exe",
"linux": "bin/STM32_Programmer.sh"
},
"optional": false,
"addToSystemPath": true

View File

@@ -20,12 +20,12 @@ constexpr auto armgcc_stm32h750b_discovery_baremetal_json = R"(
"type": "path",
"setting": "Stm32CubeProgrammer",
"defaultValue": {
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
},
"detectionPath": {
"windows": "STM32_Programmer_CLI.exe",
"linux": "STM32_Programmer.sh"
"windows": "bin/STM32_Programmer_CLI.exe",
"linux": "bin/STM32_Programmer.sh"
},
"optional": false,
"addToSystemPath": true

View File

@@ -20,12 +20,12 @@ constexpr auto iar_stm32f469i_discovery_baremetal_json = R"(
"type": "path",
"setting": "Stm32CubeProgrammer",
"defaultValue": {
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
},
"detectionPath": {
"windows": "STM32_Programmer_CLI.exe",
"linux": "STM32_Programmer.sh"
"windows": "bin/STM32_Programmer_CLI.exe",
"linux": "bin/STM32_Programmer.sh"
},
"optional": false,
"addToSystemPath": true

View File

@@ -20,12 +20,12 @@ constexpr auto iar_stm32f769i_discovery_baremetal_json = R"(
"type": "path",
"setting": "Stm32CubeProgrammer",
"defaultValue": {
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
},
"detectionPath": {
"windows": "STM32_Programmer_CLI.exe",
"linux": "STM32_Programmer.sh"
"windows": "bin/STM32_Programmer_CLI.exe",
"linux": "bin/STM32_Programmer.sh"
},
"optional": false,
"addToSystemPath": true

View File

@@ -20,12 +20,12 @@ constexpr auto iar_stm32f769i_discovery_freertos_json = R"(
"type": "path",
"setting": "Stm32CubeProgrammer",
"defaultValue": {
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
},
"detectionPath": {
"windows": "STM32_Programmer_CLI.exe",
"linux": "STM32_Programmer.sh"
"windows": "bin/STM32_Programmer_CLI.exe",
"linux": "bin/STM32_Programmer.sh"
},
"optional": false,
"addToSystemPath": true

View File

@@ -20,12 +20,12 @@ constexpr auto iar_stm32h750b_discovery_baremetal_json = R"(
"type": "path",
"setting": "Stm32CubeProgrammer",
"defaultValue": {
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
"windows": "%{Env:PROGRAMFILES}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/",
"linux": "%{Env:HOME}/STMicroelectronics/STM32Cube/STM32CubeProgrammer/"
},
"detectionPath": {
"windows": "STM32_Programmer_CLI.exe",
"linux": "STM32_Programmer.sh"
"windows": "bin/STM32_Programmer_CLI.exe",
"linux": "bin/STM32_Programmer.sh"
},
"optional": false,
"addToSystemPath": true

View File

@@ -141,10 +141,10 @@ const QString xpressoIdeDetectionPath{
const char stmCubeProgrammerSetting[]{"Stm32CubeProgrammer"};
const char stmCubeProgrammerLabel[]{"STM32CubeProgrammer"};
const QString stmCubeProgrammerPath{QString{defaultToolPath} + "/bin"};
const QString stmCubeProgrammerPath{defaultToolPath};
const QString stmCubeProgrammerDetectionPath{HostOsInfo::isWindowsHost()
? QString("STM32_Programmer_CLI.exe")
: QString("STM32_Programmer.sh")};
? QString("bin/STM32_Programmer_CLI.exe")
: QString("bin/STM32_Programmer.sh")};
const char renesasProgrammerSetting[]{"RenesasFlashProgrammer"};
const char renesasProgrammerCmakeVar[]{"RENESAS_FLASH_PROGRAMMER_PATH"};
@@ -1703,31 +1703,43 @@ void McuSupportTest::test_addToSystemPathFlag()
void McuSupportTest::test_processWildcards_data()
{
QTest::addColumn<QString>("package_label");
QTest::addColumn<QString>("path");
QTest::addColumn<bool>("isFile");
QTest::addColumn<QString>("expected_path");
QTest::addColumn<QStringList>("paths");
QTest::newRow("\"*\" at the end") << "FAKE_WILDCARD_TEST_1"
<< "folder-123" << false;
QTest::newRow("\"*\" in the middle") << "FAKE_WILDCARD_TEST_2"
<< "file-123.exe" << true;
QTest::newRow("\"*\" at the start") << "FAKE_WILDCARD_TEST_3"
<< "123-file.exe" << true;
QTest::newRow("wildcard_at_the_end") << "FAKE_WILDCARD_TEST_1" << "folder-123" << QStringList {"folder-123/" };
QTest::newRow("wildcard_in_th_middle") << "FAKE_WILDCARD_TEST_2" << "file-123.exe" << QStringList {"file-123.exe"};
QTest::newRow("wildcard_at_the_end") << "FAKE_WILDCARD_TEST_3" << "123-file.exe" << QStringList( "123-file.exe");
QTest::newRow("multi_wildcards")
<< "FAKE_WILDCARD_TEST_MULTI"
<< "2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64"
<< QStringList{
"2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/",
"2019/Alpha/Beta/Gamma/",
"2019/Community/VC/Tools/MSVC/",
"2019/Community/VC/Tools/MSVC/14.29.30133/bin/",
"2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/",
"2019/Enterprise/VC/Tools/MSVC/",
};
}
void McuSupportTest::test_processWildcards()
{
QFETCH(QString, package_label);
QFETCH(QString, path);
QFETCH(bool, isFile);
QFETCH(QString, expected_path);
QFETCH(QStringList, paths);
QVERIFY(createFakePath(testing_output_dir / "wildcards" / path, isFile));
for (const auto &path : paths)
QVERIFY(createFakePath(testing_output_dir / "wildcards" / path, !path.endsWith("/")));
auto [targets, packages] = createTestingKitTargetsAndPackages(wildcards_test_kit);
auto testWildcardsPackage = findOrDefault(packages, [&](const McuPackagePtr &pkg) {
return (pkg->label() == package_label);
});
QVERIFY(testWildcardsPackage != nullptr);
QCOMPARE(testWildcardsPackage->path().toString(), FilePath(testing_output_dir / "wildcards" / path).toString());
QVERIFY(paths.size() > 0);
// FilePaths with "/" at the end and without it evaluate to different paths.
QCOMPARE(testWildcardsPackage->path(),
FilePath(testing_output_dir / "wildcards" / expected_path));
}
void McuSupportTest::test_nonemptyVersionDetector()

View File

@@ -34,6 +34,13 @@ constexpr auto wildcards_test_kit = R"(
"defaultValue": "%{MCU_TESTING_FOLDER}/wildcards/*-file.exe",
"envVar": "",
"type": "path"
},
{
"label": "FAKE_WILDCARD_TEST_MULTI",
"description": "Assert '*' is replaced by possible values",
"defaultValue": "%{MCU_TESTING_FOLDER}/wildcards/2019/*/VC/Tools/MSVC/*/bin/Hostx64/x64",
"envVar": "",
"type": "path"
}
]
},

View File

@@ -61,6 +61,8 @@ void ToolKitAspectWidget::removeTool(const MesonTools::Tool_t &tool)
void ToolKitAspectWidget::setCurrentToolIndex(int index)
{
if (m_toolsComboBox->count() == 0)
return;
const Utils::Id id = Utils::Id::fromSetting(m_toolsComboBox->itemData(index));
if (m_type == ToolType::Meson)
MesonToolKitAspect::setMesonTool(m_kit, id);

View File

@@ -295,7 +295,7 @@ QVariant BuildStep::data(Id id) const
immutable steps are run. The default implementation returns \c false.
*/
void BuildStep::runInThread(const std::function<bool()> &syncImpl)
QFuture<bool> BuildStep::runInThread(const std::function<bool()> &syncImpl)
{
m_runInGuiThread = false;
m_cancelFlag = false;
@@ -304,7 +304,9 @@ void BuildStep::runInThread(const std::function<bool()> &syncImpl)
emit finished(watcher->result());
watcher->deleteLater();
});
watcher->setFuture(Utils::runAsync(syncImpl));
auto future = Utils::runAsync(syncImpl);
watcher->setFuture(future);
return future;
}
std::function<bool ()> BuildStep::cancelChecker() const

View File

@@ -10,6 +10,7 @@
#include <utils/qtcassert.h>
#include <QFuture>
#include <QWidget>
#include <atomic>
@@ -117,7 +118,7 @@ signals:
protected:
virtual QWidget *createConfigWidget();
void runInThread(const std::function<bool()> &syncImpl);
QFuture<bool> runInThread(const std::function<bool()> &syncImpl);
std::function<bool()> cancelChecker() const;
bool isCanceled() const;

View File

@@ -423,7 +423,7 @@ QString JsonWizard::evaluate(const QVariant &v) const
void JsonWizard::openFiles(const JsonWizard::GeneratorFiles &files)
{
QString errorMessage;
bool openedSomething = false;
bool openedSomething = stringValue("DoNotOpenFile") == "true";
for (const JsonWizard::GeneratorFile &f : files) {
const Core::GeneratedFile &file = f.file;
if (!file.filePath().exists()) {

View File

@@ -109,6 +109,10 @@ const Project::NodeMatcher Project::GeneratedFiles = [](const Node *node) {
return isListedFileNode(node) && node->isGenerated();
};
const Project::NodeMatcher Project::HiddenRccFolders = [](const Node *node) {
return node->isFolderNodeType() && node->filePath().fileName() == ".rcc";
};
// --------------------------------------------------------------------
// ProjectDocument:
// --------------------------------------------------------------------

View File

@@ -101,6 +101,7 @@ public:
static const NodeMatcher AllFiles;
static const NodeMatcher SourceFiles;
static const NodeMatcher GeneratedFiles;
static const NodeMatcher HiddenRccFolders;
Utils::FilePaths files(const NodeMatcher &matcher) const;
bool isKnownFile(const Utils::FilePath &filename) const;

View File

@@ -250,7 +250,8 @@ void PythonBuildSystem::triggerParsing()
auto modelManager = QmlJS::ModelManagerInterface::instance();
if (modelManager) {
auto projectInfo = modelManager->defaultProjectInfoForProject(project());
const auto hiddenRccFolders = project()->files(Project::HiddenRccFolders);
auto projectInfo = modelManager->defaultProjectInfoForProject(project(), hiddenRccFolders);
for (const QString &importPath : std::as_const(m_qmlImportPaths)) {
const FilePath filePath = FilePath::fromString(importPath);

View File

@@ -1052,8 +1052,9 @@ void QbsBuildSystem::updateQmlJsCodeModel()
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
if (!modelManager)
return;
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
modelManager->defaultProjectInfoForProject(project());
QmlJS::ModelManagerInterface::ProjectInfo projectInfo
= modelManager->defaultProjectInfoForProject(project(),
project()->files(Project::HiddenRccFolders));
const QJsonObject projectData = session()->projectData();
if (projectData.isEmpty())
@@ -1068,7 +1069,7 @@ void QbsBuildSystem::updateQmlJsCodeModel()
});
project()->setProjectLanguage(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID,
!projectInfo.sourceFiles.isEmpty());
!projectInfo.sourceFiles.isEmpty());
modelManager->updateProjectInfo(projectInfo, project());
}

View File

@@ -410,8 +410,9 @@ void QmakeBuildSystem::updateQmlJSCodeModel()
if (!modelManager)
return;
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
modelManager->defaultProjectInfoForProject(project());
QmlJS::ModelManagerInterface::ProjectInfo projectInfo
= modelManager->defaultProjectInfoForProject(project(),
project()->files(Project::HiddenRccFolders));
const QList<QmakeProFile *> proFiles = rootProFile()->allProFiles();

View File

@@ -11,6 +11,7 @@
#include <theme.h>
#include <utils/hdrimage.h>
#include <qmldesignerplugin.h>
#include <modelnodeoperations.h>
#include <coreplugin/icore.h>
@@ -64,6 +65,13 @@ bool AssetsLibraryModel::loadExpandedState(const QString &assetPath)
return m_expandedStateHash.value(assetPath, true);
}
bool AssetsLibraryModel::isEffectQmlExist(const QString &effectName)
{
Utils::FilePath effectsResDir = ModelNodeOperations::getEffectsDirectory();
Utils::FilePath qmlPath = effectsResDir.resolvePath(effectName + "/" + effectName + ".qml");
return qmlPath.exists();
}
AssetsLibraryModel::DirExpandState AssetsLibraryModel::getAllExpandedState() const
{
const auto keys = m_expandedStateHash.keys();

View File

@@ -52,6 +52,8 @@ public:
static void saveExpandedState(bool expanded, const QString &assetPath);
static bool loadExpandedState(const QString &assetPath);
static bool isEffectQmlExist(const QString &effectName);
enum class DirExpandState {
SomeExpanded,
AllExpanded,

View File

@@ -24,7 +24,6 @@
#include <utils/utilsicons.h>
#include "utils/environment.h"
#include "utils/filepath.h"
#include "utils/qtcprocess.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
@@ -50,9 +49,6 @@
#include <QQmlContext>
#include <QQuickItem>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
namespace QmlDesigner {
static QString propertyEditorResourcesPath()
@@ -242,44 +238,7 @@ QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
void AssetsLibraryWidget::openEffectMaker(const QString &filePath)
{
const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget();
if (!target) {
qWarning() << __FUNCTION__ << "No project open";
return;
}
Utils::FilePath projectPath = target->project()->projectDirectory();
QString effectName = QFileInfo(filePath).baseName();
QString effectResDir = "asset_imports/Effects/" + effectName;
Utils::FilePath effectResPath = projectPath.resolvePath(effectResDir);
if (!effectResPath.exists())
QDir(projectPath.toString()).mkpath(effectResDir);
const QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (baseQtVersion) {
auto effectMakerPath = baseQtVersion->binPath().pathAppended("QQEffectMaker").withExecutableSuffix();
if (!effectMakerPath.exists()) {
qWarning() << __FUNCTION__ << "Cannot find EffectMaker app";
return;
}
Utils::FilePath effectPath = Utils::FilePath::fromString(filePath);
QString effectContents = QString::fromUtf8(effectPath.fileContents().value_or(QByteArray()));
QStringList arguments;
arguments << filePath;
if (effectContents.isEmpty())
arguments << "--create";
arguments << "--exportpath" << effectResPath.toString();
Utils::Environment env = Utils::Environment::systemEnvironment();
if (env.osType() == Utils::OsTypeMac)
env.appendOrSet("QSG_RHI_BACKEND", "metal");
m_qqemProcess.reset(new Utils::QtcProcess);
m_qqemProcess->setEnvironment(env);
m_qqemProcess->setCommand({ effectMakerPath, arguments });
m_qqemProcess->start();
}
ModelNodeOperations::openEffectMaker(filePath);
}
void AssetsLibraryWidget::setModel(Model *model)

View File

@@ -22,7 +22,6 @@ QT_END_NAMESPACE
namespace Utils {
class FileSystemWatcher;
class QtcProcess;
}
namespace QmlDesigner {
@@ -96,8 +95,6 @@ private:
bool m_updateRetry = false;
QString m_filterText;
QPoint m_dragStartPoint;
std::unique_ptr<Utils::QtcProcess> m_qqemProcess;
};
} // namespace QmlDesigner

View File

@@ -47,11 +47,15 @@
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h>
#include "projectexplorer/session.h"
#include "projectexplorer/target.h"
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include "utils/qtcprocess.h"
#include <utils/smallstring.h>
#include <QComboBox>
@@ -1621,6 +1625,51 @@ void updateImported3DAsset(const SelectionContext &selectionContext)
}
}
void openEffectMaker(const QString &filePath)
{
const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget();
if (!target) {
qWarning() << __FUNCTION__ << "No project open";
return;
}
Utils::FilePath projectPath = target->project()->projectDirectory();
QString effectName = QFileInfo(filePath).baseName();
QString effectResDir = "asset_imports/Effects/" + effectName;
Utils::FilePath effectResPath = projectPath.resolvePath(effectResDir);
if (!effectResPath.exists())
QDir(projectPath.toString()).mkpath(effectResDir);
const QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (baseQtVersion) {
auto effectMakerPath = baseQtVersion->binPath().pathAppended("QQEffectMaker").withExecutableSuffix();
if (!effectMakerPath.exists()) {
qWarning() << __FUNCTION__ << "Cannot find EffectMaker app";
return;
}
Utils::FilePath effectPath = Utils::FilePath::fromString(filePath);
QStringList arguments;
arguments << filePath;
if (effectPath.fileContents())
arguments << "--create";
arguments << "--exportpath" << effectResPath.toString();
Utils::Environment env = Utils::Environment::systemEnvironment();
if (env.osType() == Utils::OsTypeMac)
env.appendOrSet("QSG_RHI_BACKEND", "metal");
Utils::QtcProcess *qqemProcess = new Utils::QtcProcess();
qqemProcess->setEnvironment(env);
qqemProcess->setCommand({ effectMakerPath, arguments });
qqemProcess->start();
QObject::connect(qqemProcess, &Utils::QtcProcess::done, [qqemProcess]() {
qqemProcess->deleteLater();
});
}
}
Utils::FilePath getEffectsDirectory()
{
QString defaultDir = "asset_imports/Effects";

View File

@@ -79,10 +79,11 @@ void openSignalDialog(const SelectionContext &selectionContext);
void updateImported3DAsset(const SelectionContext &selectionContext);
QMLDESIGNERCORE_EXPORT Utils::FilePath getEffectsDirectory();
void openEffectMaker(const QString &filePath);
// ModelNodePreviewImageOperations
QVariant previewImageDataForGenericNode(const ModelNode &modelNode);
QVariant previewImageDataForImageNode(const ModelNode &modelNode);
} // namespace ModelNodeOperationso
} // namespace ModelNodeOperations
} //QmlDesigner

View File

@@ -6,7 +6,9 @@
#include "formeditorscene.h"
#include "formeditorview.h"
#include "assetslibrarywidget.h"
#include "assetslibrarymodel.h"
#include <metainfo.h>
#include <modelnodeoperations.h>
#include <nodehints.h>
#include <rewritingexception.h>
#include "qmldesignerconstants.h"
@@ -19,6 +21,7 @@
#include <QMimeData>
#include <QTimer>
#include <QWidget>
#include <QMessageBox>
static Q_LOGGING_CATEGORY(dragToolInfo, "qtc.qmldesigner.formeditor", QtWarningMsg);
@@ -242,9 +245,31 @@ void DragTool::dropEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneD
if (targetContainerFormEditorItem) {
QmlItemNode parentQmlItemNode = targetContainerFormEditorItem->qmlItemNode();
QString effectName = QFileInfo(effectPath).baseName();
QmlItemNode effectNode = QmlItemNode::createQmlItemNodeForEffect(view(), parentQmlItemNode, effectName);
view()->setSelectedModelNodes({effectNode});
if (!AssetsLibraryModel::isEffectQmlExist(effectName)) {
QMessageBox msgBox;
msgBox.setText("Effect " + effectName + " is empty");
msgBox.setInformativeText("Do you want to edit " + effectName + "?");
msgBox.setStandardButtons(QMessageBox::No |QMessageBox::Yes);
msgBox.setDefaultButton(QMessageBox::Yes);
msgBox.setIcon(QMessageBox::Question);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Yes:
ModelNodeOperations::openEffectMaker(effectPath);
break;
default:
break;
}
event->ignore();
return;
}
QmlItemNode effectNode = QmlItemNode::
createQmlItemNodeForEffect(view(), parentQmlItemNode, effectName);
view()->setSelectedModelNodes({parentQmlItemNode});
view()->resetPuppet();
commitTransaction();

View File

@@ -13,6 +13,8 @@
#include <model.h>
#include <abstractview.h>
#include <coreplugin/icore.h>
#include <QUrl>
#include <QPlainTextEdit>
#include <QFileInfo>
@@ -151,12 +153,22 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view,
return newQmlItemNode;
}
static bool useLayerEffect()
{
QSettings *settings = Core::ICore::settings();
const QString layerEffectEntry = "QML/Designer/UseLayerEffect";
return settings->value(layerEffectEntry, true).toBool();
}
QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view,
const QmlItemNode &parentNode,
const QString &effectName)
{
QmlItemNode newQmlItemNode;
const bool layerEffect = useLayerEffect();
QmlDesigner::Import import = Import::createLibraryImport("Effects." + effectName, "1.0");
try {
if (!view->model()->hasImport(import, true, true))
@@ -167,11 +179,17 @@ QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view,
TypeName type(effectName.toUtf8());
newQmlItemNode = QmlItemNode(view->createModelNode(type, 1, 0));
NodeAbstractProperty parentProperty = parentNode.defaultNodeAbstractProperty();
NodeAbstractProperty parentProperty = layerEffect
? parentNode.nodeAbstractProperty("layer.effect")
: parentNode.defaultNodeAbstractProperty();
parentProperty.reparentHere(newQmlItemNode);
newQmlItemNode.modelNode().bindingProperty("source").setExpression("parent");
newQmlItemNode.modelNode().bindingProperty("anchors.fill").setExpression("parent");
if (!layerEffect) {
newQmlItemNode.modelNode().bindingProperty("source").setExpression("parent");
newQmlItemNode.modelNode().bindingProperty("anchors.fill").setExpression("parent");
} else {
parentNode.modelNode().variantProperty("layer.enabled").setValue(true);
}
QTC_ASSERT(newQmlItemNode.isValid(), return QmlItemNode());

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "qmldesignerplugin.h"
#include "coreplugin/iwizardfactory.h"
#include "designmodecontext.h"
#include "designmodewidget.h"
#include "dynamiclicensecheck.h"
@@ -41,8 +42,10 @@
#include <coreplugin/coreconstants.h>
#include <coreplugin/designmode.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/featureprovider.h>
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
#include <coreplugin/iwizardfactory.h>
#include <coreplugin/messagebox.h>
#include <coreplugin/modemanager.h>
#include <extensionsystem/pluginmanager.h>
@@ -54,19 +57,19 @@
#include <sqlitelibraryinitializer.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/algorithm.h>
#include <QAction>
#include <QTimer>
#include <QApplication>
#include <QCoreApplication>
#include <qplugin.h>
#include <QDebug>
#include <QProcessEnvironment>
#include <QScreen>
#include <QTimer>
#include <QWindow>
#include <QApplication>
#include <qplugin.h>
#include "nanotrace/nanotrace.h"
#include <modelnodecontextmenu_helper.h>
@@ -79,6 +82,17 @@ namespace QmlDesigner {
namespace Internal {
class EnterpriseFeatureProvider : public Core::IFeatureProvider
{
public:
QSet<Utils::Id> availableFeatures(Utils::Id id) const override
{
return {"QmlDesigner.Wizards.Enterprise"};
}
QSet<Utils::Id> availablePlatforms() const override { return {}; }
QString displayNameForPlatform(Utils::Id id) const override { return {}; }
};
QString normalizeIdentifier(const QString &string)
{
if (string.isEmpty())
@@ -232,6 +246,8 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
//TODO Move registering those types out of the property editor, since they are used also in the states editor
Quick2PropertyEditorView::registerQmlTypes();
if (QmlDesigner::checkLicense() == QmlDesigner::FoundLicense::enterprise)
Core::IWizardFactory::registerFeatureProvider(new EnterpriseFeatureProvider);
Exception::setWarnAboutException(!QmlDesignerPlugin::instance()
->settings()
.value(DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT)

View File

@@ -20,22 +20,23 @@
#include <qmljstools/qmljstoolssettings.h>
#include <qmljstools/qmljscodestylepreferences.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <projectexplorer/taskhub.h>
#include <coreplugin/icore.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/taskhub.h>
#include <texteditor/formattexteditor.h>
#include <texteditor/snippets/snippetprovider.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorconstants.h>
#include <utils/fsengine/fileiconprovider.h>
#include <utils/qtcassert.h>
#include <utils/json.h>
#include <utils/qtcassert.h>
#include <QTextDocument>
#include <QMenu>
@@ -260,24 +261,14 @@ void QmlJSEditorPluginPrivate::reformatFile()
tabSettings.m_tabSize,
QmlJSTools::QmlJSToolsSettings::globalCodeStyle()->currentCodeStyleSettings().lineLength);
// QTextDocument::setPlainText cannot be used, as it would reset undo/redo history
const auto setNewText = [this, &newText]() {
auto ed = qobject_cast<TextEditor::BaseTextEditor *>(EditorManager::currentEditor());
if (ed) {
TextEditor::updateEditorText(ed->editorWidget(), newText);
} else {
QTextCursor tc(m_currentDocument->document());
tc.movePosition(QTextCursor::Start);
tc.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
tc.insertText(newText);
};
IEditor *ed = EditorManager::currentEditor();
if (ed) {
QByteArray state = ed->saveState();
int line = ed->currentLine();
int column = ed->currentColumn();
setNewText();
ed->gotoLine(line, column - 1);
ed->restoreState(state);
} else {
setNewText();
}
}
}

View File

@@ -81,8 +81,36 @@ static void setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo &proje
}
}
static void findAllQrcFiles(const FilePath &filePath, FilePaths &out)
{
filePath.iterateDirectory(
[&out](const FilePath &path) {
out.append(path.canonicalPath());
return true;
},
{{"*.qrc"}, QDir::Files});
}
static FilePaths findGeneratedQrcFiles(const ModelManagerInterface::ProjectInfo &pInfo,
const FilePaths &hiddenRccFolders)
{
FilePaths result;
// Search in Application Directories for directories named ".rcc"
// and add all .qrc files in there to the resource file list.
for (const Utils::FilePath &path : pInfo.applicationDirectories) {
Utils::FilePath generatedQrcDir = path.pathAppended(".rcc");
findAllQrcFiles(generatedQrcDir, result);
}
for (const Utils::FilePath &hiddenRccFolder : hiddenRccFolders) {
findAllQrcFiles(hiddenRccFolder, result);
}
return result;
}
ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
Project *project) const
Project *project, const FilePaths &hiddenRccFolders) const
{
ModelManagerInterface::ProjectInfo projectInfo;
projectInfo.project = project;
@@ -187,6 +215,7 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
}
setupProjectInfoQmlBundles(projectInfo);
projectInfo.generatedQrcFiles = findGeneratedQrcFiles(projectInfo, hiddenRccFolders);
return projectInfo;
}
@@ -298,7 +327,7 @@ void ModelManager::updateDefaultProjectInfo()
Project *currentProject = SessionManager::startupProject();
setDefaultProject(containsProject(currentProject)
? projectInfo(currentProject)
: defaultProjectInfoForProject(currentProject),
: defaultProjectInfoForProject(currentProject, {}),
currentProject);
}

View File

@@ -32,7 +32,8 @@ protected:
WorkingCopy workingCopyInternal() const override;
void addTaskInternal(const QFuture<void> &result, const QString &msg,
const char *taskId) const override;
ProjectInfo defaultProjectInfoForProject(ProjectExplorer::Project *project) const override;
ProjectInfo defaultProjectInfoForProject(
ProjectExplorer::Project *project, const Utils::FilePaths &hiddenRccFolders) const override;
private:
void updateDefaultProjectInfo();
void loadDefaultQmlTypeDescriptions();

View File

@@ -311,8 +311,9 @@ void QmlBuildSystem::refresh(RefreshOptions options)
if (!modelManager)
return;
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
modelManager->defaultProjectInfoForProject(project());
QmlJS::ModelManagerInterface::ProjectInfo projectInfo
= modelManager->defaultProjectInfoForProject(project(),
project()->files(Project::HiddenRccFolders));
const QStringList searchPaths = makeAbsolute(canonicalProjectDir(), customImportPaths());
for (const QString &searchPath : searchPaths)
projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(searchPath),

View File

@@ -13,6 +13,8 @@
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <utils/futuresynchronizer.h>
#include <QDateTime>
#include <QDir>
#include <QFile>
@@ -80,6 +82,8 @@ private:
BoolAspect *m_ignoreMissingFilesAspect = nullptr;
bool m_packagingNeeded = false;
QList<DeployableFile> m_files;
FutureSynchronizer m_synchronizer;
};
TarPackageCreationStep::TarPackageCreationStep(BuildStepList *bsl, Id id)
@@ -126,7 +130,7 @@ bool TarPackageCreationStep::init()
void TarPackageCreationStep::doRun()
{
runInThread([this] { return runImpl(); });
m_synchronizer.addFuture(runInThread([this] { return runImpl(); }));
}
bool TarPackageCreationStep::fromMap(const QVariantMap &map)

View File

@@ -19,7 +19,7 @@ public:
virtual ~IAssistProcessor();
virtual IAssistProposal *immediateProposal(const AssistInterface *) { return nullptr; }
virtual IAssistProposal *perform(const AssistInterface *interface) = 0;
virtual IAssistProposal *perform(const AssistInterface *interface) = 0; // takes ownership
void setAsyncProposalAvailable(IAssistProposal *proposal);

View File

@@ -132,7 +132,7 @@ static FormatTask format(FormatTask task)
* actually changed parts are updated while preserving the cursor position, the folded
* blocks, and the scroll bar position.
*/
static void updateEditorText(QPlainTextEdit *editor, const QString &text)
void updateEditorText(QPlainTextEdit *editor, const QString &text)
{
const QString editorText = editor->toPlainText();
if (editorText == text)

View File

@@ -44,5 +44,6 @@ TEXTEDITOR_EXPORT void formatEditor(TextEditorWidget *editor, const TextEditor::
int startPos = -1, int endPos = 0);
TEXTEDITOR_EXPORT void formatEditorAsync(TextEditorWidget *editor, const TextEditor::Command &command,
int startPos = -1, int endPos = 0);
TEXTEDITOR_EXPORT void updateEditorText(QPlainTextEdit *editor, const QString &text);
} // namespace TextEditor

View File

@@ -732,7 +732,7 @@ Core::IDocument::OpenResult TextDocument::open(QString *errorString,
emit aboutToOpen(filePath, realFilePath);
OpenResult success = openImpl(errorString, filePath, realFilePath, /*reload =*/ false);
if (success == OpenResult::Success) {
setMimeType(Utils::mimeTypeForFile(filePath).name());
setMimeType(Utils::mimeTypeForFile(filePath, MimeMatchMode::MatchDefaultAndRemote).name());
emit openFinishedSuccessfully();
}
return success;

View File

@@ -3343,7 +3343,9 @@ void TextEditorWidgetPrivate::updateFileLineEndingVisible()
void TextEditorWidgetPrivate::reconfigure()
{
m_document->setMimeType(Utils::mimeTypeForFile(m_document->filePath()).name());
m_document->setMimeType(
Utils::mimeTypeForFile(m_document->filePath(),
MimeMatchMode::MatchDefaultAndRemote).name());
q->configureGenericHighlighter();
}