diff options
author | Eike Ziller <eike.ziller@qt.io> | 2021-04-09 12:42:03 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2021-04-09 12:42:03 +0200 |
commit | 2800f3b51f70d50d2d976ee6340b71c29efd17d0 (patch) | |
tree | c7f356d9a245a65cc743916140d60473da3697d2 /src | |
parent | 86679c130b2905d4de88669b481f7eb2e9415aa9 (diff) | |
parent | 8413d6d58569b5ed02ca4778fbc2ff568e7b1f0a (diff) | |
download | qt-creator-2800f3b51f70d50d2d976ee6340b71c29efd17d0.tar.gz |
Merge remote-tracking branch 'origin/4.15'
Change-Id: I0afcf51d354ffd73a8f2956a7f78b1e4f032677b
Diffstat (limited to 'src')
39 files changed, 495 insertions, 186 deletions
diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index c85444a228..871bb3a87f 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -462,6 +462,7 @@ void TypePrettyPrinter::visit(Function *type) argumentText.showReturnTypes = true; argumentText.showArgumentNames = false; argumentText.showFunctionSignatures = true; + argumentText.showTemplateParameters = _overview->showTemplateParameters; _text += QLatin1Char('('); diff --git a/src/plugins/autotest/autotestunittests.cpp b/src/plugins/autotest/autotestunittests.cpp index e799eb7b43..b65fb25c3d 100644 --- a/src/plugins/autotest/autotestunittests.cpp +++ b/src/plugins/autotest/autotestunittests.cpp @@ -213,7 +213,7 @@ void AutoTestUnitTests::testCodeParserGTest() QVERIFY(parserSpy.wait(20000)); QVERIFY(modelUpdateSpy.wait()); - QCOMPARE(m_model->gtestNamesCount(), 7); + QCOMPARE(m_model->gtestNamesCount(), 8); QMultiMap<QString, int> expectedNamesAndSets; expectedNamesAndSets.insert(QStringLiteral("FactorialTest"), 3); @@ -222,6 +222,7 @@ void AutoTestUnitTests::testCodeParserGTest() expectedNamesAndSets.insert(QStringLiteral("QueueTest"), 2); expectedNamesAndSets.insert(QStringLiteral("DummyTest"), 1); // used as parameterized test expectedNamesAndSets.insert(QStringLiteral("DummyTest"), 1); // used as 'normal' test + expectedNamesAndSets.insert(QStringLiteral("NumberAsNameStart"), 1); expectedNamesAndSets.insert(QStringLiteral("NamespaceTest"), 1); QMultiMap<QString, int> foundNamesAndSets = m_model->gtestNamesAndSets(); diff --git a/src/plugins/autotest/gtest/gtestvisitors.cpp b/src/plugins/autotest/gtest/gtestvisitors.cpp index 80c2051f46..9f622acb5b 100644 --- a/src/plugins/autotest/gtest/gtestvisitors.cpp +++ b/src/plugins/autotest/gtest/gtestvisitors.cpp @@ -29,6 +29,8 @@ #include <cplusplus/LookupContext.h> #include <utils/qtcassert.h> +#include <QRegularExpression> + namespace Autotest { namespace Internal { @@ -45,7 +47,7 @@ bool GTestVisitor::visit(CPlusPlus::FunctionDefinitionAST *ast) return false; CPlusPlus::DeclaratorIdAST *id = ast->declarator->core_declarator->asDeclaratorId(); - if (!id || !ast->symbol || ast->symbol->argumentCount() != 2) + if (!id || !ast->symbol) return false; QString prettyName = @@ -61,33 +63,68 @@ bool GTestVisitor::visit(CPlusPlus::FunctionDefinitionAST *ast) if (!GTestUtils::isGTestMacro(prettyName)) return false; - CPlusPlus::Argument *testCaseNameArg = ast->symbol->argumentAt(0)->asArgument(); - CPlusPlus::Argument *testNameArg = ast->symbol->argumentAt(1)->asArgument(); - if (testCaseNameArg && testNameArg) { - const QString &testCaseName = m_overview.prettyType(testCaseNameArg->type()); - const QString &testName = m_overview.prettyType(testNameArg->type()); - - const bool disabled = testName.startsWith(disabledPrefix); - const bool disabledCase = testCaseName.startsWith(disabledPrefix); - int line = 0; - int column = 0; - unsigned token = id->firstToken(); - m_document->translationUnit()->getTokenStartPosition(token, &line, &column); - - GTestCodeLocationAndType locationAndType; - locationAndType.m_name = testName; - locationAndType.m_line = line; - locationAndType.m_column = column - 1; - locationAndType.m_type = TestTreeItem::TestCase; - locationAndType.m_state = disabled ? GTestTreeItem::Disabled - : GTestTreeItem::Enabled; - GTestCaseSpec spec; - spec.testCaseName = testCaseName; - spec.parameterized = GTestUtils::isGTestParameterized(prettyName); - spec.typed = GTestUtils::isGTestTyped(prettyName); - spec.disabled = disabledCase; - m_gtestFunctions[spec].append(locationAndType); + QString testSuiteName; + QString testCaseName; + if (ast->symbol->argumentCount() != 2 && ast->declarator->initializer) { + // we might have a special case when second parameter is a literal starting with a number + if (auto expressionListParenAST = ast->declarator->initializer->asExpressionListParen()) { + // only try if we have 3 tokens between left and right paren (2 parameters and a comma) + if (expressionListParenAST->rparen_token - expressionListParenAST->lparen_token != 4) + return false; + + const CPlusPlus::Token parameter1 + = translationUnit()->tokenAt(expressionListParenAST->lparen_token + 1); + const CPlusPlus::Token parameter2 + = translationUnit()->tokenAt(expressionListParenAST->rparen_token - 1); + const CPlusPlus::Token comma + = translationUnit()->tokenAt(expressionListParenAST->lparen_token + 2); + if (!comma.is(CPlusPlus::T_COMMA)) + return false; + + testSuiteName = QString::fromUtf8(parameter1.spell()); + testCaseName = QString::fromUtf8(parameter2.spell()); + // test (suite) name needs to be a alpha numerical literal ( _ and $ allowed) + const QRegularExpression alnum("^[[:alnum:]_$]+$"); + // test suite must not start with a number, test case may + if (!alnum.match(testSuiteName).hasMatch() + || (!testSuiteName.isEmpty() && testSuiteName.at(0).isNumber())) { + testSuiteName.clear(); + } + if (!alnum.match(testCaseName).hasMatch()) + testCaseName.clear(); + } + } else { + const CPlusPlus::Argument *testSuiteNameArg = ast->symbol->argumentAt(0)->asArgument(); + const CPlusPlus::Argument *testCaseNameArg = ast->symbol->argumentAt(1)->asArgument(); + if (testSuiteNameArg && testCaseNameArg) { + testSuiteName = m_overview.prettyType(testSuiteNameArg->type()); + testCaseName = m_overview.prettyType(testCaseNameArg->type()); + } } + if (testSuiteName.isEmpty() || testCaseName.isEmpty()) + return false; + + const bool disabled = testCaseName.startsWith(disabledPrefix); + const bool disabledCase = testSuiteName.startsWith(disabledPrefix); + int line = 0; + int column = 0; + unsigned token = id->firstToken(); + m_document->translationUnit()->getTokenStartPosition(token, &line, &column); + + GTestCodeLocationAndType locationAndType; + locationAndType.m_name = testCaseName; + locationAndType.m_line = line; + locationAndType.m_column = column - 1; + locationAndType.m_type = TestTreeItem::TestCase; + locationAndType.m_state = disabled ? GTestTreeItem::Disabled + : GTestTreeItem::Enabled; + GTestCaseSpec spec; + // FIXME GTestCaseSpec structure wrong nowadays (suite vs case / case vs function) + spec.testCaseName = testSuiteName; + spec.parameterized = GTestUtils::isGTestParameterized(prettyName); + spec.typed = GTestUtils::isGTestTyped(prettyName); + spec.disabled = disabledCase; + m_gtestFunctions[spec].append(locationAndType); return false; } diff --git a/src/plugins/autotest/unit_test/simple_gt/tests/gt1/main.cpp b/src/plugins/autotest/unit_test/simple_gt/tests/gt1/main.cpp index a4a394b310..eb907c6007 100644 --- a/src/plugins/autotest/unit_test/simple_gt/tests/gt1/main.cpp +++ b/src/plugins/autotest/unit_test/simple_gt/tests/gt1/main.cpp @@ -70,6 +70,11 @@ TEST(FactorialTest_Iterative, DISABLED_HandlesPositiveInput) ASSERT_EQ(40320, factorial_it(8)); } +TEST(NumberAsNameStart, 1IsEnough) +{ + EXPECT_FALSE(false); +} + int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 07fdd16f05..dac933afc3 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -534,6 +534,14 @@ void CMakeBuildStep::recreateBuildTargetsModel() addItem(QString(), true); + // Remove the targets that do not exist in the build system + // This can result when selected targets get renamed + if (!targetList.empty()) { + Utils::erase(m_buildTargets, [targetList](const QString &bt) { return !targetList.contains(bt); }); + if (m_buildTargets.empty()) + m_buildTargets.push_back(m_allTarget); + } + for (const QString &buildTarget : qAsConst(targetList)) addItem(buildTarget, specialTargets(usesAllCapsTargets).contains(buildTarget)); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 1755181948..eafbe2c9f2 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -932,10 +932,6 @@ void CMakeBuildSystem::becameDirty() if (isParsing()) return; - const CMakeTool *tool = m_parameters.cmakeTool(); - if (!tool->isAutoRun()) - return; - setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()), REPARSE_SCAN); } diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 37ca090f7e..0fcbe92e98 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -3839,7 +3839,7 @@ void CppEditorPlugin::test_quickfix_InsertDefFromDecl_headerSource_basic2() QByteArray expected; // Header File - original = "void f()@;\n"; + original = "void f(const std::vector<int> &v)@;\n"; expected = original; testDocuments << QuickFixTestDocument::create("file.h", original, expected); @@ -3854,7 +3854,7 @@ void CppEditorPlugin::test_quickfix_InsertDefFromDecl_headerSource_basic2() "\n" "int x;\n" "\n" - "void f()\n" + "void f(const std::vector<int> &v)\n" "{\n" "\n" "}\n" diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 9ec611200f..75d7caf7c5 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -456,20 +456,21 @@ void Client::requestDocumentHighlights(TextEditor::TextEditorWidget *widget) return; } - auto runningRequest = m_highlightRequests.find(uri); - if (runningRequest != m_highlightRequests.end()) - cancelRequest(runningRequest.value()); + if (m_highlightRequests.contains(widget)) + cancelRequest(m_highlightRequests.take(widget)); DocumentHighlightsRequest request( TextDocumentPositionParams(TextDocumentIdentifier(uri), Position(widget->textCursor()))); + auto connection = connect(widget, &QObject::destroyed, this, [this, widget]() { + if (m_highlightRequests.contains(widget)) + cancelRequest(m_highlightRequests.take(widget)); + }); request.setResponseCallback( - [widget = QPointer<TextEditor::TextEditorWidget>(widget), this, uri] + [widget, this, uri, connection] (const DocumentHighlightsRequest::Response &response) { - m_highlightRequests.remove(uri); - if (!widget) - return; - + m_highlightRequests.remove(widget); + disconnect(connection); const Id &id = TextEditor::TextEditorWidget::CodeSemanticsSelection; QList<QTextEdit::ExtraSelection> selections; const Utils::optional<DocumentHighlightsResult> &result = response.result(); @@ -493,7 +494,7 @@ void Client::requestDocumentHighlights(TextEditor::TextEditorWidget *widget) } widget->setExtraSelections(id, selections); }); - m_highlightRequests[uri] = request.id(); + m_highlightRequests[widget] = request.id(); sendContent(request); } @@ -713,19 +714,19 @@ void Client::cursorPositionChanged(TextEditor::TextEditorWidget *widget) QTimer *timer = m_documentHighlightsTimer[widget]; if (!timer) { const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath()); - auto runningRequest = m_highlightRequests.find(uri); - if (runningRequest != m_highlightRequests.end()) - cancelRequest(runningRequest.value()); + if (m_highlightRequests.contains(widget)) + cancelRequest(m_highlightRequests.take(widget)); timer = new QTimer; timer->setSingleShot(true); m_documentHighlightsTimer.insert(widget, timer); - connect(timer, &QTimer::timeout, this, [this, widget]() { + auto connection = connect(widget, &QWidget::destroyed, this, [widget, this]() { + delete m_documentHighlightsTimer.take(widget); + }); + connect(timer, &QTimer::timeout, this, [this, widget, connection]() { + disconnect(connection); requestDocumentHighlights(widget); m_documentHighlightsTimer.take(widget)->deleteLater(); }); - connect(widget, &QWidget::destroyed, this, [widget, this]() { - delete m_documentHighlightsTimer.take(widget); - }); } const Id selectionsId(TextEditor::TextEditorWidget::CodeSemanticsSelection); const QList semanticSelections = widget->extraSelections(selectionsId); diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 4210831014..d3d86870fa 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -231,7 +231,7 @@ private: AssistProviders m_clientProviders; QMap<TextEditor::TextDocument *, AssistProviders> m_resetAssistProvider; - QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests; + QHash<TextEditor::TextEditorWidget *, LanguageServerProtocol::MessageId> m_highlightRequests; int m_restartsLeft = 5; QScopedPointer<BaseClientInterface> m_clientInterface; DiagnosticManager m_diagnosticManager; diff --git a/src/plugins/languageclient/languageclienthoverhandler.cpp b/src/plugins/languageclient/languageclienthoverhandler.cpp index f9533ab470..bf537d6f00 100644 --- a/src/plugins/languageclient/languageclienthoverhandler.cpp +++ b/src/plugins/languageclient/languageclienthoverhandler.cpp @@ -59,7 +59,8 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, { if (m_currentRequest.has_value()) abort(); - if (m_client.isNull() || !m_client->documentOpen(editorWidget->textDocument())) { + if (m_client.isNull() || !m_client->documentOpen(editorWidget->textDocument()) + || !m_client->reachable()) { report(Priority_None); return; } diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index de3f7f596e..9671ad9835 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -311,12 +311,15 @@ void KitManagerConfigWidget::setIcon() for (const IDeviceFactory * const factory : qAsConst(allDeviceFactories)) { if (factory->icon().isNull()) continue; - iconMenu.addAction(factory->icon(), tr("Default for %1").arg(factory->displayName()), - [this, factory] { - m_iconButton->setIcon(factory->icon()); - m_modifiedKit->setDeviceTypeForIcon(factory->deviceType()); - emit dirty(); - }); + QAction *action = iconMenu.addAction(factory->icon(), + tr("Default for %1").arg(factory->displayName()), + [this, factory] { + m_iconButton->setIcon(factory->icon()); + m_modifiedKit->setDeviceTypeForIcon( + factory->deviceType()); + emit dirty(); + }); + action->setIconVisibleInMenu(true); } iconMenu.addSeparator(); iconMenu.addAction(Utils::PathChooser::browseButtonLabel(), [this] { diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 8f79c23bee..9ec5253cf7 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -344,6 +344,12 @@ static BuildConfiguration *activeBuildConfiguration() return target ? target->activeBuildConfiguration() : nullptr; } +static RunConfiguration *activeRunConfiguration() +{ + const Target * const target = activeTarget(); + return target ? target->activeRunConfiguration() : nullptr; +} + static bool isTextFile(const QString &fileName) { return Utils::mimeTypeForFile(fileName).inherits( @@ -1881,6 +1887,39 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er return QString(); }); + expander->registerVariable("ActiveProject:RunConfig:Name", + tr("Name of the active project's active run configuration."), + []() -> QString { + if (const RunConfiguration * const rc = activeRunConfiguration()) + return rc->displayName(); + return QString(); + }); + expander->registerFileVariables("ActiveProject:RunConfig:Executable", + tr("The executable of the active project's active run configuration."), + []() -> QString { + if (const RunConfiguration * const rc = activeRunConfiguration()) + return rc->commandLine().executable().toString(); + return QString(); + }); + expander->registerPrefix("ActiveProject:RunConfig:Env", + tr("Variables in the environment of the active project's active run configuration."), + [](const QString &var) { + if (const RunConfiguration * const rc = activeRunConfiguration()) { + if (const auto envAspect = rc->aspect<EnvironmentAspect>()) + return envAspect->environment().expandedValueForKey(var); + } + return QString(); + }); + expander->registerVariable("ActiveProject:RunConfig:WorkingDir", + tr("The working directory of the active project's active run configuration."), + [] { + if (const RunConfiguration * const rc = activeRunConfiguration()) { + if (const auto wdAspect = rc->aspect<WorkingDirectoryAspect>()) + return wdAspect->workingDirectory(rc->macroExpander()).toString(); + } + return QString(); + }); + const auto fileHandler = [] { return SessionManager::sessionNameToFileName(SessionManager::activeSession()).toString(); }; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 4f245ad5a5..7ccb75abbe 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -188,6 +188,24 @@ RunConfiguration::RunConfiguration(Target *target, Utils::Id id) BuildConfiguration *bc = target->activeBuildConfiguration(); return bc ? bc->macroExpander() : target->macroExpander(); }); + m_expander.registerPrefix("RunConfig:Env", tr("Variables in the run environment"), + [this](const QString &var) { + const auto envAspect = aspect<EnvironmentAspect>(); + return envAspect ? envAspect->environment().expandedValueForKey(var) : QString(); + }); + m_expander.registerVariable("RunConfig:WorkingDir", + tr("The run configuration's working directory"), + [this] { + const auto wdAspect = aspect<WorkingDirectoryAspect>(); + return wdAspect ? wdAspect->workingDirectory(&m_expander).toString() : QString(); + }); + m_expander.registerVariable("RunConfig:Name", tr("The run configuration's name."), + [this] { return displayName(); }); + m_expander.registerFileVariables("RunConfig:Executable", + tr("The run configuration's executable."), + [this] { return commandLine().executable().toString(); }); + + m_commandLineGetter = [this] { FilePath executable; if (const auto executableAspect = aspect<ExecutableAspect>()) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 7f35f525ab..7c6e50b515 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -363,7 +363,7 @@ void RunControl::setRunConfiguration(RunConfiguration *runConfig) d->runConfiguration = runConfig; d->runConfigId = runConfig->id(); d->runnable = runConfig->runnable(); - d->displayName = runConfig->displayName(); + d->displayName = runConfig->expandedDisplayName(); d->macroExpander = runConfig->macroExpander(); d->buildKey = runConfig->buildKey(); d->settingsData = runConfig->aspectData(); diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index 967077ffd3..f2d79dec95 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -174,14 +174,14 @@ Target::Target(Project *project, Kit *k, _constructor_tag) : if (RunConfiguration * const rc = activeRunConfiguration()) return rc->displayName(); return QString(); - }); + }, false); d->m_macroExpander.registerFileVariables("CurrentRun:Executable", tr("The currently active run configuration's executable (if applicable)."), [this]() -> QString { if (RunConfiguration * const rc = activeRunConfiguration()) return rc->commandLine().executable().toString(); return QString(); - }); + }, false); d->m_macroExpander.registerPrefix("CurrentRun:Env", tr("Variables in the current run environment."), [this](const QString &var) { if (RunConfiguration * const rc = activeRunConfiguration()) { @@ -189,7 +189,7 @@ Target::Target(Project *project, Kit *k, _constructor_tag) : return envAspect->environment().expandedValueForKey(var); } return QString(); - }); + }, false); d->m_macroExpander.registerVariable("CurrentRun:WorkingDir", tr("The currently active run configuration's working directory."), [this] { @@ -198,7 +198,7 @@ Target::Target(Project *project, Kit *k, _constructor_tag) : return wdAspect->workingDirectory(&d->m_macroExpander).toString(); } return QString(); - }); + }, false); } Target::~Target() diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 6701ebbf84..26b147c0d3 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -78,7 +78,6 @@ class TaskView : public Utils::ListView { public: TaskView(QWidget *parent = nullptr); - void setCurrentAndScrollTo(const QModelIndex &index); ~TaskView() override; private: @@ -213,12 +212,6 @@ TaskView::TaskView(QWidget *parent) verticalScrollBar()->setSingleStep(vStepSize); } -void TaskView::setCurrentAndScrollTo(const QModelIndex &index) -{ - scrollTo(index); - setCurrentIndex(index); -} - TaskView::~TaskView() = default; void TaskView::resizeEvent(QResizeEvent *e) @@ -482,6 +475,7 @@ void TaskWindow::currentChanged(const QModelIndex &index) ITaskHandler *h = d->handler(action); action->setEnabled((task.isNull() || !h) ? false : h->canHandle(task)); } + d->m_listview->scrollTo(index); } void TaskWindow::saveSettings() @@ -563,7 +557,7 @@ void TaskWindow::showTask(unsigned int id) int sourceRow = d->m_model->rowForId(id); QModelIndex sourceIdx = d->m_model->index(sourceRow, 0); QModelIndex filterIdx = d->m_filter->mapFromSource(sourceIdx); - d->m_listview->setCurrentAndScrollTo(filterIdx); + d->m_listview->setCurrentIndex(filterIdx); popup(Core::IOutputPane::ModeSwitch); } @@ -692,7 +686,7 @@ void TaskWindow::setFocus() if (d->m_filter->rowCount()) { d->m_listview->setFocus(); if (d->m_listview->currentIndex() == QModelIndex()) - d->m_listview->setCurrentAndScrollTo(d->m_filter->index(0,0, QModelIndex())); + d->m_listview->setCurrentIndex(d->m_filter->index(0,0, QModelIndex())); } } @@ -725,7 +719,7 @@ void TaskWindow::goToNext() } else { currentIndex = d->m_filter->index(0, 0); } - d->m_listview->setCurrentAndScrollTo(currentIndex); + d->m_listview->setCurrentIndex(currentIndex); triggerDefaultHandler(currentIndex); } @@ -748,7 +742,7 @@ void TaskWindow::goToPrev() } else { currentIndex = d->m_filter->index(0, 0); } - d->m_listview->setCurrentAndScrollTo(currentIndex); + d->m_listview->setCurrentIndex(currentIndex); triggerDefaultHandler(currentIndex); } diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp index 8e289a344c..7dfee67c92 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp @@ -85,6 +85,7 @@ void CommentDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { + Q_UNUSED(index) editor->setGeometry(option.rect); } @@ -104,6 +105,9 @@ QWidget *CommentTitleDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { + Q_UNUSED(option) + Q_UNUSED(index) + auto *editor = new QComboBox(parent); editor->setEditable(true); editor->setCompleter(completer()); diff --git a/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp index 3623dceeb9..de3084bb01 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp @@ -139,9 +139,6 @@ QVariantMap DefaultAnnotationsModel::asVariantMapFromJson(const QJsonDocument &d case QJsonValue::Double: map[key] = double{0.0}; break; - case QJsonValue::String: - map[key] = QString{}; - break; case QJsonValue::Bool: map[key] = false; break; @@ -160,7 +157,13 @@ QVariantMap DefaultAnnotationsModel::asVariantMapFromJson(const QJsonDocument &d map[key] = QVariant::fromValue(val.toDouble()); else if (type == QStringLiteral("color")) map[key] = QVariant::fromValue(QColor(val.toString())); + break; } + case QJsonValue::String: + map[key] = QString{}; + break; + default: + break; } } diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp index 41d98ca608..c9d2de9e72 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp @@ -39,6 +39,8 @@ #include <qmldesignerconstants.h> #include <qmldesignerplugin.h> +#include <utils/qtcassert.h> + #include <QStandardItemModel> #include <QMessageBox> #include <QTableView> @@ -370,7 +372,10 @@ void ConnectionModel::abstractPropertyChanged(const AbstractProperty &abstractPr void ConnectionModel::deleteConnectionByRow(int currentRow) { SignalHandlerProperty targetSignal = signalHandlerPropertyForRow(currentRow); + QTC_ASSERT(targetSignal.isValid(), return ); QmlDesigner::ModelNode node = targetSignal.parentModelNode(); + QTC_ASSERT(node.isValid(), return ); + QList<SignalHandlerProperty> allSignals = node.signalProperties(); if (allSignals.size() > 1) { if (allSignals.contains(targetSignal)) diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp index 88dd6a971d..6737d66d18 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp @@ -102,7 +102,15 @@ void ConnectionView::nodeIdChanged(const ModelNode & /*node*/, const QString & / dynamicPropertiesModel()->resetModel(); } -void ConnectionView::propertiesAboutToBeRemoved(const QList<AbstractProperty> & propertyList) +void ConnectionView::propertiesRemoved(const QList<AbstractProperty> &propertyList) +{ + for (const AbstractProperty &property : propertyList) { + if (property.isDefaultProperty()) + connectionModel()->resetModel(); + } +} + +void ConnectionView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList) { foreach (const AbstractProperty &property, propertyList) { if (property.isBindingProperty()) { diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionview.h b/src/plugins/qmldesigner/components/connectioneditor/connectionview.h index dda496263d..fb934ba385 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionview.h +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionview.h @@ -62,6 +62,7 @@ public: void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override; + void propertiesRemoved(const QList<AbstractProperty> &propertyList) override; void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList) override; void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange) override; void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange) override; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp index ac9fbab89e..6fac0dd0c3 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp @@ -2046,7 +2046,7 @@ void FormEditorFlowDecisionItem::updateGeometry() QRectF textRect(0, 0, 100, 20); - Qt::Corner corner = Qt::TopRightCorner; + Qt::Corner corner = Qt::TopLeftCorner; if (qmlItemNode().modelNode().hasAuxiliaryData("dialogLabelPosition")) corner = qmlItemNode().modelNode().auxiliaryData("dialogLabelPosition").value<Qt::Corner>(); @@ -2191,7 +2191,7 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap QRectF textRect(0, 0, 100, 20); - Qt::Corner corner = Qt::TopRightCorner; + Qt::Corner corner = Qt::TopLeftCorner; if (qmlItemNode().modelNode().hasAuxiliaryData("dialogLabelPosition")) corner = qmlItemNode().modelNode().auxiliaryData("dialogLabelPosition").value<Qt::Corner>(); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 5341ff06d6..0ee760b9a1 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -129,19 +129,24 @@ void FormEditorView::setupFormEditorItemTree(const QmlItemNode &qmlItemNode) m_scene->synchronizeTransformation(rootItem); formEditorWidget()->setRootItemRect(qmlItemNode.instanceBoundingRect()); - for (const QmlObjectNode &nextNode : qmlItemNode.allDirectSubNodes()) { - if (QmlItemNode::isValidQmlItemNode(nextNode) && nextNode.toQmlItemNode().isFlowItem()) { - setupFormEditorItemTree(nextNode.toQmlItemNode()); + const QList<QmlObjectNode> allDirectSubNodes = qmlItemNode.allDirectSubNodes(); + for (const QmlObjectNode &childNode : allDirectSubNodes) { + if (QmlItemNode::isValidQmlItemNode(childNode) + && childNode.toQmlItemNode().isFlowItem()) { + setupFormEditorItemTree(childNode.toQmlItemNode()); } } - for (const QmlObjectNode &nextNode : qmlItemNode.allDirectSubNodes()) { - if (QmlVisualNode::isValidQmlVisualNode(nextNode) && nextNode.toQmlVisualNode().isFlowTransition()) { - setupFormEditorItemTree(nextNode.toQmlItemNode()); - } else if (QmlVisualNode::isValidQmlVisualNode(nextNode) && nextNode.toQmlVisualNode().isFlowDecision()) { - setupFormEditorItemTree(nextNode.toQmlItemNode()); - } else if (QmlVisualNode::isValidQmlVisualNode(nextNode) && nextNode.toQmlVisualNode().isFlowWildcard()) { - setupFormEditorItemTree(nextNode.toQmlItemNode()); + for (const QmlObjectNode &childNode : allDirectSubNodes) { + if (QmlVisualNode::isValidQmlVisualNode(childNode) + && childNode.toQmlVisualNode().isFlowTransition()) { + setupFormEditorItemTree(childNode.toQmlItemNode()); + } else if (QmlVisualNode::isValidQmlVisualNode(childNode) + && childNode.toQmlVisualNode().isFlowDecision()) { + setupFormEditorItemTree(childNode.toQmlItemNode()); + } else if (QmlVisualNode::isValidQmlVisualNode(childNode) + && childNode.toQmlVisualNode().isFlowWildcard()) { + setupFormEditorItemTree(childNode.toQmlItemNode()); } } } else { @@ -632,8 +637,21 @@ void FormEditorView::auxiliaryDataChanged(const ModelNode &node, const PropertyN } } +static void updateTransitions(FormEditorScene *scene, const QmlItemNode &qmlItemNode) +{ + QmlFlowTargetNode flowItem(qmlItemNode); + if (flowItem.isValid() && flowItem.flowView().isValid()) { + const auto nodes = flowItem.flowView().transitions(); + for (const ModelNode &node : nodes) { + if (FormEditorItem *item = scene->itemForQmlItemNode(node)) + item->updateGeometry(); + } + }; +} + void FormEditorView::instancesCompleted(const QVector<ModelNode> &completedNodeList) { + const bool isFlow = rootModelNode().isValid() && QmlItemNode(rootModelNode()).isFlowView(); QList<FormEditorItem*> itemNodeList; for (const ModelNode &node : completedNodeList) { const QmlItemNode qmlItemNode(node); @@ -641,6 +659,8 @@ void FormEditorView::instancesCompleted(const QVector<ModelNode> &completedNodeL if (FormEditorItem *item = scene()->itemForQmlItemNode(qmlItemNode)) { scene()->synchronizeParent(qmlItemNode); itemNodeList.append(item); + if (isFlow && qmlItemNode.isFlowItem()) + updateTransitions(scene(), qmlItemNode); } } } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp index 3176d1ebb7..a9a772c953 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp @@ -75,14 +75,18 @@ QVariant ItemLibraryCategoriesModel::data(const QModelIndex &index, int role) co bool ItemLibraryCategoriesModel::setData(const QModelIndex &index, const QVariant &value, int role) { - // currently only categoryExpanded property is updatable + // currently only categoryExpanded and categoryVisible properties is updatable if (index.isValid() && m_roleNames.contains(role)) { QVariant currValue = m_categoryList.at(index.row())->property(m_roleNames.value(role)); + if (currValue != value) { m_categoryList[index.row()]->setProperty(m_roleNames.value(role), value); if (m_roleNames.value(role) == "categoryExpanded") { ItemLibraryModel::saveExpandedState(value.toBool(), m_categoryList[index.row()]->categoryName()); + } else if (m_roleNames.value(role) == "categoryVisible") { + ItemLibraryModel::saveCategoryVisibleState(value.toBool(), + m_categoryList[index.row()]->categoryName()); } emit dataChanged(index, index, {role}); return true; @@ -139,6 +143,17 @@ void ItemLibraryCategoriesModel::resetModel() endResetModel(); } +void ItemLibraryCategoriesModel::showAllCategories(bool show) +{ + for (const auto &category : std::as_const(m_categoryList)) { + if (category->isCategoryVisible() != show) { + category->setCategoryVisible(show); + ItemLibraryModel::saveCategoryVisibleState(show, category->categoryName()); + } + } + emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categoryVisible")}); +} + void ItemLibraryCategoriesModel::addRoleNames() { int role = 0; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h index 982083569d..276d47ac48 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h @@ -54,6 +54,7 @@ public: void sortCategorySections(); void resetModel(); + void showAllCategories(bool show = true); private: void addRoleNames(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp index f55fd30921..5f46d1e1ce 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp @@ -87,6 +87,14 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool * return hasVisibleItems; } +void ItemLibraryCategory::setCategoryVisible(bool isVisible) +{ + if (isVisible != m_isVisible) { + m_isVisible = isVisible; + emit categoryVisibilityChanged(); + } +} + bool ItemLibraryCategory::setVisible(bool isVisible) { if (isVisible != m_isVisible) { @@ -97,7 +105,7 @@ bool ItemLibraryCategory::setVisible(bool isVisible) return false; } -bool ItemLibraryCategory::isVisible() const +bool ItemLibraryCategory::isCategoryVisible() const { return m_isVisible; } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h index ad3f1579a0..1018402019 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h @@ -36,7 +36,7 @@ class ItemLibraryCategory : public QObject Q_OBJECT Q_PROPERTY(QString categoryName READ categoryName FINAL) - Q_PROPERTY(bool categoryVisible READ isVisible NOTIFY visibilityChanged FINAL) + Q_PROPERTY(bool categoryVisible READ isCategoryVisible WRITE setCategoryVisible NOTIFY categoryVisibilityChanged FINAL) Q_PROPERTY(bool categoryExpanded READ categoryExpanded WRITE setExpanded NOTIFY expandedChanged FINAL) Q_PROPERTY(QObject *itemModel READ itemModel NOTIFY itemModelChanged FINAL) @@ -52,8 +52,9 @@ public: bool updateItemVisibility(const QString &searchText, bool *changed); + void setCategoryVisible(bool isVisible); bool setVisible(bool isVisible); - bool isVisible() const; + bool isCategoryVisible() const; void sortItems(); @@ -63,6 +64,7 @@ signals: void itemModelChanged(); void visibilityChanged(); void expandedChanged(); + void categoryVisibilityChanged(); private: ItemLibraryItemsModel m_itemModel; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp index 79acb29d58..40892db07b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp @@ -116,19 +116,28 @@ bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool *changed = false; for (const auto &category : m_categoryModel.categorySections()) { - bool categoryChanged = false; - bool hasVisibleItems = category->updateItemVisibility(searchText, &categoryChanged); - categoryChanged |= category->setVisible(hasVisibleItems); + category->setCategoryVisible(ItemLibraryModel::loadCategoryVisibleState(category->categoryName())); - *changed |= categoryChanged; + if (!searchText.isEmpty() || category->isCategoryVisible()) { + bool categoryChanged = false; + bool hasVisibleItems = category->updateItemVisibility(searchText, &categoryChanged); + categoryChanged |= category->setVisible(hasVisibleItems); - if (hasVisibleItems) - hasVisibleCategories = true; + *changed |= categoryChanged; + + if (hasVisibleItems) + hasVisibleCategories = true; + } } return hasVisibleCategories; } +void ItemLibraryImport::showAllCategories(bool show) +{ + m_categoryModel.showAllCategories(show); +} + Import ItemLibraryImport::importEntry() const { return m_import; @@ -235,4 +244,22 @@ void ItemLibraryImport::updateRemovable() } } +// returns true if all categories are visible, otherwise false +bool ItemLibraryImport::importCatVisibleState() const +{ + if (m_categoryModel.rowCount() > 0) { + for (ItemLibraryCategory *cat : m_categoryModel.categorySections()) { + if (!cat->isCategoryVisible()) + return false; + } + } + + return true; +} + +void ItemLibraryImport::setImportCatVisibleState(bool show) +{ + m_categoryModel.showAllCategories(show); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h index 3b860e488b..81717439f9 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h @@ -43,6 +43,7 @@ class ItemLibraryImport : public QObject Q_PROPERTY(bool importExpanded READ importExpanded WRITE setImportExpanded NOTIFY importExpandChanged FINAL) Q_PROPERTY(bool importRemovable READ importRemovable NOTIFY importRemovableChanged FINAL) Q_PROPERTY(bool importUnimported READ importUnimported FINAL) + Q_PROPERTY(bool importCatVisibleState READ importCatVisibleState WRITE setImportCatVisibleState NOTIFY importCatVisibleStateChanged FINAL) Q_PROPERTY(QObject *categoryModel READ categoryModel NOTIFY categoryModelChanged FINAL) public: @@ -64,6 +65,7 @@ public: bool importVisible() const; bool importUsed() const; bool importRemovable() const; + bool importCatVisibleState() const; bool hasCategories() const; bool hasSingleCategory() const; ItemLibraryCategory *getCategorySection(const QString &categoryName) const; @@ -75,7 +77,9 @@ public: void setImportUsed(bool importUsed); void sortCategorySections(); void setImportExpanded(bool expanded = true); + void setImportCatVisibleState(bool show); void expandCategories(bool expand = true); + void showAllCategories(bool show = true); static QString userComponentsTitle(); static QString quick3DAssetsTitle(); @@ -89,6 +93,7 @@ signals: void importUsedChanged(); void importExpandChanged(); void importRemovableChanged(); + void importCatVisibleStateChanged(); private: void updateRemovable(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 91a930b783..ae7fc0bc49 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -59,6 +59,49 @@ bool ItemLibraryModel::loadExpandedState(const QString §ionName) return expandedStateHash.value(sectionName, true); } +void ItemLibraryModel::saveCategoryVisibleState(bool isVisible, const QString &categoryName) +{ + categoryVisibleStateHash.insert(categoryName, isVisible); +} + +bool ItemLibraryModel::loadCategoryVisibleState(const QString &categoryName) +{ + return categoryVisibleStateHash.value(categoryName, true); +} + +void ItemLibraryModel::showHiddenCategories() +{ + for (const QPointer<ItemLibraryImport> &import : std::as_const(m_importList)) { + if (import->hasCategories()) + import->showAllCategories(true); + } + + categoryVisibleStateHash.clear(); +} + +bool ItemLibraryModel::getIsAnyCategoryHidden() const +{ + for (const bool &catState : std::as_const(categoryVisibleStateHash)) { + if (!catState) + return true; + } + + return false; +} + +bool ItemLibraryModel::isAnyCategoryHidden() const +{ + return m_isAnyCategoryHidden; +} + +void ItemLibraryModel::setIsAnyCategoryHidden(bool state) +{ + if (state != m_isAnyCategoryHidden) { + m_isAnyCategoryHidden = state; + emit isAnyCategoryHiddenChanged(); + } +} + void ItemLibraryModel::expandAll() { int i = 0; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h index 2412550a3a..1bb9447bd7 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h @@ -41,6 +41,7 @@ class ItemLibraryImport; class ItemLibraryModel : public QAbstractListModel { Q_OBJECT + Q_PROPERTY(bool isAnyCategoryHidden READ isAnyCategoryHidden WRITE setIsAnyCategoryHidden NOTIFY isAnyCategoryHiddenChanged FINAL) public: explicit ItemLibraryModel(QObject *parent = nullptr); @@ -62,15 +63,25 @@ public: void setSearchText(const QString &searchText); void setFlowMode(bool); + bool isAnyCategoryHidden() const; + void setIsAnyCategoryHidden(bool state); + static void registerQmlTypes(); static void saveExpandedState(bool expanded, const QString §ionName); static bool loadExpandedState(const QString §ionName); + static void saveCategoryVisibleState(bool isVisible, const QString &categoryName); + static bool loadCategoryVisibleState(const QString &categoryName); Q_INVOKABLE void expandAll(); Q_INVOKABLE void collapseAll(); + Q_INVOKABLE void showHiddenCategories(); + Q_INVOKABLE bool getIsAnyCategoryHidden() const; Import entryToImport(const ItemLibraryEntry &entry); +signals: + void isAnyCategoryHiddenChanged(); + private: void updateVisibility(bool *changed); void addRoleNames(); @@ -82,8 +93,10 @@ private: QString m_searchText; bool m_flowMode = false; + bool m_isAnyCategoryHidden = false; inline static QHash<QString, bool> expandedStateHash; + inline static QHash<QString, bool> categoryVisibleStateHash; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp b/src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp index f755e4863e..fd17b10d9a 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp @@ -126,8 +126,6 @@ QIcon paintPreview(const QColor& background) QIcon paintPreview(const EasingCurve &curve, const QColor& background, const QColor& curveColor) { - const QColor curveLine = Theme::getColor(Theme::DStextColor); - QPixmap pm(iconWidth, iconHeight); pm.fill(background); diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp index a62fe1fd8c..a981537a4f 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp @@ -328,8 +328,11 @@ void TransitionEditorWidget::init() if (root.isValid() && root.hasProperty("transitions")) { NodeAbstractProperty transitions = root.nodeAbstractProperty("transitions"); - if (transitions.isValid()) - transition = transitions.directSubNodes().constFirst(); + if (transitions.isValid()) { + const QList<ModelNode> directSubNodes = transitions.directSubNodes(); + if (!directSubNodes.isEmpty()) + transition = directSubNodes.constFirst(); + } } m_graphicsScene->setTransition(transition); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 432667c63a..a751bf5b1f 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -104,16 +104,26 @@ QStringList globalQtEnums() QStringList knownEnumScopes() { - static const QStringList list = { - "TextInput", "TextEdit", "Material", "Universal", "Font", "Shape", "ShapePath", - "AbstractButton", "Text", "ShaderEffectSource", "Grid" - }; + static const QStringList list = {"TextInput", + "TextEdit", + "Material", + "Universal", + "Font", + "Shape", + "ShapePath", + "AbstractButton", + "Text", + "ShaderEffectSource", + "Grid", + "ItemLayer", + "ImageLayer", + "SpriteLayer"}; return list; } bool supportedQtQuickVersion(const QString &version) { - return supportedVersionsList().contains(version); + return version.isEmpty() || supportedVersionsList().contains(version); } QString stripQuotes(const QString &str) @@ -787,11 +797,8 @@ void TextToModelMerger::setupImports(const Document::Ptr &doc, differenceHandler.modelMissesImport(newImport); } else { QString importUri = toString(import->importUri); - if (importUri == QStringLiteral("Qt") && version == QStringLiteral("4.7")) { - importUri = QStringLiteral("QtQuick"); - version = QStringLiteral("1.0"); - } - + if (version.isEmpty()) + version = "2.15"; const Import newImport = Import::createLibraryImport(importUri, version, as, m_rewriterView->importDirectories()); @@ -946,9 +953,13 @@ void TextToModelMerger::setupUsedImports() } for (const QmlJS::Import &import : allImports) { + QString version = import.info.version().toString(); + if (version.isEmpty()) + version = "2.15"; if (!import.info.name().isEmpty() && usedImportsSet.contains(import.info.name())) { if (import.info.type() == ImportType::Library) - usedImports.append(Import::createLibraryImport(import.info.name(), import.info.version().toString(), import.info.as())); + usedImports.append( + Import::createLibraryImport(import.info.name(), version, import.info.as())); else if (import.info.type() == ImportType::Directory || import.info.type() == ImportType::File) usedImports.append(Import::createFileImport(import.info.name(), import.info.version().toString(), import.info.as())); } diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 7b3fd99d11..c2d37968b2 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1040,11 +1040,16 @@ QString BaseQtVersionPrivate::findHostBinary(HostBinaries binary) const switch (binary) { case Designer: case Linguist: - case Rcc: - case Uic: case QScxmlc: baseDir = q->hostBinPath().toString(); break; + case Rcc: + case Uic: + if (q->qtVersion() >= QtVersionNumber(6, 1)) + baseDir = q->hostLibexecPath().toString(); + else + baseDir = q->hostBinPath().toString(); + break; default: // Can't happen Q_ASSERT(false); diff --git a/src/plugins/studiowelcome/qml/splashscreen/Welcome_splash.qml b/src/plugins/studiowelcome/qml/splashscreen/Welcome_splash.qml index 240788a37a..416693f5b8 100644 --- a/src/plugins/studiowelcome/qml/splashscreen/Welcome_splash.qml +++ b/src/plugins/studiowelcome/qml/splashscreen/Welcome_splash.qml @@ -305,6 +305,6 @@ Image { scale: 0.5 checked: usageStatisticModel.usageStatisticEnabled - onCheckedChanged: usageStatisticModel.setPluginEnabled(usageStatisticCheckBox.checked) + onCheckedChanged: usageStatisticModel.setTelemetryEnabled(usageStatisticCheckBox.checked) } } diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 35889ce522..0129b0e226 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -49,36 +49,55 @@ #include <QAbstractListModel> #include <QApplication> #include <QDesktopServices> -#include <QFontDatabase> #include <QFileInfo> +#include <QFontDatabase> #include <QPointer> #include <QQmlContext> #include <QQmlEngine> #include <QQuickItem> #include <QQuickView> #include <QQuickWidget> +#include <QSettings> #include <QTimer> +#include <algorithm> +#include <memory> + namespace StudioWelcome { namespace Internal { const char DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY[] = "StudioSplashScreen"; +const char DETAILED_USAGE_STATISTICS[] = "DetailedUsageStatistics"; +const char STATISTICS_COLLECTION_MODE[] = "StatisticsCollectionMode"; +const char NO_TELEMETRY[] = "NoTelemetry"; + QPointer<QQuickWidget> s_view = nullptr; static StudioWelcomePlugin *s_pluginInstance = nullptr; -static bool isUsageStatistic(const ExtensionSystem::PluginSpec *spec) +std::unique_ptr<QSettings> makeUserFeedbackSettings() { - if (!spec) - return false; - - return spec->name().contains("UsageStatistic"); -} + QStringList domain = QCoreApplication::organizationDomain().split(QLatin1Char('.')); + std::reverse(domain.begin(), domain.end()); + QString productId = domain.join(QLatin1String(".")); + if (!productId.isEmpty()) + productId += "."; + productId += QCoreApplication::applicationName(); + + QString organization; + if (Utils::HostOsInfo::isMacHost()) { + organization = QCoreApplication::organizationDomain().isEmpty() + ? QCoreApplication::organizationName() + : QCoreApplication::organizationDomain(); + } else { + organization = QCoreApplication::organizationName().isEmpty() + ? QCoreApplication::organizationDomain() + : QCoreApplication::organizationName(); + } -ExtensionSystem::PluginSpec *getUsageStatisticPlugin() -{ - const auto plugins = ExtensionSystem::PluginManager::plugins(); - return Utils::findOrDefault(plugins, &isUsageStatistic); + std::unique_ptr<QSettings> settings(new QSettings(organization, "UserFeedback." + productId)); + settings->beginGroup("UserFeedback"); + return settings; } class UsageStatisticPluginModel : public QObject @@ -95,27 +114,21 @@ public: void setupModel() { - auto plugin = getUsageStatisticPlugin(); - if (plugin) - m_usageStatisticEnabled = plugin->isEnabledBySettings(); - else - m_usageStatisticEnabled = false; + auto settings = makeUserFeedbackSettings(); + QVariant value = settings->value(STATISTICS_COLLECTION_MODE); + m_usageStatisticEnabled = value.isValid() && value.toString() == DETAILED_USAGE_STATISTICS; emit usageStatisticChanged(); } - Q_INVOKABLE void setPluginEnabled(bool b) + Q_INVOKABLE void setTelemetryEnabled(bool b) { - auto plugin = getUsageStatisticPlugin(); - - if (!plugin) + if (m_usageStatisticEnabled == b) return; - if (plugin->isEnabledBySettings() == b) - return; + auto settings = makeUserFeedbackSettings(); - plugin->setEnabledBySettings(b); - ExtensionSystem::PluginManager::writeSettings(); + settings->setValue(STATISTICS_COLLECTION_MODE, b ? DETAILED_USAGE_STATISTICS : NO_TELEMETRY); // pause remove splash timer while dialog is open otherwise splash crashes upon removal s_pluginInstance->pauseRemoveSplashTimer(); @@ -139,9 +152,9 @@ class ProjectModel : public QAbstractListModel { Q_OBJECT public: - enum { FilePathRole = Qt::UserRole+1, PrettyFilePathRole }; + enum { FilePathRole = Qt::UserRole + 1, PrettyFilePathRole }; - Q_PROPERTY(bool communityVersion MEMBER m_communityVersion NOTIFY communityVersionChanged) + Q_PROPERTY(bool communityVersion MEMBER m_communityVersion NOTIFY communityVersionChanged) explicit ProjectModel(QObject *parent = nullptr); @@ -161,16 +174,12 @@ public: Q_INVOKABLE void openProjectAt(int row) { - const QString projectFile = data(index(row, 0), - ProjectModel::FilePathRole).toString(); + const QString projectFile = data(index(row, 0), ProjectModel::FilePathRole).toString(); if (QFileInfo::exists(projectFile)) ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); } - Q_INVOKABLE int get(int) - { - return -1; - } + Q_INVOKABLE int get(int) { return -1; } Q_INVOKABLE void showHelp() { @@ -200,8 +209,11 @@ public: const QString projectFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + example + ".qmlproject"; + ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); - const QString qmlFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + formFile; + const QString qmlFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + + formFile; + Core::EditorManager::openEditor(qmlFile); } public slots: @@ -222,9 +234,9 @@ ProjectModel::ProjectModel(QObject *parent) this, &ProjectModel::resetProjects); - if (!Utils::findOrDefault(ExtensionSystem::PluginManager::plugins(), - Utils::equal(&ExtensionSystem::PluginSpec::name, QString("LicenseChecker")))) + Utils::equal(&ExtensionSystem::PluginSpec::name, + QString("LicenseChecker")))) m_communityVersion = true; } @@ -235,8 +247,8 @@ int ProjectModel::rowCount(const QModelIndex &) const QVariant ProjectModel::data(const QModelIndex &index, int role) const { - QPair<QString,QString> data = - ProjectExplorer::ProjectExplorerPlugin::recentProjects().at(index.row()); + QPair<QString, QString> data = ProjectExplorer::ProjectExplorerPlugin::recentProjects().at( + index.row()); switch (role) { case Qt::DisplayRole: return data.second; @@ -275,7 +287,6 @@ public: ~WelcomeMode() override; private: - QQuickWidget *m_modeWidget = nullptr; }; @@ -344,22 +355,25 @@ void StudioWelcomePlugin::extensionsInitialized() s_view->setWindowFlag(Qt::SplashScreen, true); s_view->setWindowModality(Qt::ApplicationModal); s_view->engine()->addImportPath("qrc:/studiofonts"); - #ifdef QT_DEBUG - s_view->engine()->addImportPath(QLatin1String(STUDIO_QML_PATH) - + "splashscreen/imports"); - s_view->setSource(QUrl::fromLocalFile(QLatin1String(STUDIO_QML_PATH) - + "splashscreen/main.qml")); - #else +#ifdef QT_DEBUG + s_view->engine()->addImportPath(QLatin1String(STUDIO_QML_PATH) + "splashscreen/imports"); + s_view->setSource( + QUrl::fromLocalFile(QLatin1String(STUDIO_QML_PATH) + "splashscreen/main.qml")); +#else s_view->engine()->addImportPath("qrc:/qml/splashscreen/imports"); s_view->setSource(QUrl("qrc:/qml/splashscreen/main.qml")); - #endif +#endif QTC_ASSERT(s_view->rootObject(), - qWarning() << "The StudioWelcomePlugin has a runtime depdendency on qt/qtquicktimeline."; - return); + qWarning() << "The StudioWelcomePlugin has a runtime depdendency on " + "qt/qtquicktimeline."; + return ); connect(s_view->rootObject(), SIGNAL(closeClicked()), this, SLOT(closeSplashScreen())); - connect(s_view->rootObject(), SIGNAL(configureClicked()), this, SLOT(showSystemSettings())); + connect(s_view->rootObject(), + SIGNAL(configureClicked()), + this, + SLOT(showSystemSettings())); s_view->show(); s_view->raise(); @@ -374,7 +388,7 @@ bool StudioWelcomePlugin::delayedInitialize() if (s_view.isNull()) return false; - QTC_ASSERT(s_view->rootObject() , return true); + QTC_ASSERT(s_view->rootObject(), return true); #ifdef ENABLE_CRASHPAD const bool crashReportingEnabled = true; diff --git a/src/plugins/texteditor/codeassist/genericproposalmodel.cpp b/src/plugins/texteditor/codeassist/genericproposalmodel.cpp index 8e891283ab..7236f90beb 100644 --- a/src/plugins/texteditor/codeassist/genericproposalmodel.cpp +++ b/src/plugins/texteditor/codeassist/genericproposalmodel.cpp @@ -30,6 +30,7 @@ #include <texteditor/completionsettings.h> #include <QDebug> +#include <QElapsedTimer> #include <QRegularExpression> #include <QtAlgorithms> #include <QHash> @@ -297,28 +298,46 @@ void GenericProposalModel::filter(const QString &prefix) convertCaseSensitivity(TextEditorSettings::completionSettings().m_caseSensitivity); const QRegularExpression regExp = FuzzyMatcher::createRegExp(prefix, caseSensitivity); + QElapsedTimer timer; + timer.start(); + m_currentItems.clear(); const QString lowerPrefix = prefix.toLower(); + const bool checkInfix = prefix.size() >= 3; for (const auto &item : qAsConst(m_originalItems)) { const QString &text = item->text(); - const QRegularExpressionMatch match = regExp.match(text); - const bool hasPrefixMatch = match.capturedStart() == 0; - const bool hasInfixMatch = prefix.size() >= 3 && match.hasMatch(); - if (hasPrefixMatch || hasInfixMatch) { + + // Direct match? + if (text.startsWith(prefix)) { m_currentItems.append(item); - if (text.startsWith(prefix)) { - // Direct match - item->setProposalMatch(text.length() == prefix.length() - ? AssistProposalItemInterface::ProposalMatch::Full - : AssistProposalItemInterface::ProposalMatch::Exact); - continue; - } + item->setProposalMatch(text.length() == prefix.length() + ? AssistProposalItemInterface::ProposalMatch::Full + : AssistProposalItemInterface::ProposalMatch::Exact); + continue; + } + + if (text.startsWith(lowerPrefix, Qt::CaseInsensitive)) { + m_currentItems.append(item); + item->setProposalMatch(AssistProposalItemInterface::ProposalMatch::Prefix); + continue; + } - if (text.startsWith(lowerPrefix, Qt::CaseInsensitive)) - item->setProposalMatch(AssistProposalItemInterface::ProposalMatch::Prefix); - else if (text.contains(lowerPrefix, Qt::CaseInsensitive)) - item->setProposalMatch(AssistProposalItemInterface::ProposalMatch::Infix); + if (checkInfix && text.contains(lowerPrefix, Qt::CaseInsensitive)) { + m_currentItems.append(item); + item->setProposalMatch(AssistProposalItemInterface::ProposalMatch::Infix); + continue; } + + // Our fuzzy matcher can become unusably slow with certain inputs, so skip it + // if we'd become unresponsive. See QTCREATORBUG-25419. + if (timer.elapsed() > 100) + continue; + + const QRegularExpressionMatch match = regExp.match(text); + const bool hasPrefixMatch = match.capturedStart() == 0; + const bool hasInfixMatch = checkInfix && match.hasMatch(); + if (hasPrefixMatch || hasInfixMatch) + m_currentItems.append(item); } } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 244d1b6275..912ad8e260 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -1999,7 +1999,7 @@ void TextEditorWidgetPrivate::moveLineUpDown(bool up) move.setPosition(cursor.selectionStart()); move.movePosition(QTextCursor::StartOfBlock); move.setPosition(cursor.selectionEnd(), QTextCursor::KeepAnchor); - move.movePosition(move.atBlockStart() ? QTextCursor::Left: QTextCursor::EndOfBlock, + move.movePosition(move.atBlockStart() ? QTextCursor::PreviousCharacter: QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); } else { move.movePosition(QTextCursor::StartOfBlock); @@ -2024,19 +2024,19 @@ void TextEditorWidgetPrivate::moveLineUpDown(bool up) } } - move.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + move.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); move.removeSelectedText(); if (up) { move.movePosition(QTextCursor::PreviousBlock); move.insertBlock(); - move.movePosition(QTextCursor::Left); + move.movePosition(QTextCursor::PreviousCharacter); } else { move.movePosition(QTextCursor::EndOfBlock); if (move.atBlockStart()) { // empty block move.movePosition(QTextCursor::NextBlock); move.insertBlock(); - move.movePosition(QTextCursor::Left); + move.movePosition(QTextCursor::PreviousCharacter); } else { move.insertBlock(); } |