Merge remote-tracking branch 'origin/6.0'

Conflicts:
	cmake/QtCreatorIDEBranding.cmake
	qbs/modules/qtc/qtc.qbs
	qtcreator_ide_branding.pri

Change-Id: I32991a77e52831dd2e24cf4a51ec252998c2d743
This commit is contained in:
Eike Ziller
2021-12-09 12:02:47 +01:00
328 changed files with 2093 additions and 709 deletions

View File

@@ -256,8 +256,22 @@
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSAppleEventsUsageDescription</key>
<string>This application wants to run AppleScript.</string>
<key>NSDesktopFolderUsageDescription</key>
<string>This application wants to access the Desktop folder.</string>
<key>NSDocumentsFolderUsageDescription</key>
<string>This application wants to access the Documents folder.</string>
<key>NSDownloadsFolderUsageDescription</key>
<string>This application wants to access the Downloads folder.</string>
<key>NSNetworkVolumesUsageDescription</key>
<string>This application wants to access network volumes.</string>
<key>NSRemovableVolumesUsageDescription</key>
<string>This application wants to access removable volumes.</string>
<key>NSFileProviderDomainUsageDescription</key>
<string>This application wants to access files from a provider.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>A user application wants to access bluetooth.</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>A user application wants to access bluetooth.</string>
<key>NSCalendarsUsageDescription</key>
<string>A user application wants to access calendars.</string>
<key>NSCameraUsageDescription</key>

View File

@@ -31,7 +31,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/src/CMakeLists.txt)
set(QLITEHTML_DEVEL_EXCLUDE_FROM_ALL ON)
set(QLITEHTML_HEADER_PATH "${IDE_HEADER_INSTALL_PATH}/src/lib/qlitehtml")
set(QT_VERSION_MAJOR ${Qt5_VERSION_MAJOR})
set(BUILD_TESTING OFF) # otherwise litehtml downloads googletest
option(BUILD_TESTING "Build litehtml tests" OFF) # otherwise litehtml downloads googletest
add_subdirectory(qlitehtml/src)
endif()
if(TARGET qlitehtml)

View File

@@ -1236,7 +1236,11 @@ bool Check::visit(FunctionExpression *ast)
}
}
addMessage(ErrFunctionsNotSupportedInQmlUi, locationFromRange(locfunc, loclparen));
const bool isDirectInConnectionsScope =
(!m_typeStack.isEmpty() && m_typeStack.last() == "Connections");
if (!isDirectInConnectionsScope)
addMessage(ErrFunctionsNotSupportedInQmlUi, locationFromRange(locfunc, loclparen));
DeclarationsCheck bodyCheck;
addMessages(bodyCheck(ast));

View File

@@ -1,4 +1,5 @@
add_qtc_library(Sqlite
PROPERTIES AUTOMOC OFF AUTOUIC OFF
PUBLIC_DEFINES
BUILD_SQLITE_LIBRARY
SQLITE_CORE

View File

@@ -27,6 +27,8 @@
#include <utils/smallstringview.h>
#include <type_traits>
namespace Sqlite {
constexpr int compare(Utils::SmallStringView first, Utils::SmallStringView second) noexcept
@@ -41,6 +43,8 @@ constexpr int compare(Utils::SmallStringView first, Utils::SmallStringView secon
return difference;
}
enum class UpdateChange { No, Update };
template<typename SqliteRange,
typename Range,
typename CompareKey,
@@ -58,6 +62,7 @@ void insertUpdateDelete(SqliteRange &&sqliteRange,
auto endSqliteIterator = sqliteRange.end();
auto currentValueIterator = values.begin();
auto endValueIterator = values.end();
std::optional<std::decay_t<decltype(*currentValueIterator)>> lastValue;
while (true) {
bool hasMoreValues = currentValueIterator != endValueIterator;
@@ -67,21 +72,42 @@ void insertUpdateDelete(SqliteRange &&sqliteRange,
auto &&value = *currentValueIterator;
auto compare = compareKey(sqliteValue, value);
if (compare == 0) {
updateCallback(sqliteValue, value);
++currentValueIterator;
UpdateChange updateChange = updateCallback(sqliteValue, value);
switch (updateChange) {
case UpdateChange::Update:
lastValue = value;
break;
case UpdateChange::No:
lastValue.reset();
break;
}
++currentSqliteIterator;
++currentValueIterator;
} else if (compare > 0) {
insertCallback(value);
++currentValueIterator;
} else if (compare < 0) {
deleteCallback(sqliteValue);
if (lastValue) {
if (compareKey(sqliteValue, *lastValue) != 0)
deleteCallback(sqliteValue);
lastValue.reset();
} else {
deleteCallback(sqliteValue);
}
++currentSqliteIterator;
}
} else if (hasMoreValues) {
insertCallback(*currentValueIterator);
++currentValueIterator;
} else if (hasMoreSqliteValues) {
deleteCallback(*currentSqliteIterator);
auto &&sqliteValue = *currentSqliteIterator;
if (lastValue) {
if (compareKey(sqliteValue, *lastValue) != 0)
deleteCallback(sqliteValue);
lastValue.reset();
} else {
deleteCallback(sqliteValue);
}
++currentSqliteIterator;
} else {
break;

View File

@@ -639,11 +639,12 @@ public:
std::function<QString(const QString &)> m_displayFilter;
std::unique_ptr<BoolAspect> m_checker;
Qt::TextElideMode m_elideMode = Qt::ElideNone;
QString m_placeHolderText;
QString m_historyCompleterKey;
PathChooser::Kind m_expectedKind = PathChooser::File;
EnvironmentChange m_environmentChange;
QPointer<QLabel> m_labelDisplay;
QPointer<ElidingLabel> m_labelDisplay;
QPointer<FancyLineEdit> m_lineEditDisplay;
QPointer<PathChooser> m_pathChooserDisplay;
QPointer<QTextEdit> m_textEditDisplay;
@@ -935,6 +936,16 @@ void StringAspect::setPlaceHolderText(const QString &placeHolderText)
d->m_textEditDisplay->setPlaceholderText(placeHolderText);
}
/*!
Sets \a elideMode as label elide mode.
*/
void StringAspect::setElideMode(Qt::TextElideMode elideMode)
{
d->m_elideMode = elideMode;
if (d->m_labelDisplay)
d->m_labelDisplay->setElideMode(elideMode);
}
/*!
Sets \a historyCompleterKey as key for the history completer settings for
line edits and path chooser displays.
@@ -1144,7 +1155,8 @@ void StringAspect::addToLayout(LayoutBuilder &builder)
}
break;
case LabelDisplay:
d->m_labelDisplay = createSubWidget<QLabel>();
d->m_labelDisplay = createSubWidget<ElidingLabel>();
d->m_labelDisplay->setElideMode(d->m_elideMode);
d->m_labelDisplay->setTextInteractionFlags(Qt::TextSelectableByMouse);
d->m_labelDisplay->setText(displayedString);
d->m_labelDisplay->setToolTip(d->m_showToolTipOnLabel ? displayedString : toolTip());

View File

@@ -308,6 +308,7 @@ public:
void setValidationFunction(const Utils::FancyLineEdit::ValidationFunction &validator);
void setOpenTerminalHandler(const std::function<void()> &openTerminal);
void setAutoApplyOnEditingFinished(bool applyOnEditingFinished);
void setElideMode(Qt::TextElideMode elideMode);
void validateInput();

View File

@@ -111,7 +111,7 @@ static QLayout *createLayoutFromType(LayoutBuilder::LayoutType layoutType)
switch (layoutType) {
case LayoutBuilder::FormLayout: {
auto formLayout = new QFormLayout;
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
return formLayout;
}
case LayoutBuilder::GridLayout: {

View File

@@ -325,6 +325,13 @@ int main(int argc, char *argv[])
kill(chldPid, SIGKILL);
}
break;
case 'i':
if (chldPid > 0) {
int res = kill(chldPid, SIGINT);
if (res)
perror("Stub could not interrupt inferior");
}
break;
case 'c': {
int res = write(blockingPipe[1], &c, 1);
if (res < 0)

View File

@@ -589,7 +589,7 @@ FilePath AndroidConfig::openJDKBinPath() const
FilePath AndroidConfig::keytoolPath() const
{
return openJDKBinPath().pathAppended(keytoolName);
return openJDKBinPath().pathAppended(keytoolName).withExecutableSuffix();
}
QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(QString *error) const

View File

@@ -84,7 +84,8 @@ AndroidPackageInstallationStep::AndroidPackageInstallationStep(BuildStepList *bs
setWidgetExpandedByDefault(false);
setImmutable(true);
setSummaryUpdater([this] {
return tr("<b>Make install:</b> Copy App Files to %1").arg(nativeAndroidBuildPath());
return tr("<b>Make install:</b> Copy App Files to %1")
.arg(QDir::toNativeSeparators(nativeAndroidBuildPath()));
});
setUseEnglishOutput();
}

View File

@@ -59,18 +59,18 @@ QStringList filterInterfering(const QStringList &provided, QStringList *omitted)
"--gtest_print_time="
};
QSet<QString> allowed = Utils::filtered(Utils::toSet(provided), [] (const QString &arg) {
QStringList allowed = Utils::filtered(provided, [] (const QString &arg) {
return Utils::allOf(knownInterferingOptions, [&arg] (const QString &interfering) {
return !arg.startsWith(interfering);
});
});
if (omitted) {
if (omitted && allowed.size() < provided.size()) {
QSet<QString> providedSet = Utils::toSet(provided);
providedSet.subtract(allowed);
providedSet.subtract(Utils::toSet(allowed));
omitted->append(Utils::toList(providedSet));
}
return Utils::toList(allowed);
return allowed;
}
QStringList GTestConfiguration::argumentsForTestRunner(QStringList *omitted) const

View File

@@ -395,10 +395,14 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath,
bool ClangdTextMark::addToolTipContent(QLayout *target) const
{
const auto canApplyFixIt = [c = m_client, diag = m_lspDiagnostic, fp = fileName()] {
return c && c->reachable() && c->hasDiagnostic(DocumentUri::fromFilePath(fp), diag);
return QTC_GUARD(c) && c->reachable()
&& c->hasDiagnostic(DocumentUri::fromFilePath(fp), diag);
};
const QString clientName = QTC_GUARD(m_client) ? m_client->name() : "clangd [unknown]";
target->addWidget(ClangDiagnosticWidget::createWidget({m_diagnostic},
ClangDiagnosticWidget::ToolTip, canApplyFixIt, m_client ? m_client->name() : "clangd"));
ClangDiagnosticWidget::ToolTip,
canApplyFixIt,
clientName));
return true;
}

View File

@@ -581,7 +581,15 @@ QStringList createClangOptions(const ProjectPart &projectPart, const QString &fi
LibClangOptionsBuilder optionsBuilder(projectPart, fileOptions.useBuildSystemWarnings());
const QStringList projectPartOptions = optionsBuilder.build(CppEditor::ProjectFile::Unsupported,
UsePrecompiledHeaders::No);
return projectPartOptions + fileOptions.options();
// FIXME: Sanitize FileOptionsBuilder instead.
QStringList fileArgs = fileOptions.options();
if (projectPartOptions.contains("-TP"))
fileArgs.removeAll("/TP");
if (projectPartOptions.contains("-TC"))
fileArgs.removeAll("/TC");
return projectPartOptions + fileArgs;
}
ClangDiagnosticConfig warningsConfigForProject(Project *project)

View File

@@ -35,6 +35,8 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmacro.h>
#include <qnx/qnxconstants.h>
#include <utils/algorithm.h>
#include <utils/cpplanguage_details.h>
#include <utils/fileutils.h>
@@ -152,6 +154,7 @@ QStringList CompilerOptionsBuilder::build(ProjectFile::Kind fileKind,
undefineClangVersionMacrosForMsvc();
undefineCppLanguageFeatureMacrosForMsvc2015();
addDefineFunctionMacrosMsvc();
addDefineFunctionMacrosQnx();
addHeaderPathOptions();
@@ -404,8 +407,8 @@ void CompilerOptionsBuilder::addProjectMacros()
static const int useMacros = qEnvironmentVariableIntValue("QTC_CLANG_USE_TOOLCHAIN_MACROS");
if (m_projectPart.toolchainType == ProjectExplorer::Constants::CUSTOM_TOOLCHAIN_TYPEID
|| m_projectPart.toolchainType.name().contains("BareMetal")
|| useMacros) {
|| m_projectPart.toolchainType == Qnx::Constants::QNX_TOOLCHAIN_ID
|| m_projectPart.toolchainType.name().contains("BareMetal") || useMacros) {
addMacros(m_projectPart.toolChainMacros);
}
@@ -771,6 +774,17 @@ void CompilerOptionsBuilder::undefineClangVersionMacrosForMsvc()
}
}
void CompilerOptionsBuilder::addDefineFunctionMacrosQnx()
{
// QNX 7.0+ uses GCC with LIBCPP from Clang, and in that context GCC is giving
// the builtin operator new and delete.
//
// In our case we have only Clang and need to instruct LIBCPP that it doesn't
// have these operators. This makes the code model happy and doesn't produce errors.
if (m_projectPart.toolchainType == Qnx::Constants::QNX_TOOLCHAIN_ID)
addMacros({{"_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE"}});
}
void CompilerOptionsBuilder::reset()
{
m_options.clear();

View File

@@ -84,6 +84,8 @@ public:
void addProjectConfigFileInclude();
void undefineClangVersionMacrosForMsvc();
void addDefineFunctionMacrosQnx();
// Add custom options
void add(const QString &arg, bool gccOnlyOption = false);
void prepend(const QString &arg);

View File

@@ -74,8 +74,7 @@ CppUseSelectionsUpdater::RunnerInfo CppUseSelectionsUpdater::update(CallType cal
auto *cppEditorDocument = qobject_cast<CppEditorDocument *>(cppEditorWidget->textDocument());
QTC_ASSERT(cppEditorDocument, return RunnerInfo::FailedToStart);
if (!CppModelManager::instance()->supportsLocalUses(cppEditorDocument))
return RunnerInfo::AlreadyUpToDate;
m_updateSelections = CppModelManager::instance()->supportsLocalUses(cppEditorDocument);
CursorInfoParams params;
params.semanticInfo = cppEditorWidget->semanticInfo();
@@ -130,16 +129,16 @@ bool CppUseSelectionsUpdater::isSameIdentifierAsBefore(const QTextCursor &cursor
void CppUseSelectionsUpdater::processResults(const CursorInfo &result)
{
ExtraSelections localVariableSelections;
if (!result.useRanges.isEmpty() || !currentUseSelections().isEmpty()) {
ExtraSelections selections = updateUseSelections(result.useRanges);
if (result.areUseRangesForLocalVariable)
localVariableSelections = selections;
if (m_updateSelections) {
ExtraSelections localVariableSelections;
if (!result.useRanges.isEmpty() || !currentUseSelections().isEmpty()) {
ExtraSelections selections = updateUseSelections(result.useRanges);
if (result.areUseRangesForLocalVariable)
localVariableSelections = selections;
}
updateUnusedSelections(result.unusedVariablesRanges);
emit selectionsForVariableUnderCursorUpdated(localVariableSelections);
}
updateUnusedSelections(result.unusedVariablesRanges);
emit selectionsForVariableUnderCursorUpdated(localVariableSelections);
emit finished(result.localUses, true);
}

View File

@@ -79,6 +79,7 @@ private:
QScopedPointer<QFutureWatcher<CursorInfo>> m_runnerWatcher;
int m_runnerRevision = -1;
int m_runnerWordStartPosition = -1;
bool m_updateSelections = true;
};
} // namespace Internal

View File

@@ -254,6 +254,7 @@ QList<ReloadInput> DiffOpenFilesController::reloadInputList() const
const QList<IDocument *> openedDocuments = DocumentModel::openedDocuments();
for (IDocument *doc : openedDocuments) {
QTC_ASSERT(doc, continue);
auto textDocument = qobject_cast<TextEditor::TextDocument *>(doc);
if (textDocument && textDocument->isModified()) {
@@ -518,6 +519,7 @@ void DiffEditorPluginPrivate::updateDiffCurrentFileAction()
void DiffEditorPluginPrivate::updateDiffOpenFilesAction()
{
const bool enabled = Utils::anyOf(DocumentModel::openedDocuments(), [](IDocument *doc) {
QTC_ASSERT(doc, return false);
return doc->isModified() && qobject_cast<TextEditor::TextDocument *>(doc);
});
m_diffOpenFilesAction->setEnabled(enabled);

View File

@@ -692,7 +692,7 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
const QString method(DidChangeTextDocumentNotification::methodName);
TextDocumentSyncKind syncKind = m_serverCapabilities.textDocumentSyncKindHelper();
if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) {
syncKind = registered.value() ? TextDocumentSyncKind::None : TextDocumentSyncKind::Full;
syncKind = registered.value() ? TextDocumentSyncKind::Full : TextDocumentSyncKind::None;
if (syncKind != TextDocumentSyncKind::None) {
const TextDocumentChangeRegistrationOptions option(
m_dynamicCapabilities.option(method).toObject());

View File

@@ -392,8 +392,10 @@ bool LanguageClientCompletionAssistProcessor::running()
void LanguageClientCompletionAssistProcessor::cancel()
{
if (m_currentRequest.has_value()) {
m_client->cancelRequest(m_currentRequest.value());
m_client->removeAssistProcessor(this);
if (m_client) {
m_client->cancelRequest(m_currentRequest.value());
m_client->removeAssistProcessor(this);
}
m_currentRequest.reset();
} else if (m_postponedUpdateConnection) {
QObject::disconnect(m_postponedUpdateConnection);

View File

@@ -75,6 +75,10 @@ void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument)
const TextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath));
auto responseCallback = [this, filePath, documentVersion = m_client->documentVersion(filePath)](
const SemanticTokensFullRequest::Response &response) {
if (const auto error = response.error()) {
qCDebug(LOGLSPHIGHLIGHT)
<< "received error" << error->code() << error->message() << "for" << filePath;
}
handleSemanticTokens(filePath, response.result().value_or(nullptr), documentVersion);
};
/*if (supportedRequests.testFlag(SemanticRequestType::Range)) {
@@ -120,6 +124,10 @@ void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
request.setResponseCallback(
[this, filePath, documentVersion](
const SemanticTokensFullDeltaRequest::Response &response) {
if (const auto error = response.error()) {
qCDebug(LOGLSPHIGHLIGHT) << "received error" << error->code()
<< error->message() << "for" << filePath;
}
handleSemanticTokensDelta(filePath,
response.result().value_or(nullptr),
documentVersion);
@@ -285,6 +293,9 @@ void SemanticTokenSupport::handleSemanticTokens(const Utils::FilePath &filePath,
m_tokens[filePath] = {*tokens, documentVersion};
highlight(filePath);
} else {
qCDebug(LOGLSPHIGHLIGHT)
<< "no data in reply to full semantic tokens request, clearing tokens"
<< m_client->name() << filePath;
m_tokens.remove(filePath);
}
}
@@ -353,8 +364,10 @@ void SemanticTokenSupport::handleSemanticTokensDelta(
tokens.setData(newData);
tokens.setResultId(tokensDelta->resultId());
} else {
qCDebug(LOGLSPHIGHLIGHT)
<< "no data in reply to semantic tokens delta request, clearing tokens"
<< m_client->name() << filePath;
m_tokens.remove(filePath);
qCDebug(LOGLSPHIGHLIGHT) << "Data cleared";
return;
}
highlight(filePath);

View File

@@ -56,7 +56,7 @@ static const QHash<QString, QString> &envVarToCMakeVarMapping()
{"RenesasFlashProgrammer_PATH", "RENESAS_FLASH_PROGRAMMER_PATH"},
{"MCUXpressoIDE_PATH", "MCUXPRESSO_IDE_PATH"},
{"JLINK_PATH", "JLINK_PATH"},
{"CYPRESS_AUTO_FLASH_UTILITY_DIR", "CYPRESS_AUTO_FLASH_UTILITY_DIR"},
{"CYPRESS_AUTO_FLASH_UTILITY_DIR", "INFINEON_AUTO_FLASH_UTILITY_DIR"},
{"EK_RA6M3G_E2_PROJECT_PATH", "EK_RA6M3G_E2_PROJECT_PATH"},
};
return mapping;

View File

@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 3.15)
project(%{ProjectName} VERSION 0.0.1 LANGUAGES C CXX ASM)
project(%{ProjectName} VERSION 0.0.1 LANGUAGES C CXX ASM ASM_MASM)
find_package(Qul)

View File

@@ -2110,7 +2110,7 @@ Utils::optional<QString> MsvcToolChain::generateEnvironmentSettings(const Utils:
Utils::Environment runEnv = env;
runEnv.unset(QLatin1String("ORIGINALPATH"));
run.setEnvironment(runEnv);
run.setTimeoutS(30);
run.setTimeoutS(60);
Utils::FilePath cmdPath = Utils::FilePath::fromUserInput(
QString::fromLocal8Bit(qgetenv("COMSPEC")));
if (cmdPath.isEmpty())

View File

@@ -794,7 +794,9 @@ static void getExpandedCompilerFlags(QStringList &cFlags, QStringList &cxxFlags,
cFlags = cxxFlags = commonFlags;
const auto cxxLanguageVersion = arrayToStringList(getCppProp("cxxLanguageVersion"));
if (cxxLanguageVersion.contains("c++20"))
if (cxxLanguageVersion.contains("c++23"))
cxxFlags << "-std=c++2b";
else if (cxxLanguageVersion.contains("c++20"))
cxxFlags << "-std=c++20";
else if (cxxLanguageVersion.contains("c++17"))
cxxFlags << "-std=c++17";
@@ -850,9 +852,12 @@ static void getExpandedCompilerFlags(QStringList &cFlags, QStringList &cxxFlags,
cxxFlags << "/TP";
if (!enableRtti.isUndefined())
cxxFlags << QLatin1String(enableRtti.toBool() ? "/GR" : "/GR-");
if (getCppProp("cxxLanguageVersion").toArray().contains("c++20"))
const QJsonArray cxxLanguageVersion = getCppProp("cxxLanguageVersion").toArray();
if (cxxLanguageVersion.contains("c++23"))
cxxFlags << "/std:c++latest";
else if (cxxLanguageVersion.contains("c++20"))
cxxFlags << "/std:c++20";
else if (getCppProp("cxxLanguageVersion").toArray().contains("c++17"))
else if (cxxLanguageVersion.contains("c++17"))
cxxFlags << "/std:c++17";
}
}

View File

@@ -202,33 +202,36 @@ void ActionEditor::prepareConnections()
continue;
const QString name = QString::fromUtf8(propertyName);
const bool writeable = modelNode.metaInfo().propertyIsWritable(propertyName);
TypeName type = modelNode.metaInfo().propertyTypeName(propertyName);
if (type.contains("<cpp>."))
type.remove(0, 6);
connection.properties.append(ActionEditorDialog::PropertyOption(name, type));
connection.properties.append(ActionEditorDialog::PropertyOption(name, type, writeable));
}
for (const VariantProperty &variantProperty : modelNode.variantProperties()) {
if (variantProperty.isValid()) {
if (variantProperty.isDynamic()) {
if (!typeWhiteList.contains(variantProperty.dynamicTypeName()))
continue;
if (variantProperty.isValid() && variantProperty.isDynamic()) {
if (!typeWhiteList.contains(variantProperty.dynamicTypeName()))
continue;
const QString name = QString::fromUtf8(variantProperty.name());
TypeName type = variantProperty.dynamicTypeName();
if (type.contains("<cpp>."))
type.remove(0, 6);
const QString name = QString::fromUtf8(variantProperty.name());
const bool writeable = modelNode.metaInfo().propertyIsWritable(variantProperty.name());
TypeName type = variantProperty.dynamicTypeName();
if (type.contains("<cpp>."))
type.remove(0, 6);
connection.properties.append(ActionEditorDialog::PropertyOption(name, type));
}
connection.properties.append(ActionEditorDialog::PropertyOption(name, type, writeable));
}
}
for (const auto &slotName : modelNode.metaInfo().slotNames()) {
if (slotName.startsWith("q_") || slotName.startsWith("_q_"))
continue;
QmlJS::Document::MutablePtr newDoc = QmlJS::Document::create(
QLatin1String("<expression>"), QmlJS::Dialect::JavaScript);
newDoc->setSource(QLatin1String(slotName));
newDoc->setSource(modelNode.id() + "." + QLatin1String(slotName));
newDoc->parseExpression();
QmlJS::AST::ExpressionNode *expression = newDoc->expression();
@@ -263,10 +266,11 @@ void ActionEditor::prepareConnections()
continue;
const QString name = QString::fromUtf8(propertyName);
const bool writeable = metaInfo.propertyIsWritable(propertyName);
if (type.contains("<cpp>."))
type.remove(0, 6);
singelton.properties.append(ActionEditorDialog::PropertyOption(name, type));
singelton.properties.append(ActionEditorDialog::PropertyOption(name, type, writeable));
}
if (!singelton.properties.isEmpty()) {

View File

@@ -472,7 +472,7 @@ void ActionEditorDialog::fillAndSetTargetItem(const QString &value, bool useDefa
} else { // ConnectionType::Assignment
m_assignmentTargetItem->clear();
for (const auto &connection : qAsConst(m_connections)) {
if (!connection.properties.isEmpty())
if (!connection.properties.isEmpty() && connection.hasWriteableProperties())
m_assignmentTargetItem->addItem(connection.item);
}
@@ -516,8 +516,10 @@ void ActionEditorDialog::fillAndSetTargetProperty(const QString &value, bool use
if (idx == -1) {
insertAndSetUndefined(m_assignmentTargetProperty);
} else {
for (const auto &property : qAsConst(m_connections[idx].properties))
m_assignmentTargetProperty->addItem(property.name, property.type);
for (const auto &property : qAsConst(m_connections[idx].properties)) {
if (property.isWriteable)
m_assignmentTargetProperty->addItem(property.name, property.type);
}
if (m_assignmentTargetProperty->findText(value) != -1) {
m_assignmentTargetProperty->setCurrentText(value);

View File

@@ -51,10 +51,10 @@ public:
class PropertyOption
{
public:
PropertyOption() {}
PropertyOption(const QString &n, const TypeName &t)
PropertyOption(const QString &n, const TypeName &t, bool writeable = true)
: name(n)
, type(t)
, isWriteable(writeable)
{}
bool operator==(const QString &value) const { return value == name; }
@@ -62,6 +62,7 @@ public:
QString name;
TypeName type;
bool isWriteable;
};
class SingletonOption
@@ -80,6 +81,16 @@ public:
return false;
}
bool hasWriteableProperties() const
{
for (const auto &p : properties) {
if (p.isWriteable)
return true;
}
return false;
}
bool operator==(const QString &value) const { return value == item; }
bool operator==(const SingletonOption &value) const { return value.item == item; }
@@ -90,7 +101,6 @@ public:
class ConnectionOption : public SingletonOption
{
public:
ConnectionOption() {}
ConnectionOption(const QString &value) : SingletonOption(value) {}
QStringList methods;

View File

@@ -221,6 +221,7 @@ const int priorityLast = 60;
const char addImagesDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Image Files");
const char addFontsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Font Files");
const char addSoundsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Sound Files");
const char addVideosDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Video Files");
const char addShadersDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Shader Files");
const char add3DAssetsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "3D Assets");
const char addQt3DSPresentationsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",

View File

@@ -57,6 +57,7 @@
#include <QGraphicsLinearLayout>
#include <QHBoxLayout>
#include <QImageReader>
#include <QMessageBox>
#include <QMimeData>
@@ -1549,20 +1550,27 @@ void DesignerActionManager::createDefaultAddResourceHandler()
registerAddResourceHandler(AddResourceHandler(category, ext, op));
};
auto transformer = [](const QByteArray& format) -> QString { return QString("*.") + format; };
auto imageFormats = Utils::transform(QImageReader::supportedImageFormats(), transformer);
imageFormats.push_back("*.hdr");
// The filters will be displayed in reverse order to these lists in file dialog,
// so declare most common types last
registerHandlers({"*.webp", "*.hdr", "*.svg", "*.bmp", "*.jpg", "*.png"},
registerHandlers(imageFormats,
ModelNodeOperations::addImageToProject,
ComponentCoreConstants::addImagesDisplayString);
registerHandlers({"*.otf", "*.ttf"},
ModelNodeOperations::addFontToProject,
ComponentCoreConstants::addFontsDisplayString);
registerHandlers({"*.wav"},
registerHandlers({"*.wav", "*.mp3"},
ModelNodeOperations::addSoundToProject,
ComponentCoreConstants::addSoundsDisplayString);
registerHandlers({"*.glsl", "*.glslv", "*.glslf", "*.vsh", "*.fsh", "*.vert", "*.frag"},
ModelNodeOperations::addShaderToProject,
ComponentCoreConstants::addShadersDisplayString);
registerHandlers({"*.mp4"},
ModelNodeOperations::addVideoToProject,
ComponentCoreConstants::addVideosDisplayString);
}
void DesignerActionManager::createDefaultModelNodePreviewImageHandlers()

View File

@@ -1083,6 +1083,11 @@ AddFilesResult addImageToProject(const QStringList &fileNames, const QString &de
return addFilesToProject(fileNames, getAssetDefaultDirectory("images", defaultDirectory));
}
AddFilesResult addVideoToProject(const QStringList &fileNames, const QString &defaultDirectory)
{
return addFilesToProject(fileNames, getAssetDefaultDirectory("videos", defaultDirectory));
}
void createFlowActionArea(const SelectionContext &selectionContext)
{
AbstractView *view = selectionContext.view();

View File

@@ -80,6 +80,7 @@ AddFilesResult addImageToProject(const QStringList &fileNames, const QString &di
AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addVideoToProject(const QStringList &fileNames, const QString &directory);
void createFlowActionArea(const SelectionContext &selectionContext);
void addTransition(const SelectionContext &selectionState);
void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName);

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

View File

@@ -33,5 +33,7 @@
<file>images/x@2x.png</file>
<file>images/browse.png</file>
<file>images/browse@2x.png</file>
<file>images/item-video-icon.png</file>
<file>images/item-video-icon@2x.png</file>
</qresource>
</RCC>

View File

@@ -54,6 +54,8 @@ QPixmap ItemLibraryAssetsIconProvider::requestPixmap(const QString &id, QSize *s
pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/asset_shader_48.png");
else if (ItemLibraryAssetsModel::supportedAudioSuffixes().contains(suffix))
pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/asset_sound_48.png");
else if (ItemLibraryAssetsModel::supportedVideoSuffixes().contains(suffix))
pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/item-video-icon.png");
if (size) {
size->setWidth(pixmap.width());

View File

@@ -167,7 +167,13 @@ const QStringList &ItemLibraryAssetsModel::supportedFontSuffixes()
const QStringList &ItemLibraryAssetsModel::supportedAudioSuffixes()
{
static const QStringList retList {"*.wav"};
static const QStringList retList {"*.wav", "*.mp3"};
return retList;
}
const QStringList &ItemLibraryAssetsModel::supportedVideoSuffixes()
{
static const QStringList retList {"*.mp4"};
return retList;
}
@@ -300,6 +306,7 @@ const QSet<QString> &ItemLibraryAssetsModel::supportedSuffixes() const
insertSuffixes(supportedShaderSuffixes());
insertSuffixes(supportedFontSuffixes());
insertSuffixes(supportedAudioSuffixes());
insertSuffixes(supportedVideoSuffixes());
insertSuffixes(supportedTexture3DSuffixes());
}
return allSuffixes;

View File

@@ -66,6 +66,7 @@ public:
static const QStringList &supportedShaderSuffixes();
static const QStringList &supportedFontSuffixes();
static const QStringList &supportedAudioSuffixes();
static const QStringList &supportedVideoSuffixes();
static const QStringList &supportedTexture3DSuffixes();
const QSet<QString> &previewableSuffixes() const;

View File

@@ -552,6 +552,9 @@ QPair<QString, QByteArray> ItemLibraryWidget::getAssetTypeAndData(const QString
} else if (ItemLibraryAssetsModel::supportedAudioSuffixes().contains(suffix)) {
// No extra data for sounds
return {"application/vnd.bauhaus.libraryresource.sound", {}};
} else if (ItemLibraryAssetsModel::supportedVideoSuffixes().contains(suffix)) {
// No extra data for videos
return {"application/vnd.bauhaus.libraryresource.video", {}};
} else if (ItemLibraryAssetsModel::supportedTexture3DSuffixes().contains(suffix)) {
// Data: Image format (suffix)
return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()};
@@ -653,10 +656,12 @@ void ItemLibraryWidget::addResources(const QStringList &files)
QStringList fileNames = categoryFileNames.values(category);
AddResourceOperation operation = categoryToOperation.value(category);
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category);
AddFilesResult result = operation(fileNames, document->fileName().parentDir().toString());
if (result == AddFilesResult::Failed) {
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
tr("Could not add %1 to project.").arg(fileNames.join(' ')));
if (operation) {
AddFilesResult result = operation(fileNames, document->fileName().parentDir().toString());
if (result == AddFilesResult::Failed) {
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
tr("Could not add %1 to project.").arg(fileNames.join(' ')));
}
}
}
}

View File

@@ -168,12 +168,9 @@ void StatesEditorWidget::reloadQmlSource()
connect(rootObject(), SIGNAL(createNewState()), m_statesEditorView.data(), SLOT(createNewState()));
connect(rootObject(), SIGNAL(deleteState(int)), m_statesEditorView.data(), SLOT(removeState(int)));
m_statesEditorView.data()->synchonizeCurrentStateFromWidget();
setFixedHeight(initialSize().height());
if (!DesignerSettings::getValue(DesignerSettingsKey::STATESEDITOR_EXPANDED).toBool()) {
if (!DesignerSettings::getValue(DesignerSettingsKey::STATESEDITOR_EXPANDED).toBool())
toggleStatesViewExpanded();
setFixedHeight(rootObject()->height());
}
connect(rootObject(), SIGNAL(expandedChanged()), this, SLOT(handleExpandedChanged()));
}
@@ -184,7 +181,5 @@ void StatesEditorWidget::handleExpandedChanged()
bool expanded = rootObject()->property("expanded").toBool();
DesignerSettings::setValue(DesignerSettingsKey::STATESEDITOR_EXPANDED, expanded);
setFixedHeight(rootObject()->height());
}
}

View File

@@ -25,6 +25,8 @@
#pragma once
#include <utils/span.h>
#include <vector>
namespace QmlDesigner {
@@ -73,6 +75,15 @@ public:
InternalIntergerType id = -1;
};
template<typename Container>
auto toIntegers(const Container &container)
{
using DataType = typename Container::value_type::DatabaseType;
const DataType *data = reinterpret_cast<const DataType *>(container.data());
return Utils::span{data, container.size()};
}
enum class BasicIdType {
Type,
PropertyType,

View File

@@ -538,8 +538,13 @@ QProcessEnvironment PuppetCreator::processEnvironment() const
environment.set("QMLDESIGNER_QUICK3D_PARTICLES3D_MODE", "true");
import = QmlDesigner::Import::createLibraryImport("QtCharts", "2.0");
if (m_model->hasImport(import, true, true))
if (m_model->hasImport(import, true, true)) {
environment.set("QMLDESIGNER_FORCE_QAPPLICATION", "true");
} else if (m_target) {
auto bs = qobject_cast<QmlProjectManager::QmlBuildSystem *>(m_target->buildSystem());
if (bs && bs->widgetApp())
environment.set("QMLDESIGNER_FORCE_QAPPLICATION", "true");
}
bool particlemode = QmlDesigner::DesignerSettings::getValue("particleMode").toBool();
if (!particlemode)

View File

@@ -957,7 +957,8 @@ static QList<QmlDesigner::Import> generatePossibleLibraryImports(const QHash<QSt
if (majorVersion >= 0) {
int minorVersion = (importKey.minorVersion == LanguageUtils::ComponentVersion::NoVersion) ? 0 : importKey.minorVersion;
QString version = QStringLiteral("%1.%2").arg(majorVersion).arg(minorVersion);
possibleImports.append(QmlDesigner::Import::createLibraryImport(libraryName, version));
if (!libraryName.endsWith(".impl"))
possibleImports.append(QmlDesigner::Import::createLibraryImport(libraryName, version));
// In Qt6, QtQuick.Controls itself doesn't have any version as it has no types,
// so it never gets added normally to possible imports.

View File

@@ -77,14 +77,10 @@ public:
TypeIds typeIdsToBeDeleted;
auto sourceIdValues = Utils::transform<std::vector>(package.sourceIds, [](SourceId sourceId) {
return &sourceId;
});
std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end());
std::sort(sourceIdValues.begin(), sourceIdValues.end());
synchronizeFileStatuses(package.fileStatuses, sourceIdValues);
synchronizeImports(package.imports, sourceIdValues);
synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds);
synchronizeImports(package.imports, package.updatedSourceIds);
synchronizeTypes(package.types,
updatedTypeIds,
insertedAliasPropertyDeclarations,
@@ -92,10 +88,10 @@ public:
relinkableAliasPropertyDeclarations,
relinkablePropertyDeclarations,
relinkablePrototypes,
sourceIdValues);
package.updatedSourceIds);
deleteNotUpdatedTypes(updatedTypeIds,
sourceIdValues,
package.updatedSourceIds,
typeIdsToBeDeleted,
relinkableAliasPropertyDeclarations,
relinkablePropertyDeclarations,
@@ -109,6 +105,8 @@ public:
linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations);
synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds);
transaction.commit();
}
@@ -271,7 +269,7 @@ public:
SourceContextId fetchSourceContextId(SourceId sourceId) const
{
auto sourceContextId = selectSourceContextIdFromSourcesBySourceIdStatement
.template valueWithTransaction<SourceContextId>(sourceId.id);
.template valueWithTransaction<SourceContextId>(&sourceId);
if (!sourceContextId)
throw SourceIdDoesNotExists();
@@ -305,9 +303,16 @@ public:
&sourceId);
}
Storage::ProjectDatas fetchProjectDatas(SourceId sourceId) const override
Storage::ProjectDatas fetchProjectDatas(SourceId projectSourceId) const override
{
return Storage::ProjectDatas{};
return selectProjectDatasForModuleIdStatement
.template valuesWithTransaction<Storage::ProjectData>(64, &projectSourceId);
}
Storage::ProjectDatas fetchProjectDatas(const SourceIds &projectSourceIds) const
{
return selectProjectDatasForModuleIdsStatement
.template valuesWithTransaction<Storage::ProjectData>(64, toIntegers(projectSourceIds));
}
private:
@@ -332,7 +337,7 @@ private:
friend bool operator==(const Module &first, const Module &second)
{
return first.id == second.id && first.value == second.value;
return &first == &second && first.value == second.value;
}
};
@@ -503,7 +508,7 @@ private:
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes,
const std::vector<int> &sourceIdValues)
const SourceIds &updatedSourceIds)
{
Storage::ExportedTypes exportedTypes;
exportedTypes.reserve(types.size() * 3);
@@ -517,7 +522,7 @@ private:
extractExportedTypes(typeId, type, exportedTypes);
}
synchronizeExportedTypes(sourceIdValues,
synchronizeExportedTypes(updatedSourceIds,
updatedTypeIds,
exportedTypes,
relinkableAliasPropertyDeclarations,
@@ -532,10 +537,72 @@ private:
relinkablePropertyDeclarations);
}
void synchronizeFileStatuses(FileStatuses &fileStatuses, const std::vector<int> &sourceIdValues)
void synchronizeProjectDatas(Storage::ProjectDatas &projectDatas,
const SourceIds &updatedProjectSourceIds)
{
auto compareKey = [](auto &&first, auto &&second) {
return first.sourceId.id - second.sourceId.id;
auto projectSourceIdDifference = &first.projectSourceId - &second.projectSourceId;
if (projectSourceIdDifference != 0)
return projectSourceIdDifference;
return &first.sourceId - &second.sourceId;
};
std::sort(projectDatas.begin(), projectDatas.end(), [&](auto &&first, auto &&second) {
return std::tie(first.projectSourceId, first.sourceId)
< std::tie(second.projectSourceId, second.sourceId);
});
auto range = selectProjectDatasForModuleIdsStatement.template range<Storage::ProjectData>(
toIntegers(updatedProjectSourceIds));
auto insert = [&](const Storage::ProjectData &projectData) {
if (!projectData.projectSourceId)
throw ProjectDataHasInvalidProjectSourceId{};
if (!projectData.sourceId)
throw ProjectDataHasInvalidSourceId{};
if (!projectData.moduleId)
throw ProjectDataHasInvalidModuleId{};
insertProjectDataStatement.write(&projectData.projectSourceId,
&projectData.sourceId,
&projectData.moduleId,
static_cast<int>(projectData.fileType));
};
auto update = [&](const Storage::ProjectData &projectDataFromDatabase,
const Storage::ProjectData &projectData) {
if (!projectData.moduleId)
throw ProjectDataHasInvalidModuleId{};
if (projectDataFromDatabase.fileType != projectData.fileType
|| projectDataFromDatabase.moduleId != projectData.moduleId) {
updateProjectDataStatement.write(&projectData.projectSourceId,
&projectData.sourceId,
&projectData.moduleId,
static_cast<int>(projectData.fileType));
return Sqlite::UpdateChange::Update;
}
return Sqlite::UpdateChange::No;
};
auto remove = [&](const Storage::ProjectData &projectData) {
deleteProjectDataStatement.write(&projectData.projectSourceId, &projectData.sourceId);
};
Sqlite::insertUpdateDelete(range, projectDatas, compareKey, insert, update, remove);
}
void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds)
{
auto updatedSourceIdValues = Utils::transform<std::vector>(updatedSourceIds,
[](SourceId sourceId) {
return &sourceId;
});
auto compareKey = [](auto &&first, auto &&second) {
return &first.sourceId - &second.sourceId;
};
std::sort(fileStatuses.begin(), fileStatuses.end(), [&](auto &&first, auto &&second) {
@@ -543,7 +610,7 @@ private:
});
auto range = selectFileStatusesForSourceIdsStatement.template range<FileStatus>(
Utils::span(sourceIdValues));
toIntegers(updatedSourceIds));
auto insert = [&](const FileStatus &fileStatus) {
insertFileStatusStatement.write(&fileStatus.sourceId,
@@ -557,7 +624,10 @@ private:
updateFileStatusStatement.write(&fileStatus.sourceId,
fileStatus.size,
fileStatus.lastModified);
return Sqlite::UpdateChange::Update;
}
return Sqlite::UpdateChange::No;
};
auto remove = [&](const FileStatus &fileStatus) {
@@ -567,30 +637,32 @@ private:
Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove);
}
void synchronizeImports(Storage::Imports &imports, std::vector<int> &sourceIdValues)
void synchronizeImports(Storage::Imports &imports, const SourceIds &updatedSourceIds)
{
deleteDocumentImportsForDeletedDocuments(imports, sourceIdValues);
deleteDocumentImportsForDeletedDocuments(imports, updatedSourceIds);
synchronizeDocumentImports(imports, sourceIdValues);
synchronizeDocumentImports(imports, updatedSourceIds);
}
void deleteDocumentImportsForDeletedDocuments(Storage::Imports &imports,
const std::vector<int> &sourceIdValues)
const SourceIds &updatedSourceIds)
{
std::vector<int> importSourceIds = Utils::transform<std::vector<int>>(
imports, [](const Storage::Import &import) { return &import.sourceId; });
SourceIds importSourceIds = Utils::transform<SourceIds>(imports,
[](const Storage::Import &import) {
return import.sourceId;
});
std::sort(importSourceIds.begin(), importSourceIds.end());
std::vector<int> documentSourceIdsToBeDeleted;
SourceIds documentSourceIdsToBeDeleted;
std::set_difference(sourceIdValues.begin(),
sourceIdValues.end(),
std::set_difference(updatedSourceIds.begin(),
updatedSourceIds.end(),
importSourceIds.begin(),
importSourceIds.end(),
std::back_inserter(documentSourceIdsToBeDeleted));
deleteDocumentImportsWithSourceIdsStatement.write(Utils::span{documentSourceIdsToBeDeleted});
deleteDocumentImportsWithSourceIdsStatement.write(toIntegers(documentSourceIdsToBeDeleted));
}
ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const
@@ -767,17 +839,13 @@ private:
}
void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds,
const std::vector<int> &sourceIdValues,
const SourceIds &updatedSourceIds,
const TypeIds &typeIdsToBeDeleted,
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes,
TypeIds &deletedTypeIds)
{
auto updatedTypeIdValues = Utils::transform<std::vector>(updatedTypeIds, [](TypeId typeId) {
return &typeId;
});
auto callback = [&](long long typeId) {
deletedTypeIds.push_back(TypeId{typeId});
deleteType(TypeId{typeId},
@@ -788,8 +856,8 @@ private:
};
selectNotUpdatedTypesInSourcesStatement.readCallback(callback,
Utils::span(sourceIdValues),
Utils::span(updatedTypeIdValues));
toIntegers(updatedSourceIds),
toIntegers(updatedTypeIds));
for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted)
callback(&typeIdToBeDeleted);
}
@@ -853,7 +921,7 @@ private:
updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations);
}
void synchronizeExportedTypes(const std::vector<int> &sourceIdValues,
void synchronizeExportedTypes(const SourceIds &exportedSourceIds,
const TypeIds &updatedTypeIds,
Storage::ExportedTypes &exportedTypes,
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
@@ -865,17 +933,13 @@ private:
< std::tie(second.moduleId, second.name, second.version);
});
Utils::span typeIdValues{static_cast<const TypeIds::value_type::DatabaseType *>(
&updatedTypeIds.data()->id),
updatedTypeIds.size()};
auto range = selectExportedTypesForSourceIdsStatement
.template range<Storage::ExportedTypeView>(Utils::span{sourceIdValues},
typeIdValues);
.template range<Storage::ExportedTypeView>(toIntegers(exportedSourceIds),
toIntegers(updatedTypeIds));
auto compareKey = [](const Storage::ExportedTypeView &view,
const Storage::ExportedType &type) -> long long {
auto moduleIdDifference = view.moduleId.id - type.moduleId.id;
auto moduleIdDifference = &view.moduleId - &type.moduleId;
if (moduleIdDifference != 0)
return moduleIdDifference;
@@ -924,7 +988,9 @@ private:
relinkableAliasPropertyDeclarations);
handlePrototypes(view.typeId, relinkablePrototypes);
updateExportedTypeNameTypeIdStatement.write(&view.exportedTypeNameId, &type.typeId);
return Sqlite::UpdateChange::Update;
}
return Sqlite::UpdateChange::No;
};
auto remove = [&](const Storage::ExportedTypeView &view) {
@@ -998,7 +1064,7 @@ private:
view.aliasId);
}
void synchronizePropertyDeclarationsUpdateProperty(const Storage::PropertyDeclarationView &view,
auto synchronizePropertyDeclarationsUpdateProperty(const Storage::PropertyDeclarationView &view,
const Storage::PropertyDeclaration &value,
SourceId sourceId,
PropertyDeclarationIds &propertyDeclarationIds)
@@ -1012,7 +1078,7 @@ private:
if (view.traits == value.traits && propertyTypeId == view.typeId
&& propertyImportedTypeNameId == view.typeNameId)
return;
return Sqlite::UpdateChange::No;
updatePropertyDeclarationStatement.write(&view.id,
&propertyTypeId,
@@ -1021,6 +1087,7 @@ private:
updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement
.write(&view.id, &propertyTypeId, static_cast<int>(value.traits));
propertyDeclarationIds.push_back(view.id);
return Sqlite::UpdateChange::Update;
}
void synchronizePropertyDeclarations(TypeId typeId,
@@ -1064,11 +1131,13 @@ private:
sourceId);
propertyDeclarationIds.push_back(view.id);
} else {
synchronizePropertyDeclarationsUpdateProperty(view,
value,
sourceId,
propertyDeclarationIds);
return synchronizePropertyDeclarationsUpdateProperty(view,
value,
sourceId,
propertyDeclarationIds);
}
return Sqlite::UpdateChange::No;
};
auto remove = [&](const Storage::PropertyDeclarationView &view) {
@@ -1127,7 +1196,7 @@ private:
auto insert = [&](const Storage::PropertyDeclaration &) {};
auto update = [&](const AliasPropertyDeclarationView &,
const Storage::PropertyDeclaration &) {};
const Storage::PropertyDeclaration &) { return Sqlite::UpdateChange::No; };
auto remove = [&](const AliasPropertyDeclarationView &view) {
updatePropertyDeclarationAliasIdToNullStatement.write(&view.id);
@@ -1151,7 +1220,7 @@ private:
PropertyCompare<AliasPropertyDeclaration>{});
}
void synchronizeDocumentImports(Storage::Imports &imports, const std::vector<int> &sourceIdValues)
void synchronizeDocumentImports(Storage::Imports &imports, const SourceIds &updatedSourceIds)
{
std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) {
return std::tie(first.sourceId, first.moduleId, first.version)
@@ -1159,15 +1228,15 @@ private:
});
auto range = selectDocumentImportForSourceIdStatement.template range<Storage::ImportView>(
Utils::span{sourceIdValues});
toIntegers(updatedSourceIds));
auto compareKey = [](const Storage::ImportView &view,
const Storage::Import &import) -> long long {
auto sourceIdDifference = view.sourceId.id - import.sourceId.id;
auto sourceIdDifference = &view.sourceId - &import.sourceId;
if (sourceIdDifference != 0)
return sourceIdDifference;
auto moduleIdDifference = view.moduleId.id - import.moduleId.id;
auto moduleIdDifference = &view.moduleId - &import.moduleId;
if (moduleIdDifference != 0)
return moduleIdDifference;
@@ -1193,7 +1262,9 @@ private:
}
};
auto update = [](const Storage::ImportView &, const Storage::Import &) {};
auto update = [](const Storage::ImportView &, const Storage::Import &) {
return Sqlite::UpdateChange::No;
};
auto remove = [&](const Storage::ImportView &view) {
deleteDocumentImportStatement.write(&view.importId);
@@ -1258,9 +1329,11 @@ private:
Utils::PathString signature{createJson(value.parameters)};
if (value.returnTypeName == view.returnTypeName && signature == view.signature)
return;
return Sqlite::UpdateChange::No;
updateFunctionDeclarationStatement.write(&view.id, value.returnTypeName, signature);
return Sqlite::UpdateChange::Update;
};
auto remove = [&](const Storage::FunctionDeclarationView &view) {
@@ -1295,9 +1368,11 @@ private:
Utils::PathString signature{createJson(value.parameters)};
if (signature == view.signature)
return;
return Sqlite::UpdateChange::No;
updateSignalDeclarationStatement.write(&view.id, signature);
return Sqlite::UpdateChange::Update;
};
auto remove = [&](const Storage::SignalDeclarationView &view) {
@@ -1360,9 +1435,11 @@ private:
Utils::PathString enumeratorDeclarations{createJson(value.enumeratorDeclarations)};
if (enumeratorDeclarations == view.enumeratorDeclarations)
return;
return Sqlite::UpdateChange::No;
updateEnumerationDeclarationStatement.write(&view.id, enumeratorDeclarations);
return Sqlite::UpdateChange::Update;
};
auto remove = [&](const Storage::EnumerationDeclarationView &view) {
@@ -1760,6 +1837,7 @@ private:
createSignalsTable(database);
createDocumentImportsTable(database, moduleIdColumn);
createFileStatusesTable(database);
createProjectDatasTable(database);
transaction.commit();
@@ -2002,6 +2080,22 @@ private:
table.initialize(database);
}
void createProjectDatasTable(Database &database)
{
Sqlite::Table table;
table.setUseIfNotExists(true);
table.setUseWithoutRowId(true);
table.setName("projectDatas");
auto &projectSourceIdColumn = table.addColumn("projectSourceId");
auto &sourceIdColumn = table.addColumn("sourceId");
table.addColumn("moduleId");
table.addColumn("fileType");
table.addPrimaryKeyContraint({projectSourceIdColumn, sourceIdColumn});
table.initialize(database);
}
};
public:
@@ -2442,6 +2536,22 @@ public:
"DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database};
WriteStatement updateExportedTypeNameTypeIdStatement{
"UPDATE exportedTypeNames SET typeId=?2 WHERE exportedTypeNameId=?1", database};
mutable ReadStatement<4> selectProjectDatasForModuleIdsStatement{
"SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE "
"projectSourceId IN carray(?1) ORDER BY projectSourceId, sourceId",
database};
WriteStatement insertProjectDataStatement{"INSERT INTO projectDatas(projectSourceId, sourceId, "
"moduleId, fileType) VALUES(?1, ?2, ?3, ?4)",
database};
WriteStatement deleteProjectDataStatement{
"DELETE FROM projectDatas WHERE projectSourceId=?1 AND sourceId=?2", database};
WriteStatement updateProjectDataStatement{
"UPDATE projectDatas SET moduleId=?3, fileType=?4 WHERE projectSourceId=?1 AND sourceId=?2",
database};
mutable ReadStatement<4> selectProjectDatasForModuleIdStatement{
"SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE "
"projectSourceId=?1",
database};
};
} // namespace QmlDesigner

View File

@@ -107,4 +107,28 @@ public:
const char *what() const noexcept override { return "Cannot parse qml types file!"; }
};
class CannotParseQmlDocumentFile : std::exception
{
public:
const char *what() const noexcept override { return "Cannot parse qml types file!"; }
};
class ProjectDataHasInvalidProjectSourceId : std::exception
{
public:
const char *what() const noexcept override { return "The project source id is invalid!"; }
};
class ProjectDataHasInvalidSourceId : std::exception
{
public:
const char *what() const noexcept override { return "The source id is invalid!"; }
};
class ProjectDataHasInvalidModuleId : std::exception
{
public:
const char *what() const noexcept override { return "The module id is invalid!"; }
};
} // namespace QmlDesigner

View File

@@ -47,6 +47,8 @@ enum class PropertyDeclarationTraits : unsigned int {
enum class TypeNameKind { Native = 0, Exported = 1, QualifiedExported = 2 };
enum class FileType : char { QmlTypes, QmlDocument };
constexpr PropertyDeclarationTraits operator|(PropertyDeclarationTraits first,
PropertyDeclarationTraits second)
{
@@ -630,7 +632,7 @@ public:
PropertyDeclarationId aliasId;
};
enum class ChangeLevel { Full, Minimal };
enum class ChangeLevel : char { Full, Minimal, ExcludeExportedTypes };
class Type
{
@@ -668,6 +670,18 @@ public:
, prototypeId{prototypeId}
{}
explicit Type(Utils::SmallStringView typeName,
ImportedTypeName prototype,
TypeAccessSemantics accessSemantics,
SourceId sourceId,
ChangeLevel changeLevel)
: typeName{typeName}
, prototype{std::move(prototype)}
, accessSemantics{accessSemantics}
, sourceId{sourceId}
, changeLevel{changeLevel}
{}
explicit Type(Utils::SmallStringView typeName,
Utils::SmallStringView prototype,
int accessSemantics,
@@ -721,8 +735,31 @@ using Types = std::vector<Type>;
class ProjectData
{
public:
ModuleId extraModuleId;
ProjectData(SourceId projectSourceId, SourceId sourceId, ModuleId moduleId, FileType fileType)
: projectSourceId{projectSourceId}
, sourceId{sourceId}
, moduleId{moduleId}
, fileType{fileType}
{}
ProjectData(int projectSourceId, int sourceId, int moduleId, int fileType)
: projectSourceId{projectSourceId}
, sourceId{sourceId}
, moduleId{moduleId}
, fileType{static_cast<Storage::FileType>(fileType)}
{}
friend bool operator==(const ProjectData &first, const ProjectData &second)
{
return first.projectSourceId == second.projectSourceId && first.sourceId == second.sourceId
&& first.moduleId == second.moduleId && first.fileType == second.fileType;
}
public:
SourceId projectSourceId;
SourceId sourceId;
ModuleId moduleId;
FileType fileType;
};
using ProjectDatas = std::vector<ProjectData>;
@@ -731,30 +768,38 @@ class SynchronizationPackage
{
public:
SynchronizationPackage() = default;
SynchronizationPackage(Imports imports, Types types, SourceIds sourceIds)
SynchronizationPackage(Imports imports, Types types, SourceIds updatedSourceIds)
: imports{std::move(imports)}
, types{std::move(types)}
, sourceIds(std::move(sourceIds))
, updatedSourceIds(std::move(updatedSourceIds))
{}
SynchronizationPackage(Types types)
: types{std::move(types)}
{}
SynchronizationPackage(SourceIds sourceIds)
: sourceIds(std::move(sourceIds))
SynchronizationPackage(SourceIds updatedSourceIds)
: updatedSourceIds(std::move(updatedSourceIds))
{}
SynchronizationPackage(SourceIds sourceIds, FileStatuses fileStatuses)
: sourceIds(std::move(sourceIds))
SynchronizationPackage(SourceIds updatedFileStatusSourceIds, FileStatuses fileStatuses)
: updatedFileStatusSourceIds(std::move(updatedFileStatusSourceIds))
, fileStatuses(std::move(fileStatuses))
{}
SynchronizationPackage(SourceIds updatedProjectSourceIds, ProjectDatas projectDatas)
: projectDatas(std::move(projectDatas))
, updatedProjectSourceIds(std::move(updatedProjectSourceIds))
{}
public:
Imports imports;
Types types;
SourceIds sourceIds;
SourceIds updatedSourceIds;
FileStatuses fileStatuses;
ProjectDatas projectDatas;
SourceIds updatedProjectSourceIds;
SourceIds updatedFileStatusSourceIds;
};
} // namespace QmlDesigner::Storage

View File

@@ -38,6 +38,7 @@
#include <functional>
namespace QmlDesigner {
namespace {
ComponentReferences createComponentReferences(const QMultiHash<QString, QmlDirParser::Component> &components)
{
@@ -50,53 +51,117 @@ ComponentReferences createComponentReferences(const QMultiHash<QString, QmlDirPa
return componentReferences;
}
SourceIds filterNotUpdatedSourceIds(SourceIds updatedSourceIds, SourceIds notUpdatedSourceIds)
{
std::sort(updatedSourceIds.begin(), updatedSourceIds.end());
std::sort(notUpdatedSourceIds.begin(), notUpdatedSourceIds.end());
SourceIds filteredUpdatedSourceIds;
filteredUpdatedSourceIds.reserve(updatedSourceIds.size());
std::set_difference(updatedSourceIds.cbegin(),
updatedSourceIds.cend(),
notUpdatedSourceIds.cbegin(),
notUpdatedSourceIds.cend(),
std::back_inserter(filteredUpdatedSourceIds));
filteredUpdatedSourceIds.erase(std::unique(filteredUpdatedSourceIds.begin(),
filteredUpdatedSourceIds.end()),
filteredUpdatedSourceIds.end());
return filteredUpdatedSourceIds;
}
void addSourceIds(SourceIds &sourceIds, const Storage::ProjectDatas &projectDatas)
{
for (const auto &projectData : projectDatas)
sourceIds.push_back(projectData.sourceId);
}
} // namespace
void ProjectUpdater::update()
{
Storage::SynchronizationPackage package;
SourceIds notUpdatedFileStatusSourceIds;
SourceIds notUpdatedSourceIds;
for (const QString &qmldirPath : m_projectManager.qtQmlDirs()) {
SourcePath qmldirSourcePath{qmldirPath};
SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath);
switch (fileState(qmlDirSourceId, package.fileStatuses)) {
auto state = fileState(qmlDirSourceId,
package.fileStatuses,
package.updatedFileStatusSourceIds,
notUpdatedFileStatusSourceIds);
switch (state) {
case FileState::Changed: {
QmlDirParser parser;
parser.parse(m_fileSystem.contentAsQString(qmldirPath));
package.sourceIds.push_back(qmlDirSourceId);
package.updatedSourceIds.push_back(qmlDirSourceId);
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
Utils::PathString moduleName{parser.typeNamespace()};
ModuleId moduleId = m_projectStorage.moduleId(moduleName);
parseTypeInfos(parser.typeInfos(), directoryId, package);
const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
addSourceIds(package.updatedSourceIds, qmlProjectDatas);
addSourceIds(package.updatedFileStatusSourceIds, qmlProjectDatas);
parseTypeInfos(parser.typeInfos(),
qmlDirSourceId,
directoryId,
moduleId,
package,
notUpdatedFileStatusSourceIds,
notUpdatedSourceIds);
parseQmlComponents(createComponentReferences(parser.components()),
qmlDirSourceId,
directoryId,
moduleId,
package);
package,
notUpdatedFileStatusSourceIds);
package.updatedProjectSourceIds.push_back(qmlDirSourceId);
break;
}
case FileState::NotChanged: {
auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
parseTypeInfos(qmlProjectDatas, package);
const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
parseTypeInfos(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
parseQmlComponents(qmlProjectDatas, package, notUpdatedFileStatusSourceIds);
break;
}
case FileState::NotExists: {
// sourceIds.push_back(qmlDirSourceId);
package.updatedSourceIds.push_back(qmlDirSourceId);
auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
for (const Storage::ProjectData &projectData : qmlProjectDatas) {
package.updatedSourceIds.push_back(projectData.sourceId);
}
break;
}
}
}
package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds),
std::move(notUpdatedSourceIds));
package.updatedFileStatusSourceIds = filterNotUpdatedSourceIds(
std::move(package.updatedFileStatusSourceIds), std::move(notUpdatedFileStatusSourceIds));
m_projectStorage.synchronize(std::move(package));
}
void ProjectUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) {}
void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
SourceId qmldirSourceId,
SourceContextId directoryId,
Storage::SynchronizationPackage &package)
ModuleId moduleId,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds)
{
QString directory{m_pathCache.sourceContextPath(directoryId)};
@@ -104,37 +169,140 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo});
QString qmltypesPath = directory + "/" + typeInfo;
Storage::ProjectData projectData{ModuleId{}, sourceId};
auto projectData = package.projectDatas.emplace_back(qmldirSourceId,
sourceId,
moduleId,
Storage::FileType::QmlTypes);
parseTypeInfo(projectData, qmltypesPath, package);
parseTypeInfo(projectData,
qmltypesPath,
package,
notUpdatedFileStatusSourceIds,
notUpdatedSourceIds);
}
}
void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas,
Storage::SynchronizationPackage &package)
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds)
{
for (const Storage::ProjectData &projectData : projectDatas) {
if (projectData.fileType != Storage::FileType::QmlTypes)
continue;
QString qmltypesPath = m_pathCache.sourcePath(projectData.sourceId).toQString();
parseTypeInfo(projectData, qmltypesPath, package);
parseTypeInfo(projectData,
qmltypesPath,
package,
notUpdatedFileStatusSourceIds,
notUpdatedSourceIds);
}
}
void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
const QString &qmltypesPath,
Storage::SynchronizationPackage &package)
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds)
{
if (fileState(projectData.sourceId, package.fileStatuses) == FileState::Changed) {
package.sourceIds.push_back(projectData.sourceId);
auto state = fileState(projectData.sourceId,
package.fileStatuses,
package.updatedFileStatusSourceIds,
notUpdatedFileStatusSourceIds);
switch (state) {
case FileState::Changed: {
package.updatedSourceIds.push_back(projectData.sourceId);
const auto content = m_fileSystem.contentAsQString(qmltypesPath);
m_qmlTypesParser.parse(content, package.imports, package.types, projectData);
break;
}
case FileState::NotChanged: {
notUpdatedSourceIds.push_back(projectData.sourceId);
break;
}
case FileState::NotExists:
break;
}
}
void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView directory,
Utils::SmallStringView typeName,
Storage::Version version,
ModuleId moduleId,
SourceId qmldirSourceId,
SourceContextId directoryId,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds)
{
SourceId sourceId = m_pathCache.sourceId(directoryId, fileName);
Storage::Type type;
auto state = fileState(sourceId,
package.fileStatuses,
package.updatedFileStatusSourceIds,
notUpdatedFileStatusSourceIds);
switch (state) {
case FileState::NotChanged:
type.changeLevel = Storage::ChangeLevel::Minimal;
break;
case FileState::NotExists:
throw CannotParseQmlDocumentFile{};
case FileState::Changed:
const auto content = m_fileSystem.contentAsQString(
QString{Utils::PathString{directory} + "/" + fileName});
type = m_qmlDocumentParser.parse(content, package.imports);
break;
}
package.projectDatas.emplace_back(qmldirSourceId, sourceId, moduleId, Storage::FileType::QmlDocument);
package.updatedSourceIds.push_back(sourceId);
type.typeName = fileName;
type.accessSemantics = Storage::TypeAccessSemantics::Reference;
type.sourceId = sourceId;
type.exportedTypes.push_back(Storage::ExportedType{moduleId, typeName, version});
package.types.push_back(std::move(type));
}
void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView filePath,
SourceId sourceId,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds)
{
auto state = fileState(sourceId,
package.fileStatuses,
package.updatedFileStatusSourceIds,
notUpdatedFileStatusSourceIds);
if (state != FileState::Changed)
return;
package.updatedSourceIds.push_back(sourceId);
const auto content = m_fileSystem.contentAsQString(QString{filePath});
auto type = m_qmlDocumentParser.parse(content, package.imports);
type.typeName = fileName;
type.accessSemantics = Storage::TypeAccessSemantics::Reference;
type.sourceId = sourceId;
type.changeLevel = Storage::ChangeLevel::ExcludeExportedTypes;
package.types.push_back(std::move(type));
}
void ProjectUpdater::parseQmlComponents(ComponentReferences components,
SourceId qmldirSourceId,
SourceContextId directoryId,
ModuleId moduleId,
Storage::SynchronizationPackage &package)
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds)
{
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
return std::tie(first.get().typeName, first.get().majorVersion, first.get().minorVersion)
@@ -148,33 +316,43 @@ void ProjectUpdater::parseQmlComponents(ComponentReferences components,
components.erase(newEnd, components.end());
QString directory{m_pathCache.sourceContextPath(directoryId)};
auto directory = m_pathCache.sourceContextPath(directoryId);
for (const QmlDirParser::Component &component : components) {
Utils::SmallString fileName{component.fileName};
SourceId sourceId = m_pathCache.sourceId(directoryId, fileName);
if (fileState(sourceId, package.fileStatuses) != FileState::Changed)
continue;
package.sourceIds.push_back(sourceId);
const auto content = m_fileSystem.contentAsQString(directory + "/" + component.fileName);
auto type = m_qmlDocumentParser.parse(content, package.imports);
type.typeName = fileName;
type.accessSemantics = Storage::TypeAccessSemantics::Reference;
type.sourceId = sourceId;
type.exportedTypes.push_back(
Storage::ExportedType{moduleId,
Utils::SmallString{component.typeName},
Storage::Version{component.majorVersion, component.minorVersion}});
package.types.push_back(std::move(type));
parseQmlComponent(Utils::SmallString{component.fileName},
directory,
Utils::SmallString{component.typeName},
Storage::Version{component.majorVersion, component.minorVersion},
moduleId,
qmldirSourceId,
directoryId,
package,
notUpdatedFileStatusSourceIds);
}
}
ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId, FileStatuses &fileStatuses) const
void ProjectUpdater::parseQmlComponents(const Storage::ProjectDatas &projectDatas,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds)
{
for (const Storage::ProjectData &projectData : projectDatas) {
if (projectData.fileType != Storage::FileType::QmlDocument)
continue;
SourcePath qmlDocumentPath = m_pathCache.sourcePath(projectData.sourceId);
parseQmlComponent(qmlDocumentPath.name(),
qmlDocumentPath,
projectData.sourceId,
package,
notUpdatedFileStatusSourceIds);
}
}
ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId,
FileStatuses &fileStatuses,
SourceIds &updatedSourceIds,
SourceIds &notUpdatedSourceIds) const
{
auto currentFileStatus = m_fileStatusCache.find(sourceId);
@@ -185,9 +363,11 @@ ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId, FileStatu
if (!projectStorageFileStatus.isValid() || projectStorageFileStatus != currentFileStatus) {
fileStatuses.push_back(currentFileStatus);
updatedSourceIds.push_back(currentFileStatus.sourceId);
return FileState::Changed;
}
notUpdatedSourceIds.push_back(currentFileStatus.sourceId);
return FileState::NotChanged;
}

View File

@@ -87,19 +87,49 @@ private:
};
void parseTypeInfos(const QStringList &typeInfos,
SourceId qmldirSourceId,
SourceContextId directoryId,
Storage::SynchronizationPackage &package);
ModuleId moduleId,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds);
void parseTypeInfos(const Storage::ProjectDatas &projectDatas,
Storage::SynchronizationPackage &package);
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds);
void parseTypeInfo(const Storage::ProjectData &projectData,
const QString &qmltypesPath,
Storage::SynchronizationPackage &package);
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds);
void parseQmlComponents(ComponentReferences components,
SourceId qmldirSourceId,
SourceContextId directoryId,
ModuleId moduleId,
Storage::SynchronizationPackage &package);
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds);
void parseQmlComponents(const Storage::ProjectDatas &projectDatas,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds);
void parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView directory,
Utils::SmallStringView typeName,
Storage::Version version,
ModuleId moduleId,
SourceId qmldirSourceId,
SourceContextId directoryId,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds);
void parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView filePath,
SourceId sourceId,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds);
FileState fileState(SourceId sourceId, FileStatuses &fileStatuses) const;
FileState fileState(SourceId sourceId,
FileStatuses &fileStatuses,
SourceIds &updatedSourceIds,
SourceIds &notUpdatedSourceIds) const;
private:
ProjectManagerInterface &m_projectManager;

View File

@@ -283,7 +283,7 @@ void addTypes(Storage::Types &types,
types.reserve(Utils::usize(objects) + types.size());
for (const auto &object : objects)
addType(types, projectData.sourceId, projectData.extraModuleId, *object.get(), storage);
addType(types, projectData.sourceId, projectData.moduleId, *object.get(), storage);
}
} // namespace

View File

@@ -231,6 +231,7 @@ void DesignModeWidget::setup()
ADS::DockManager::setConfigFlags(ADS::DockManager::DefaultNonOpaqueConfig);
ADS::DockManager::setConfigFlag(ADS::DockManager::FocusHighlighting, true);
ADS::DockManager::setConfigFlag(ADS::DockManager::OpaqueSplitterResize, true);
ADS::DockManager::setConfigFlag(ADS::DockManager::AllTabsHaveCloseButton, true);
m_dockManager = new ADS::DockManager(this);
m_dockManager->setSettings(settings);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -31,7 +31,6 @@
<file>images/text-edit-icon16.png</file>
<file>images/text-input-icon16.png</file>
<file>images/webview-icon16.png</file>
<file>source/audio.qml</file>
<file>source/listview.qml</file>
<file>source/listviewv2.qml</file>
<file>source/gridview.qml</file>
@@ -84,9 +83,6 @@
<file>images/loader-icon.png</file>
<file>images/loader-icon@2x.png</file>
<file>images/loader-icon16.png</file>
<file>images/audio-16px.png</file>
<file>images/audio-24px.png</file>
<file>images/audio-24px@2x.png</file>
<file>images/audio-output-16px.png</file>
<file>images/audio-output-24px.png</file>
<file>images/audio-output-24px@2x.png</file>

View File

@@ -522,28 +522,6 @@ MetaInfo {
}
}
Type {
name: "QtMultimedia.MediaPlayer"
icon: ":/qtquickplugin/images/audio-16px.png"
Hints {
visibleInNavigator: true
canBeDroppedInNavigator: true
canBeDroppedInFormEditor: false
canBeContainer: false
}
ItemLibraryEntry {
name: "Audio"
category: "f.Qt Quick - Multimedia"
libraryIcon: ":/qtquickplugin/images/audio-24px.png"
version: "6.0"
requiredImport: "QtMultimedia"
QmlSource { source: ":/qtquickplugin/source/audio.qml" }
}
}
Type {
name: "QtMultimedia.AudioOutput"
icon: ":/qtquickplugin/images/audio-output-16px.png"
@@ -564,6 +542,26 @@ MetaInfo {
}
}
Type {
name: "QtMultimedia.VideoOutput"
icon: ":/qtquickplugin/images/video-output-16px.png"
Hints {
visibleInNavigator: true
canBeDroppedInNavigator: true
canBeDroppedInFormEditor: false
canBeContainer: false
}
ItemLibraryEntry {
name: "Video Output"
category: "f.Qt Quick - Multimedia"
libraryIcon: ":/qtquickplugin/images/video-output-24px.png"
version: "6.0"
requiredImport: "QtMultimedia"
}
}
Type {
name: "QtMultimedia.Video"
icon: ":/qtquickplugin/images/video-16px.png"

View File

@@ -1,35 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.0
import QtMultimedia 6.0
MediaPlayer {
audioOutput: output
AudioOutput {
id: output
}
}

View File

@@ -123,6 +123,10 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi
if (qt6ProjectProperty.isValid() && qt6ProjectProperty.value.toBool())
projectItem->setQt6Project(qt6ProjectProperty.value.toBool());
const auto widgetAppProperty = rootNode->property("widgetApp");
if (widgetAppProperty.isValid())
projectItem->setWidgetApp(widgetAppProperty.value.toBool());
if (debug)
qDebug() << "importPath:" << importPathsProperty.value << "mainFile:" << mainFileProperty.value;

View File

@@ -78,6 +78,9 @@ public:
QString mainFile() const { return m_mainFile; }
void setMainFile(const QString &mainFilePath) { m_mainFile = mainFilePath; }
bool widgetApp() const { return m_widgetApp; }
void setWidgetApp(bool widgetApp) { m_widgetApp = widgetApp; }
void appendContent(QmlProjectContentItem *item) { m_content.append(item); }
Utils::EnvironmentItems environment() const;
@@ -99,6 +102,7 @@ protected:
bool m_forceFreeType = false;
bool m_qtForMCUs = false;
bool m_qt6Project = false;
bool m_widgetApp = false;
};
} // namespace QmlProjectManager

View File

@@ -585,6 +585,13 @@ bool QmlBuildSystem::forceFreeType() const
return false;
}
bool QmlBuildSystem::widgetApp() const
{
if (m_projectItem)
return m_projectItem.data()->widgetApp();
return false;
}
bool QmlBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *)
{
if (!dynamic_cast<QmlProjectNode *>(context))

View File

@@ -93,6 +93,7 @@ public:
QString primaryLanguage() const;
void setPrimaryLanguage(QString language);
bool forceFreeType() const;
bool widgetApp() const;
bool addFiles(const QStringList &filePaths);

View File

@@ -227,6 +227,11 @@ QString QmlProjectRunConfiguration::commandLineArguments() const
ProcessArgs::addArg(&args, "windows:fontengine=freetype", osType);
}
if (bs->qt6Project() && bs->widgetApp()) {
ProcessArgs::addArg(&args, "--apptype", osType);
ProcessArgs::addArg(&args, "widget", osType);
}
const QString main = bs->targetFile(FilePath::fromString(mainScript())).toString();
if (!main.isEmpty())
ProcessArgs::addArg(&args, main, osType);

View File

@@ -185,7 +185,13 @@ void QnxToolChain::setCpuDir(const QString &cpuDir)
GccToolChain::DetectedAbisResult QnxToolChain::detectSupportedAbis() const
{
return detectTargetAbis(m_sdpPath);
// "unknown-qnx-gnu"is needed to get the "--target=xxx" parameter sent code model,
// which gets translated as "x86_64-qnx-gnu", which gets Clang to happily parse
// the QNX code.
//
// Without it on Windows Clang defaults to a MSVC mode, which breaks with
// the QNX code, which is mostly GNU based.
return GccToolChain::DetectedAbisResult{detectTargetAbis(m_sdpPath), "unknown-qnx-gnu"};
}
bool QnxToolChain::operator ==(const ToolChain &other) const

View File

@@ -96,7 +96,7 @@ QPixmap NewProjectDialogImageProvider::requestDefaultPixmap(const QString &id, Q
}
if (pixmap.isNull())
return QPixmap{};
return {};
if (requestedSize.isValid())
return pixmap.scaled(requestedSize);

View File

@@ -94,7 +94,7 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
m_dialog->setWindowModality(Qt::ApplicationModal);
m_dialog->setWindowFlags(Qt::Dialog);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
m_dialog->setMinimumSize(1110, 554);
m_dialog->setMinimumSize(1066, 554);
QSize screenSize = m_dialog->screen()->geometry().size();
if (screenSize.height() < 1080)

View File

@@ -126,7 +126,7 @@ CodeAssistantPrivate::CodeAssistantPrivate(CodeAssistant *assistant)
connect(&m_automaticProposalTimer, &QTimer::timeout,
this, &CodeAssistantPrivate::automaticProposalTimeout);
m_settings = TextEditorSettings::completionSettings();
updateFromCompletionSettings(TextEditorSettings::completionSettings());
connect(TextEditorSettings::instance(), &TextEditorSettings::completionSettingsChanged,
this, &CodeAssistantPrivate::updateFromCompletionSettings);

View File

@@ -93,10 +93,8 @@ bool FindInCurrentFile::isEnabled() const
void FindInCurrentFile::handleFileChange(Core::IEditor *editor)
{
if (!editor) {
if (m_currentDocument) {
m_currentDocument = nullptr;
emit enabledChanged(isEnabled());
}
m_currentDocument = nullptr;
emit enabledChanged(isEnabled());
} else {
Core::IDocument *document = editor->document();
if (document != m_currentDocument) {

View File

@@ -29,6 +29,7 @@
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <QLatin1String>
@@ -77,7 +78,7 @@ const QLatin1String kModified("modified");
SnippetsCollection::Hint::Hint(int index) : m_index(index)
{}
SnippetsCollection::Hint::Hint(int index, QList<Snippet>::iterator it) : m_index(index), m_it(it)
SnippetsCollection::Hint::Hint(int index, QVector<Snippet>::iterator it) : m_index(index), m_it(it)
{}
int SnippetsCollection::Hint::index() const
@@ -112,7 +113,7 @@ void SnippetsCollection::insertSnippet(const Snippet &snippet, const Hint &hint)
{
const int group = groupIndex(snippet.groupId());
if (snippet.isBuiltIn() && snippet.isRemoved()) {
m_activeSnippetsEnd[group] = m_snippets[group].insert(m_activeSnippetsEnd[group], snippet);
m_snippets[group].append(snippet);
} else {
m_snippets[group].insert(hint.m_it, snippet);
updateActiveSnippetsEnd(group);
@@ -122,9 +123,12 @@ void SnippetsCollection::insertSnippet(const Snippet &snippet, const Hint &hint)
SnippetsCollection::Hint SnippetsCollection::computeInsertionHint(const Snippet &snippet)
{
const int group = groupIndex(snippet.groupId());
QList<Snippet> &snippets = m_snippets[group];
QList<Snippet>::iterator it = std::upper_bound(snippets.begin(), m_activeSnippetsEnd.at(group),
snippet, snippetComp);
QVector<Snippet> &snippets = m_snippets[group];
QVector<Snippet>::iterator it = std::upper_bound(snippets.begin(),
snippets.begin()
+ m_activeSnippetsCount.at(group),
snippet,
snippetComp);
return Hint(static_cast<int>(std::distance(snippets.begin(), it)), it);
}
@@ -157,13 +161,16 @@ SnippetsCollection::Hint SnippetsCollection::computeReplacementHint(int index,
const Snippet &snippet)
{
const int group = groupIndex(snippet.groupId());
QList<Snippet> &snippets = m_snippets[group];
QList<Snippet>::iterator it = std::lower_bound(snippets.begin(), m_activeSnippetsEnd.at(group),
snippet, snippetComp);
QVector<Snippet> &snippets = m_snippets[group];
auto activeSnippetsEnd = snippets.begin() + m_activeSnippetsCount.at(group);
QVector<Snippet>::iterator it = std::lower_bound(snippets.begin(),
activeSnippetsEnd,
snippet,
snippetComp);
int hintIndex = static_cast<int>(std::distance(snippets.begin(), it));
if (index < hintIndex - 1)
return Hint(hintIndex - 1, it);
it = std::upper_bound(it, m_activeSnippetsEnd.at(group), snippet, snippetComp);
it = std::upper_bound(it, activeSnippetsEnd, snippet, snippetComp);
hintIndex = static_cast<int>(std::distance(snippets.begin(), it));
if (index > hintIndex)
return Hint(hintIndex, it);
@@ -176,11 +183,10 @@ void SnippetsCollection::removeSnippet(int index, const QString &groupId)
const int group = groupIndex(groupId);
Snippet snippet(m_snippets.at(group).at(index));
m_snippets[group].removeAt(index);
updateActiveSnippetsEnd(group);
if (snippet.isBuiltIn()) {
snippet.setIsRemoved(true);
m_activeSnippetsEnd[group] = m_snippets[group].insert(m_activeSnippetsEnd[group], snippet);
} else {
updateActiveSnippetsEnd(group);
m_snippets[group].append(snippet);
}
}
@@ -202,8 +208,7 @@ void SnippetsCollection::setSnippetContent(int index,
int SnippetsCollection::totalActiveSnippets(const QString &groupId) const
{
const int group = groupIndex(groupId);
return std::distance<QList<Snippet>::const_iterator>(m_snippets.at(group).begin(),
QList<Snippet>::const_iterator(m_activeSnippetsEnd.at(group)));
return m_activeSnippetsCount.at(group);
}
int SnippetsCollection::totalSnippets(const QString &groupId) const
@@ -225,14 +230,14 @@ void SnippetsCollection::clearSnippets()
void SnippetsCollection::clearSnippets(int groupIndex)
{
m_snippets[groupIndex].clear();
m_activeSnippetsEnd[groupIndex] = m_snippets[groupIndex].end();
m_activeSnippetsCount[groupIndex] = m_snippets[groupIndex].size();
}
void SnippetsCollection::updateActiveSnippetsEnd(int groupIndex)
{
m_activeSnippetsEnd[groupIndex] = std::find_if(m_snippets[groupIndex].begin(),
m_snippets[groupIndex].end(),
[](const Snippet &s) { return s.isRemoved(); });
const int index = Utils::indexOf(m_snippets[groupIndex],
[](const Snippet &s) { return s.isRemoved(); });
m_activeSnippetsCount[groupIndex] = index < 0 ? m_snippets[groupIndex].size() : index;
}
void SnippetsCollection::restoreRemovedSnippets(const QString &groupId)
@@ -240,9 +245,11 @@ void SnippetsCollection::restoreRemovedSnippets(const QString &groupId)
// The version restored contains the last modifications (if any) by the user.
// Reverting the snippet can still bring it to the original version
const int group = groupIndex(groupId);
QVector<Snippet> toRestore(std::distance(m_activeSnippetsEnd[group], m_snippets[group].end()));
std::copy(m_activeSnippetsEnd[group], m_snippets[group].end(), toRestore.begin());
m_snippets[group].erase(m_activeSnippetsEnd[group], m_snippets[group].end());
if (m_activeSnippetsCount[group] == m_snippets[group].size()) // no removed snippets
return;
const QVector<Snippet> toRestore = m_snippets[group].mid(m_activeSnippetsCount[group]);
m_snippets[group].resize(m_activeSnippetsCount[group]);
for (Snippet snippet : qAsConst(toRestore)) {
snippet.setIsRemoved(false);
insertSnippet(snippet);
@@ -425,8 +432,8 @@ void SnippetsCollection::identifyGroups()
const int groupIndex = m_groupIndexById.size();
m_groupIndexById.insert(provider.groupId(), groupIndex);
m_snippets.resize(groupIndex + 1);
m_activeSnippetsEnd.resize(groupIndex + 1);
m_activeSnippetsEnd[groupIndex] = m_snippets[groupIndex].end();
m_activeSnippetsCount.resize(groupIndex + 1);
m_activeSnippetsCount[groupIndex] = m_snippets[groupIndex].size();
}
reload();

View File

@@ -61,9 +61,9 @@ public:
int index() const;
private:
explicit Hint(int index);
Hint(int index, QList<Snippet>::iterator it);
Hint(int index, QVector<Snippet>::iterator it);
int m_index;
QList<Snippet>::iterator m_it;
QVector<Snippet>::iterator m_it;
};
void insertSnippet(const Snippet &snippet);
@@ -120,8 +120,8 @@ private:
// Snippets for each group are kept in a list. However, not all of them are necessarily
// active. Specifically, removed built-in snippets are kept as the last ones (for each
// group there is a iterator that marks the logical end).
QVector<QList<Snippet> > m_snippets;
QVector<QList<Snippet>::iterator> m_activeSnippetsEnd;
QVector<QVector<Snippet> > m_snippets;
QVector<int> m_activeSnippetsCount;
QHash<QString, int> m_groupIndexById;
};

View File

@@ -2400,7 +2400,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
if (camelCaseNavigationEnabled())
CamelCaseCursor::left(&cursor, this, QTextCursor::KeepAnchor);
else
d->moveCursor(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
}
cursor.removeSelectedText();
setMultiTextCursor(cursor);
@@ -2411,7 +2411,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
if (camelCaseNavigationEnabled())
CamelCaseCursor::right(&cursor, this, QTextCursor::KeepAnchor);
else
d->moveCursor(QTextCursor::NextWord, QTextCursor::KeepAnchor);
cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
}
cursor.removeSelectedText();
setMultiTextCursor(cursor);
@@ -6257,10 +6257,10 @@ MultiTextCursor TextEditorWidget::multiTextCursor() const
void TextEditorWidget::setMultiTextCursor(const Utils::MultiTextCursor &cursor)
{
if (d->m_cursors == cursor)
return;
MultiTextCursor oldCursor = d->m_cursors;
const MultiTextCursor oldCursor = d->m_cursors;
const_cast<MultiTextCursor &>(d->m_cursors) = cursor;
if (oldCursor == d->m_cursors)
return;
doSetTextCursor(d->m_cursors.mainCursor(), /*keepMultiSelection*/ true);
QRect updateRect = d->cursorUpdateRect(oldCursor);
if (d->m_highlightCurrentLine)