forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.15'
Change-Id: I0afcf51d354ffd73a8f2956a7f78b1e4f032677b
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
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 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);
|
||||
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;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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] {
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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>())
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
|
||||
void sortCategorySections();
|
||||
void resetModel();
|
||||
void showAllCategories(bool show = true);
|
||||
|
||||
private:
|
||||
void addRoleNames();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -305,6 +305,6 @@ Image {
|
||||
scale: 0.5
|
||||
checked: usageStatisticModel.usageStatisticEnabled
|
||||
|
||||
onCheckedChanged: usageStatisticModel.setPluginEnabled(usageStatisticCheckBox.checked)
|
||||
onCheckedChanged: usageStatisticModel.setTelemetryEnabled(usageStatisticCheckBox.checked)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
QStringList domain = QCoreApplication::organizationDomain().split(QLatin1Char('.'));
|
||||
std::reverse(domain.begin(), domain.end());
|
||||
QString productId = domain.join(QLatin1String("."));
|
||||
if (!productId.isEmpty())
|
||||
productId += ".";
|
||||
productId += QCoreApplication::applicationName();
|
||||
|
||||
return spec->name().contains("UsageStatistic");
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
// Direct match?
|
||||
if (text.startsWith(prefix)) {
|
||||
m_currentItems.append(item);
|
||||
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 (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 = prefix.size() >= 3 && match.hasMatch();
|
||||
if (hasPrefixMatch || hasInfixMatch) {
|
||||
const bool hasInfixMatch = checkInfix && match.hasMatch();
|
||||
if (hasPrefixMatch || hasInfixMatch)
|
||||
m_currentItems.append(item);
|
||||
if (text.startsWith(prefix)) {
|
||||
// Direct match
|
||||
item->setProposalMatch(text.length() == prefix.length()
|
||||
? AssistProposalItemInterface::ProposalMatch::Full
|
||||
: AssistProposalItemInterface::ProposalMatch::Exact);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (text.startsWith(lowerPrefix, Qt::CaseInsensitive))
|
||||
item->setProposalMatch(AssistProposalItemInterface::ProposalMatch::Prefix);
|
||||
else if (text.contains(lowerPrefix, Qt::CaseInsensitive))
|
||||
item->setProposalMatch(AssistProposalItemInterface::ProposalMatch::Infix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user