Merge remote-tracking branch 'origin/4.14' into master

Conflicts:
	src/plugins/cppeditor/cppquickfix_test.cpp

Change-Id: Ib2984a3b3d9d071d11304b6cf132c2f8cef77e1c
This commit is contained in:
Eike Ziller
2020-10-19 15:22:37 +02:00
247 changed files with 6131 additions and 705 deletions

View File

@@ -324,7 +324,7 @@ QWidget *AndroidBuildApkWidget::createAdvancedGroup()
auto vbox = new QVBoxLayout(group);
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(m_step->kit());
if (version && version->supportsMultipleQtAbis()) {
auto buildAAB = new QCheckBox(tr("Build .aab (Android App Bundle)"), group);
auto buildAAB = new QCheckBox(tr("Build Android App Bundle (*.aab)"), group);
buildAAB->setChecked(m_step->buildAAB());
connect(buildAAB, &QAbstractButton::toggled, m_step, &AndroidBuildApkStep::setBuildAAB);
vbox->addWidget(buildAAB);

View File

@@ -51,6 +51,7 @@
#include <qtsupport/qtkitinformation.h>
#include <utils/algorithm.h>
#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
@@ -86,8 +87,18 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Utils::Id id)
: BuildStep(parent, id)
{
setImmutable(true);
m_uninstallPreviousPackage = addAspect<BoolAspect>();
m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey);
m_uninstallPreviousPackage->setLabel(tr("Uninstall the existing app first"));
m_uninstallPreviousPackage->setValue(false);
const QtSupport::BaseQtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit());
m_uninstallPreviousPackage = qt && qt->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0);
const bool forced = qt && qt->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0);
if (forced) {
m_uninstallPreviousPackage->setValue(true);
m_uninstallPreviousPackage->setEnabled(false);
}
connect(this, &AndroidDeployQtStep::askForUninstall,
this, &AndroidDeployQtStep::slotAskForUninstall,
@@ -167,7 +178,7 @@ bool AndroidDeployQtStep::init()
emit addOutput(tr("Deploying to %1").arg(m_serialNumber), OutputFormat::Stdout);
m_uninstallPreviousPackageRun = m_uninstallPreviousPackage;
m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value();
if (m_uninstallPreviousPackageRun)
m_manifestName = AndroidManager::manifestPath(target());
@@ -480,14 +491,6 @@ QWidget *AndroidDeployQtStep::createConfigWidget()
setDisplayName(QString("<b>%1</b>").arg(displayName()));
setSummaryText(displayName());
auto uninstallPreviousCheckBox = new QCheckBox(widget);
uninstallPreviousCheckBox->setText(tr("Uninstall the existing app first"));
uninstallPreviousCheckBox->setChecked(uninstallPreviousPackage() > Keep);
uninstallPreviousCheckBox->setEnabled(uninstallPreviousPackage() != ForceUninstall);
connect(uninstallPreviousCheckBox, &QAbstractButton::toggled,
this, &AndroidDeployQtStep::setUninstallPreviousPackage);
auto resetDefaultDevices = new QPushButton(widget);
resetDefaultDevices->setText(tr("Reset Default Deployment Devices"));
@@ -508,10 +511,10 @@ QWidget *AndroidDeployQtStep::createConfigWidget()
AndroidManager::installQASIPackage(target(), packagePath);
});
auto layout = new QVBoxLayout(widget);
layout->addWidget(uninstallPreviousCheckBox);
layout->addWidget(resetDefaultDevices);
layout->addWidget(installCustomApkButton);
LayoutBuilder builder(widget);
builder.addRow(m_uninstallPreviousPackage);
builder.addRow(resetDefaultDevices);
builder.addRow(installCustomApkButton);
return widget;
}
@@ -569,32 +572,6 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::parseDeployErrors(QStr
return errorCode;
}
bool AndroidDeployQtStep::fromMap(const QVariantMap &map)
{
m_uninstallPreviousPackage = map.value(UninstallPreviousPackageKey, m_uninstallPreviousPackage).toBool();
return ProjectExplorer::BuildStep::fromMap(map);
}
QVariantMap AndroidDeployQtStep::toMap() const
{
QVariantMap map = ProjectExplorer::BuildStep::toMap();
map.insert(UninstallPreviousPackageKey, m_uninstallPreviousPackage);
return map;
}
void AndroidDeployQtStep::setUninstallPreviousPackage(bool uninstall)
{
m_uninstallPreviousPackage = uninstall;
}
AndroidDeployQtStep::UninstallType AndroidDeployQtStep::uninstallPreviousPackage()
{
const QtSupport::BaseQtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit());
if (qt && qt->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0))
return ForceUninstall;
return m_uninstallPreviousPackage ? Uninstall : Keep;
}
// AndroidDeployQtStepFactory
AndroidDeployQtStepFactory::AndroidDeployQtStepFactory()

View File

@@ -59,20 +59,8 @@ class AndroidDeployQtStep : public ProjectExplorer::BuildStep
};
public:
enum UninstallType {
Keep,
Uninstall,
ForceUninstall
};
AndroidDeployQtStep(ProjectExplorer::BuildStepList *bc, Utils::Id id);
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
UninstallType uninstallPreviousPackage();
void setUninstallPreviousPackage(bool uninstall);
signals:
void askForUninstall(DeployErrorCode errorCode);
@@ -105,7 +93,7 @@ private:
QMap<QString, QString> m_filesToPull;
QStringList m_androidABIs;
bool m_uninstallPreviousPackage = false;
Utils::BoolAspect *m_uninstallPreviousPackage = nullptr;
bool m_uninstallPreviousPackageRun = false;
bool m_useAndroiddeployqt = false;
bool m_askForUninstall = false;

View File

@@ -86,7 +86,8 @@ QString AndroidQtVersion::invalidReason() const
bool AndroidQtVersion::supportsMultipleQtAbis() const
{
return qtVersion() >= QtSupport::QtVersionNumber{5, 14};
return qtVersion() >= QtSupport::QtVersionNumber{5, 14}
&& qtVersion() < QtSupport::QtVersionNumber{6, 0};
}
Abis AndroidQtVersion::detectQtAbis() const

View File

@@ -10,9 +10,6 @@
<height>284</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">

View File

@@ -185,8 +185,11 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
qCDebug(LOG) << " LocalExecutable" << localExecutable;
qCDebug(LOG) << " DeployedExecutable" << deployedExecutable;
qCDebug(LOG) << "Iterating run configurations";
for (RunConfiguration *runConfig : target->runConfigurations()) {
qCDebug(LOG) << "Iterating run configurations - prefer active over others";
QList<RunConfiguration *> runConfigurations = target->runConfigurations();
runConfigurations.removeOne(target->activeRunConfiguration());
runConfigurations.prepend(target->activeRunConfiguration());
for (RunConfiguration *runConfig : qAsConst(runConfigurations)) {
qCDebug(LOG) << "RunConfiguration" << runConfig->id();
if (!isLocal(target)) { // TODO add device support
qCDebug(LOG) << " Skipped as not being local";

View File

@@ -58,10 +58,11 @@
#include <QThread>
using namespace ClangBackEnd;
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
using namespace ProjectExplorer;
namespace ClangCodeModel {
namespace Internal {
static Q_LOGGING_CATEGORY(debug, "qtc.clangcodemodel.batch", QtWarningMsg);
static int timeOutFromEnvironmentVariable()
@@ -78,7 +79,7 @@ static int timeOutFromEnvironmentVariable()
return intervalAsInt;
}
static int timeOutInMs()
int timeOutInMs()
{
static int timeOut = timeOutFromEnvironmentVariable();
return timeOut;
@@ -747,9 +748,6 @@ bool BatchFileParser::parseLine(const QString &line)
} // anonymous namespace
namespace ClangCodeModel {
namespace Internal {
static QString applySubstitutions(const QString &filePath, const QString &text)
{
const QString dirPath = QFileInfo(filePath).absolutePath();

View File

@@ -30,6 +30,8 @@
namespace ClangCodeModel {
namespace Internal {
int timeOutInMs();
bool runClangBatchFile(const QString &filePath);
} // namespace Internal

View File

@@ -26,6 +26,7 @@
#include "clangcodecompletion_test.h"
#include "clangautomationutils.h"
#include "clangbatchfileprocessor.h"
#include "../clangcompletionassistinterface.h"
#include "../clangmodelmanagersupport.h"
@@ -344,7 +345,7 @@ public:
if (!textToInsert.isEmpty())
openEditor.editor()->insert(textToInsert);
proposal = completionResults(openEditor.editor(), includePaths, 15000);
proposal = completionResults(openEditor.editor(), includePaths, timeOutInMs());
}
TextEditor::ProposalModelPtr proposal;
@@ -657,7 +658,8 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCode()
OpenEditorAtCursorPosition openEditor(testDocument);
QVERIFY(openEditor.succeeded());
TextEditor::ProposalModelPtr proposal = completionResults(openEditor.editor());
TextEditor::ProposalModelPtr proposal = completionResults(openEditor.editor(), {},
timeOutInMs());
QVERIFY(hasItem(proposal, "projectConfiguration1"));
}
@@ -670,7 +672,8 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCodeAfterChangingProje
QVERIFY(openEditor.succeeded());
// Check completion without project
TextEditor::ProposalModelPtr proposal = completionResults(openEditor.editor());
TextEditor::ProposalModelPtr proposal = completionResults(openEditor.editor(), {},
timeOutInMs());
QVERIFY(hasItem(proposal, "noProjectConfigurationDetected"));
{
@@ -681,7 +684,7 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCodeAfterChangingProje
QVERIFY(projectLoader.load());
openEditor.waitUntilProjectPartChanged(QLatin1String("myproject.project"));
proposal = completionResults(openEditor.editor());
proposal = completionResults(openEditor.editor(), {}, timeOutInMs());
QVERIFY(hasItem(proposal, "projectConfiguration1"));
QVERIFY(!hasItem(proposal, "projectConfiguration2"));
@@ -689,7 +692,7 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCodeAfterChangingProje
// Check completion with project configuration 2
QVERIFY(projectLoader.updateProject({{"PROJECT_CONFIGURATION_2"}}));
openEditor.waitUntilBackendIsNotified();
proposal = completionResults(openEditor.editor());
proposal = completionResults(openEditor.editor(), {}, timeOutInMs());
QVERIFY(!hasItem(proposal, "projectConfiguration1"));
QVERIFY(hasItem(proposal, "projectConfiguration2"));
@@ -697,7 +700,7 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCodeAfterChangingProje
// Check again completion without project
openEditor.waitUntilProjectPartChanged(QLatin1String(""));
proposal = completionResults(openEditor.editor());
proposal = completionResults(openEditor.editor(), {}, timeOutInMs());
QVERIFY(hasItem(proposal, "noProjectConfigurationDetected"));
}
@@ -723,7 +726,8 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCodeInGeneratedUiFile(
QVERIFY(openSource.succeeded());
// ...and check comletions
TextEditor::ProposalModelPtr proposal = completionResults(openSource.editor());
TextEditor::ProposalModelPtr proposal = completionResults(openSource.editor(), {},
timeOutInMs());
QVERIFY(hasItem(proposal, "menuBar"));
QVERIFY(hasItem(proposal, "statusBar"));
QVERIFY(hasItem(proposal, "centralWidget"));

View File

@@ -10,9 +10,6 @@
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">

View File

@@ -125,7 +125,7 @@ void ClangToolsUnitTests::testProject()
ClangToolsSettings::instance()->runSettings(),
diagnosticConfig);
QSignalSpy waitForFinishedTool(tool, &ClangTool::finished);
QVERIFY(waitForFinishedTool.wait(90000));
QVERIFY(waitForFinishedTool.wait(m_timeout));
// Check for errors
const QString errorText = waitForFinishedTool.takeFirst().first().toString();
@@ -186,5 +186,11 @@ void ClangToolsUnitTests::addTestRow(const QByteArray &relativeFilePath,
<< absoluteFilePath << expectedDiagCount << diagnosticConfig;
}
int ClangToolsUnitTests::getTimeout()
{
const int t = qEnvironmentVariableIntValue("QTC_CLANGTOOLS_TEST_TIMEOUT");
return t > 0 ? t : 480000;
}
} // namespace Internal
} // namespace ClangTools

View File

@@ -56,8 +56,11 @@ private:
const CppTools::ClangDiagnosticConfig &diagnosticConfig);
private:
static int getTimeout();
CppTools::Tests::TemporaryCopiedDir *m_tmpDir = nullptr;
ProjectExplorer::Kit *m_kit = nullptr;
int m_timeout = getTimeout();
};
} // namespace Internal

View File

@@ -10,9 +10,6 @@
<height>125</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>

View File

@@ -38,6 +38,7 @@
#include <utils/algorithm.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
#include <QThread>
@@ -67,7 +68,7 @@ void CppcheckTool::updateOptions(const CppcheckOptions &options)
if (trimmedPattern.isEmpty())
continue;
const QRegularExpression re(QRegularExpression::wildcardToRegularExpression(trimmedPattern));
const QRegularExpression re(Utils::wildcardToRegularExpression(trimmedPattern));
if (re.isValid())
m_filters.push_back(re);
}

View File

@@ -226,6 +226,8 @@ private slots:
void test_quickfix_removeUsingNamespace_data();
void test_quickfix_removeUsingNamespace();
void test_quickfix_removeUsingNamespace_simple_data();
void test_quickfix_removeUsingNamespace_simple();
void test_quickfix_removeUsingNamespace_differentSymbols();
void test_quickfix_InsertVirtualMethods_data();

View File

@@ -606,6 +606,32 @@ void CppEditorPlugin::test_quickfix_data()
""
);
// Checks: complete switch statement where enum is goes via a template type parameter
QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG-24752")
<< CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _(
"enum E {EA, EB};\n"
"template<typename T> struct S {\n"
" static T theType() { return T(); }\n"
"};\n"
"int main() {\n"
" @switch (S<E>::theType()) {\n"
" }\n"
"}\n"
) << _(
"enum E {EA, EB};\n"
"template<typename T> struct S {\n"
" static T theType() { return T(); }\n"
"};\n"
"int main() {\n"
" switch (S<E>::theType()) {\n"
" case EA:\n"
" break;\n"
" case EB:\n"
" break;\n"
" }\n"
"}\n"
);
// Checks: No special treatment for reference to non const.
// Check: Quick fix is not triggered on a member function.
@@ -7083,6 +7109,49 @@ void CppEditorPlugin::test_quickfix_removeUsingNamespace()
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), operation);
}
void CppEditorPlugin::test_quickfix_removeUsingNamespace_simple_data()
{
QTest::addColumn<QByteArray>("header");
QTest::addColumn<QByteArray>("expected");
const QByteArray common = R"--(
namespace N{
template<typename T>
struct vector{
using iterator = T*;
};
using int_vector = vector<int>;
}
)--";
const QByteArray header = common + R"--(
using namespace N@;
int_vector ints;
int_vector::iterator intIter;
using vec = vector<int>;
vec::iterator it;
)--";
const QByteArray expected = common + R"--(
N::int_vector ints;
N::int_vector::iterator intIter;
using vec = N::vector<int>;
vec::iterator it;
)--";
QTest::newRow("nested typedefs with Namespace") << header << expected;
}
void CppEditorPlugin::test_quickfix_removeUsingNamespace_simple()
{
QFETCH(QByteArray, header);
QFETCH(QByteArray, expected);
QList<QuickFixTestDocument::Ptr> testDocuments;
testDocuments << QuickFixTestDocument::create("header.h", header, expected);
RemoveUsingNamespace factory;
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths());
}
void CppEditorPlugin::test_quickfix_removeUsingNamespace_differentSymbols()
{
QByteArray header = "namespace test{\n"

View File

@@ -2752,6 +2752,7 @@ Enum *conditionEnum(const CppQuickFixInterface &interface, SwitchStatementAST *s
Block *block = statement->symbol;
Scope *scope = interface.semanticInfo().doc->scopeAt(block->line(), block->column());
TypeOfExpression typeOfExpression;
typeOfExpression.setExpandTemplates(true);
typeOfExpression.init(interface.semanticInfo().doc, interface.snapshot());
const QList<LookupItem> results = typeOfExpression(statement->condition,
interface.semanticInfo().doc,
@@ -7794,6 +7795,33 @@ private:
int counter;
};
/**
* @brief getBaseName returns the base name of a qualified name or nullptr.
* E.g.: foo::bar => foo; bar => bar
* @param name The Name, maybe qualified
* @return The base name of the qualified name or nullptr
*/
const Identifier *getBaseName(const Name *name)
{
class GetBaseName : public NameVisitor
{
void visit(const Identifier *name) override { baseName = name; }
void visit(const QualifiedNameId *name) override
{
if (name->base())
accept(name->base());
else
accept(name->name());
}
public:
const Identifier *baseName = nullptr;
};
GetBaseName getter;
getter.accept(name);
return getter.baseName;
}
/**
* @brief countNames counts the parts of the Name.
* E.g. if the name is std::vector, the function returns 2, if the name is variant, returns 1
@@ -7993,11 +8021,24 @@ private:
{
if (m_start) {
Scope *scope = m_file->scopeAt(ast->firstToken());
const QList<LookupItem> lookups = m_context.lookup(ast->name->name, scope);
const Name *wantToLookup = ast->name->name;
// first check if the base name is a typedef. Consider the following example:
// using namespace std;
// using vec = std::vector<int>;
// vec::iterator it; // we have to lookup 'vec' and not iterator (would result in
// std::vector<int>::iterator => std::vec::iterator, which is wrong)
const Name *baseName = getBaseName(wantToLookup);
QList<LookupItem> typedefCandidates = m_context.lookup(baseName, scope);
if (!typedefCandidates.isEmpty()) {
if (typedefCandidates.front().declaration()->isTypedef())
wantToLookup = baseName;
}
const QList<LookupItem> lookups = m_context.lookup(wantToLookup, scope);
if (!lookups.empty()) {
QList<const Name *> fullName = m_context.fullyQualifiedName(
lookups.first().declaration());
const int currentNameCount = countNames(ast->name->name);
const int currentNameCount = countNames(wantToLookup);
const bool needNamespace = needMissingNamespaces(std::move(fullName),
currentNameCount);
if (needNamespace)

View File

@@ -1117,12 +1117,12 @@ void CppToolsPlugin::test_modelmanager_renameIncludesInEditor()
const MyTestDataDir testDir2(_("testdata_project2"));
QFile foobar2000Header(testDir2.file("foobar2000.h"));
QVERIFY(foobar2000Header.open(QFile::ReadOnly));
QVERIFY(foobar2000Header.open(QFile::ReadOnly | QFile::Text));
const auto foobar2000HeaderContents = foobar2000Header.readAll();
foobar2000Header.close();
QFile renamedHeader(renamedHeaderWithNormalGuard);
QVERIFY(renamedHeader.open(QFile::ReadOnly));
QVERIFY(renamedHeader.open(QFile::ReadOnly | QFile::Text));
auto renamedHeaderContents = renamedHeader.readAll();
renamedHeader.close();
QCOMPARE(renamedHeaderContents, foobar2000HeaderContents);
@@ -1133,12 +1133,12 @@ void CppToolsPlugin::test_modelmanager_renameIncludesInEditor()
Core::HandleIncludeGuards::Yes));
QFile foobar4000Header(testDir2.file("foobar4000.h"));
QVERIFY(foobar4000Header.open(QFile::ReadOnly));
QVERIFY(foobar4000Header.open(QFile::ReadOnly | QFile::Text));
const auto foobar4000HeaderContents = foobar4000Header.readAll();
foobar4000Header.close();
renamedHeader.setFileName(renamedHeaderWithUnderscoredGuard);
QVERIFY(renamedHeader.open(QFile::ReadOnly));
QVERIFY(renamedHeader.open(QFile::ReadOnly | QFile::Text));
renamedHeaderContents = renamedHeader.readAll();
renamedHeader.close();
QCOMPARE(renamedHeaderContents, foobar4000HeaderContents);
@@ -1146,7 +1146,7 @@ void CppToolsPlugin::test_modelmanager_renameIncludesInEditor()
// test the renaming of a header with a malformed guard to verify we do not make
// accidental refactors
renamedHeader.setFileName(headerWithMalformedGuard);
QVERIFY(renamedHeader.open(QFile::ReadOnly));
QVERIFY(renamedHeader.open(QFile::ReadOnly | QFile::Text));
auto originalMalformedGuardContents = renamedHeader.readAll();
renamedHeader.close();
@@ -1154,7 +1154,7 @@ void CppToolsPlugin::test_modelmanager_renameIncludesInEditor()
Core::HandleIncludeGuards::Yes));
renamedHeader.setFileName(renamedHeaderWithMalformedGuard);
QVERIFY(renamedHeader.open(QFile::ReadOnly));
QVERIFY(renamedHeader.open(QFile::ReadOnly | QFile::Text));
renamedHeaderContents = renamedHeader.readAll();
renamedHeader.close();
QCOMPARE(renamedHeaderContents, originalMalformedGuardContents);

View File

@@ -4166,7 +4166,7 @@ void GdbEngine::setupInferior()
}
if (!symbolFile.isEmpty()) {
runCommand({"-file-exec-and-symbols \"" + symbolFile + '"',
runCommand({"-file-symbol-file \"" + symbolFile + '"',
CB(handleFileExecAndSymbols)});
}

View File

@@ -2951,14 +2951,12 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
const SynchronousProcessResponse resp = vcsSynchronousExec(repositoryDirectory, arguments,
VcsCommand::NoFullySync);
const QString stdErr = resp.stdErr();
if (resp.result == SynchronousProcessResponse::Finished) {
VcsOutputWindow::appendMessage(msgCommitted(amendSHA1, commitCount));
VcsOutputWindow::appendError(stdErr);
GitPlugin::updateCurrentBranch();
return true;
} else {
VcsOutputWindow::appendError(tr("Cannot commit %n files: %1\n", nullptr, commitCount).arg(stdErr));
VcsOutputWindow::appendError(tr("Cannot commit %n files\n", nullptr, commitCount));
return false;
}
}

View File

@@ -325,10 +325,9 @@ void Client::sendContent(const IContent &content)
QString error;
if (!QTC_GUARD(content.isValid(&error)))
Core::MessageManager::write(error);
LanguageClientManager::logBaseMessage(LspLogMessage::ClientMessage,
name(),
content.toBaseMessage());
m_clientInterface->sendMessage(content.toBaseMessage());
const BaseMessage message = content.toBaseMessage();
LanguageClientManager::logBaseMessage(LspLogMessage::ClientMessage, name(), message);
m_clientInterface->sendMessage(message);
}
void Client::sendContent(const DocumentUri &uri, const IContent &content)

View File

@@ -10,9 +10,6 @@
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>

View File

@@ -10,9 +10,6 @@
<height>349</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget" native="true">

View File

@@ -10,9 +10,6 @@
<height>70</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="_nameLbl">

View File

@@ -10,9 +10,6 @@
<height>349</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">

View File

@@ -124,9 +124,6 @@ QWidget *NimbleTaskStep::createConfigWidget()
connect(buildSystem, &NimbleBuildSystem::tasksChanged, this, &NimbleTaskStep::updateTaskList);
connect(m_taskName, &StringAspect::changed, this, &BuildStep::recreateSummary);
connect(m_taskArgs, &StringAspect::changed, this, &BuildStep::recreateSummary);
setSummaryUpdater([this] {
return QString("<b>%1:</b> nimble %2 %3")
.arg(displayName(), m_taskName->value(), m_taskArgs->value());

View File

@@ -477,6 +477,7 @@ void BuildManager::finish()
{
const QString elapsedTime = Utils::formatElapsedTime(d->m_elapsed.elapsed());
m_instance->addToOutputWindow(elapsedTime, BuildStep::OutputFormat::NormalMessage);
d->m_outputWindow->flush();
QApplication::alert(ICore::dialogParent(), 3000);
}
@@ -696,7 +697,7 @@ void BuildManager::nextStep()
}
static const auto finishedHandler = [](bool success) {
d->m_outputWindow->outputFormatter()->flush();
d->m_outputWindow->flush();
d->m_lastStepSucceeded = success;
disconnect(d->m_currentBuildStep, nullptr, instance(), nullptr);
BuildManager::nextBuildQueue();

View File

@@ -35,6 +35,7 @@ class PROJECTEXPLORER_EXPORT BuildPropertiesSettings
{
public:
QString buildDirectoryTemplate;
QString buildDirectoryTemplateOld; // TODO: Remove in ~4.16
Utils::TriState separateDebugInfo;
Utils::TriState qmlDebugging;
Utils::TriState qtQuickCompiler;

View File

@@ -157,6 +157,26 @@ void BuildStep::cancel()
doCancel();
}
QWidget *BuildStep::doCreateConfigWidget()
{
QWidget *widget = createConfigWidget();
const auto recreateSummary = [this] {
if (m_summaryUpdater)
setSummaryText(m_summaryUpdater());
};
for (BaseAspect *aspect : qAsConst(m_aspects))
connect(aspect, &BaseAspect::changed, widget, recreateSummary);
connect(buildConfiguration(), &BuildConfiguration::buildDirectoryChanged,
widget, recreateSummary);
recreateSummary();
return widget;
}
QWidget *BuildStep::createConfigWidget()
{
auto widget = new QWidget;
@@ -165,12 +185,8 @@ QWidget *BuildStep::createConfigWidget()
for (BaseAspect *aspect : qAsConst(m_aspects)) {
if (aspect->isVisible())
aspect->addToLayout(builder.finishRow());
connect(aspect, &BaseAspect::changed, this, &BuildStep::recreateSummary);
}
connect(buildConfiguration(), &BuildConfiguration::buildDirectoryChanged,
this, &BuildStep::recreateSummary);
if (m_addMacroExpander)
VariableChooser::addSupportForChildWidgets(widget, macroExpander());
@@ -500,13 +516,6 @@ void BuildStep::setSummaryText(const QString &summaryText)
void BuildStep::setSummaryUpdater(const std::function<QString()> &summaryUpdater)
{
m_summaryUpdater = summaryUpdater;
recreateSummary();
}
void BuildStep::recreateSummary()
{
if (m_summaryUpdater)
setSummaryText(m_summaryUpdater());
}
} // ProjectExplorer

View File

@@ -70,7 +70,6 @@ public:
virtual bool init() = 0;
void run();
void cancel();
virtual QWidget *createConfigWidget();
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
@@ -120,7 +119,7 @@ public:
QString summaryText() const;
void setSummaryText(const QString &summaryText);
void recreateSummary();
QWidget *doCreateConfigWidget();
signals:
void updateSummary();
@@ -141,6 +140,8 @@ signals:
void finished(bool result);
protected:
virtual QWidget *createConfigWidget();
void runInThread(const std::function<bool()> &syncImpl);
std::function<bool()> cancelChecker() const;

View File

@@ -170,7 +170,7 @@ void ToolWidget::setDownVisible(bool b)
BuildStepsWidgetData::BuildStepsWidgetData(BuildStep *s) :
step(s), widget(nullptr), detailsWidget(nullptr)
{
widget = s->createConfigWidget();
widget = s->doCreateConfigWidget();
Q_ASSERT(widget);
detailsWidget = new DetailsWidget;

View File

@@ -416,8 +416,6 @@ QWidget *MakeStep::createConfigWidget()
m_nonOverrideWarning->setVisible(makeflagsJobCountMismatch()
&& !jobCountOverridesMakeflags());
disableInSubDirsCheckBox->setChecked(!m_enabledForSubDirs);
recreateSummary();
};
updateDetails();

View File

@@ -259,7 +259,8 @@ const char PROJECT_OPEN_LOCATIONS_CONTEXT_MENU[] = "Project.P.OpenLocation.CtxM
// Default directories:
const char DEFAULT_BUILD_DIRECTORY_TEMPLATE[] = "../%{JS: Util.asciify(\"build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}\")}";
const char DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY[] = "Directories/BuildDirectory.Template";
const char DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY_OLD[] = "Directories/BuildDirectory.Template"; // TODO: Remove in ~4.16
const char DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY[] = "Directories/BuildDirectory.TemplateV2";
const char BUILD_BEFORE_DEPLOY_SETTINGS_KEY[] = "ProjectExplorer/Settings/BuildBeforeDeploy";
const char DEPLOY_BEFORE_RUN_SETTINGS_KEY[] = "ProjectExplorer/Settings/DeployBeforeRun";
@@ -1532,8 +1533,14 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_projectExplorerSettings.lowBuildPriority
= s->value(Constants::LOW_BUILD_PRIORITY_SETTINGS_KEY, false).toBool();
dd->m_buildPropertiesSettings.buildDirectoryTemplateOld
= s->value(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY_OLD).toString();
dd->m_buildPropertiesSettings.buildDirectoryTemplate
= s->value(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY).toString();
if (dd->m_buildPropertiesSettings.buildDirectoryTemplate.isEmpty()) {
dd->m_buildPropertiesSettings.buildDirectoryTemplate
= dd->m_buildPropertiesSettings.buildDirectoryTemplateOld;
}
if (dd->m_buildPropertiesSettings.buildDirectoryTemplate.isEmpty())
dd->m_buildPropertiesSettings.buildDirectoryTemplate = Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE;
// TODO: Remove in ~4.16
@@ -2110,6 +2117,8 @@ void ProjectExplorerPluginPrivate::savePersistentSettings()
s->setValue(Constants::STOP_BEFORE_BUILD_SETTINGS_KEY, int(dd->m_projectExplorerSettings.stopBeforeBuild));
// Store this in the Core directory scope for backward compatibility!
s->setValue(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY_OLD,
dd->m_buildPropertiesSettings.buildDirectoryTemplateOld);
s->setValue(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY,
dd->m_buildPropertiesSettings.buildDirectoryTemplate);

View File

@@ -53,9 +53,11 @@ class PROJECTEXPLORER_EXPORT Target : public QObject
friend class SessionManager; // for setActiveBuild and setActiveDeployConfiguration
Q_OBJECT
struct _constructor_tag { explicit _constructor_tag() = default; };
public:
struct _constructor_tag
{
explicit _constructor_tag() = default;
};
Target(Project *parent, Kit *k, _constructor_tag);
~Target() override;

View File

@@ -75,6 +75,17 @@ using namespace QmakeProjectManager::Internal;
namespace QmakeProjectManager {
class RunSystemAspect : public TriStateAspect
{
Q_OBJECT
public:
RunSystemAspect() : TriStateAspect(tr("Run"), tr("Ignore"), tr("Use global setting"))
{
setSettingsKey("RunSystemFunction");
setDisplayName(tr("qmake system() behavior when parsing:"));
}
};
QmakeExtraBuildInfo::QmakeExtraBuildInfo()
{
const BuildPropertiesSettings &settings = ProjectExplorerPlugin::buildPropertiesSettings();
@@ -198,6 +209,8 @@ QmakeBuildConfiguration::QmakeBuildConfiguration(Target *target, Utils::Id id)
emit qmakeBuildConfigurationChanged();
qmakeBuildSystem()->scheduleUpdateAllNowOrLater();
});
addAspect<RunSystemAspect>();
}
QmakeBuildConfiguration::~QmakeBuildConfiguration()
@@ -439,6 +452,17 @@ void QmakeBuildConfiguration::forceQtQuickCompiler(bool enable)
aspect<QtQuickCompilerAspect>()->setSetting(enable ? TriState::Enabled : TriState::Disabled);
}
bool QmakeBuildConfiguration::runSystemFunction() const
{
switch (aspect<RunSystemAspect>()->value()) {
case 0:
return true;
case 1:
return false;
}
return QmakeSettings::runSystemFunction();
}
QStringList QmakeBuildConfiguration::configCommandLineArguments() const
{
QStringList result;
@@ -875,3 +899,5 @@ void QmakeBuildConfiguration::restrictNextBuild(const RunConfiguration *rc)
}
} // namespace QmakeProjectManager
#include <qmakebuildconfiguration.moc>

View File

@@ -106,6 +106,8 @@ public:
Utils::TriState useQtQuickCompiler() const;
void forceQtQuickCompiler(bool enable);
bool runSystemFunction() const;
signals:
/// emitted for setQMakeBuildConfig, not emitted for Qt version changes, even
/// if those change the qmakebuildconfig

View File

@@ -1839,15 +1839,24 @@ QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const F
}
bool tryUnfixified = false;
// These paths should not be checked for existence, to ensure consistent include path lists
// before and after building.
const QString mocDir = mocDirPath(reader, buildDir);
const QString uiDir = uiDirPath(reader, buildDir);
foreach (const ProFileEvaluator::SourceFile &el,
reader->fixifiedValues(QLatin1String("INCLUDEPATH"), projectDir, buildDir.toString(),
false)) {
const QString sysrootifiedPath = sysrootify(el.fileName, sysroot.toString(), projectDir,
buildDir.toString());
if (IoUtils::isAbsolutePath(sysrootifiedPath) && IoUtils::exists(sysrootifiedPath))
if (IoUtils::isAbsolutePath(sysrootifiedPath)
&& (IoUtils::exists(sysrootifiedPath) || sysrootifiedPath == mocDir
|| sysrootifiedPath == uiDir)) {
paths << sysrootifiedPath;
else
} else {
tryUnfixified = true;
}
}
// If sysrootifying a fixified path does not yield a valid path, try again with the
@@ -1862,10 +1871,6 @@ QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const F
}
}
// paths already contains moc dir and ui dir, due to corrrectly parsing uic.prf and moc.prf
// except if those directories don't exist at the time of parsing
// thus we add those directories manually (without checking for existence)
paths << mocDirPath(reader, buildDir) << uiDirPath(reader, buildDir);
paths.removeDuplicates();
return paths;
}

View File

@@ -797,6 +797,7 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi
m_qmakeGlobals->environment.insert(env.key(eit), env.expandedValueForKey(env.key(eit)));
m_qmakeGlobals->setCommandLineArguments(buildDir(rootProFile()->filePath()).toString(), qmakeArgs);
m_qmakeGlobals->runSystemFunction = bc->runSystemFunction();
QtSupport::ProFileCacheManager::instance()->incRefCount();

View File

@@ -38,11 +38,13 @@ namespace Internal {
const char BUILD_DIR_WARNING_KEY[] = "QmakeProjectManager/WarnAgainstUnalignedBuildDir";
const char ALWAYS_RUN_QMAKE_KEY[] = "QmakeProjectManager/AlwaysRunQmake";
const char RUN_SYSTEM_KEY[] = "QmakeProjectManager/RunSystemFunction";
static bool operator==(const QmakeSettingsData &s1, const QmakeSettingsData &s2)
{
return s1.warnAgainstUnalignedBuildDir == s2.warnAgainstUnalignedBuildDir
&& s1.alwaysRunQmake == s2.alwaysRunQmake;
&& s1.alwaysRunQmake == s2.alwaysRunQmake
&& s1.runSystemFunction == s2.runSystemFunction;
}
static bool operator!=(const QmakeSettingsData &s1, const QmakeSettingsData &s2)
{
@@ -59,6 +61,11 @@ bool QmakeSettings::alwaysRunQmake()
return instance().m_settings.alwaysRunQmake;
}
bool QmakeSettings::runSystemFunction()
{
return instance().m_settings.runSystemFunction;
}
QmakeSettings &QmakeSettings::instance()
{
static QmakeSettings theSettings;
@@ -85,6 +92,7 @@ void QmakeSettings::loadSettings()
m_settings.warnAgainstUnalignedBuildDir = s->value(
BUILD_DIR_WARNING_KEY, Utils::HostOsInfo::isWindowsHost()).toBool();
m_settings.alwaysRunQmake = s->value(ALWAYS_RUN_QMAKE_KEY, false).toBool();
m_settings.runSystemFunction = s->value(RUN_SYSTEM_KEY, false).toBool();
}
void QmakeSettings::storeSettings() const
@@ -92,6 +100,7 @@ void QmakeSettings::storeSettings() const
QSettings * const s = Core::ICore::settings();
s->setValue(BUILD_DIR_WARNING_KEY, warnAgainstUnalignedBuildDir());
s->setValue(ALWAYS_RUN_QMAKE_KEY, alwaysRunQmake());
s->setValue(RUN_SYSTEM_KEY, runSystemFunction());
}
class QmakeSettingsPage::SettingsWidget : public QWidget
@@ -110,9 +119,15 @@ public:
m_alwaysRunQmakeCheckbox.setToolTip(tr("This option can help to prevent failures on "
"incremental builds, but might slow them down unnecessarily in the general case."));
m_alwaysRunQmakeCheckbox.setChecked(QmakeSettings::alwaysRunQmake());
m_ignoreSystemCheckbox.setText(tr("Ignore qmake's system() function "
"when parsing a project"));
m_ignoreSystemCheckbox.setToolTip(tr("Unchecking this option can help getting more exact "
"parsing results, but can have unwanted side effects."));
m_ignoreSystemCheckbox.setChecked(!QmakeSettings::runSystemFunction());
const auto layout = new QVBoxLayout(this);
layout->addWidget(&m_warnAgainstUnalignedBuildDirCheckbox);
layout->addWidget(&m_alwaysRunQmakeCheckbox);
layout->addWidget(&m_ignoreSystemCheckbox);
layout->addStretch(1);
}
@@ -121,12 +136,14 @@ public:
QmakeSettingsData settings;
settings.warnAgainstUnalignedBuildDir = m_warnAgainstUnalignedBuildDirCheckbox.isChecked();
settings.alwaysRunQmake = m_alwaysRunQmakeCheckbox.isChecked();
settings.runSystemFunction = !m_ignoreSystemCheckbox.isChecked();
QmakeSettings::setSettingsData(settings);
}
private:
QCheckBox m_warnAgainstUnalignedBuildDirCheckbox;
QCheckBox m_alwaysRunQmakeCheckbox;
QCheckBox m_ignoreSystemCheckbox;
};
QmakeSettingsPage::QmakeSettingsPage()

View File

@@ -37,6 +37,7 @@ class QmakeSettingsData {
public:
bool warnAgainstUnalignedBuildDir = false;
bool alwaysRunQmake = false;
bool runSystemFunction = false;
};
class QmakeSettings : public QObject
@@ -46,6 +47,7 @@ public:
static QmakeSettings &instance();
static bool warnAgainstUnalignedBuildDir();
static bool alwaysRunQmake();
static bool runSystemFunction();
static void setSettingsData(const QmakeSettingsData &settings);
signals:

View File

@@ -6,7 +6,7 @@ endif()
add_qtc_plugin(QmlDesigner
DEPENDS
QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
Qt5::QuickWidgets Qt5::CorePrivate
Qt5::QuickWidgets Qt5::CorePrivate Sqlite
DEFINES
DESIGNER_CORE_LIBRARY
IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\"
@@ -208,6 +208,7 @@ extend_qtc_plugin(QmlDesigner
modelnodecontextmenu.cpp modelnodecontextmenu.h
modelnodecontextmenu_helper.cpp modelnodecontextmenu_helper.h
modelnodeoperations.cpp modelnodeoperations.h
navigation2d.cpp navigation2d.h
qmldesignericonprovider.cpp qmldesignericonprovider.h
selectioncontext.cpp selectioncontext.h
theme.cpp theme.h
@@ -316,6 +317,7 @@ extend_qtc_plugin(QmlDesigner
itemlibraryassetimportdialog.cpp itemlibraryassetimportdialog.h
itemlibraryassetimportdialog.ui
itemlibraryassetimporter.cpp itemlibraryassetimporter.h
itemlibraryiconimageprovider.cpp itemlibraryiconimageprovider.h
)
find_package(Qt5 COMPONENTS Quick3DAssetImport QUIET)
@@ -501,6 +503,7 @@ extend_qtc_plugin(QmlDesigner
include/textmodifier.h
include/variantproperty.h
include/viewmanager.h
include/imagecache.h
)
extend_qtc_plugin(QmlDesigner
@@ -585,6 +588,21 @@ extend_qtc_plugin(QmlDesigner
pluginmanager/widgetpluginmanager.cpp pluginmanager/widgetpluginmanager.h
pluginmanager/widgetpluginpath.cpp pluginmanager/widgetpluginpath.h
rewritertransaction.cpp rewritertransaction.h
imagecache/imagecachecollector.h
imagecache/imagecachecollector.cpp
imagecache/imagecache.cpp
imagecache/imagecachecollectorinterface.h
imagecache/imagecacheconnectionmanager.cpp
imagecache/imagecacheconnectionmanager.h
imagecache/imagecachegenerator.cpp
imagecache/imagecachegenerator.h
imagecache/imagecachestorage.h
imagecache/imagecachegeneratorinterface.h
imagecache/imagecachestorageinterface.h
imagecache/timestampproviderinterface.h
imagecache/timestampprovider.h
imagecache/timestampprovider.cpp
)
extend_qtc_plugin(QmlDesigner
@@ -644,6 +662,16 @@ extend_qtc_plugin(QmlDesigner
texttool/texttool.cpp texttool/texttool.h
)
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/previewtooltip
SOURCES
previewimagetooltip.cpp
previewimagetooltip.h
previewimagetooltip.ui
previewtooltipbackend.cpp
previewtooltipbackend.h
)
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/richtexteditor
SOURCES

View File

@@ -28,12 +28,12 @@
#include "assetexportpluginconstants.h"
#include "filepathmodel.h"
#include "coreplugin/fileutils.h"
#include "coreplugin/icore.h"
#include "projectexplorer/task.h"
#include "projectexplorer/taskhub.h"
#include "utils/fileutils.h"
#include "utils/outputformatter.h"
#include <coreplugin/fileutils.h>
#include <coreplugin/icore.h>
#include <projectexplorer/task.h>
#include <projectexplorer/taskhub.h>
#include <utils/fileutils.h>
#include <utils/outputformatter.h>
#include <QCheckBox>
#include <QPushButton>

View File

@@ -28,18 +28,34 @@
#include "richtexteditor/richtexteditor.h"
#include "QStringListModel"
namespace QmlDesigner {
AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) :
QWidget(parent),
ui(new Ui::AnnotationCommentTab)
AnnotationCommentTab::AnnotationCommentTab(QWidget *parent)
: QWidget(parent)
, ui(new Ui::AnnotationCommentTab)
{
ui->setupUi(this);
m_editor = new RichTextEditor;
ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor);
connect(ui->titleEdit, &QLineEdit::textEdited,
ui->titleEdit->setModel(new QStringListModel{QStringList{"Description",
"Display Condition",
"helper_lines"
"highlight"
"project author",
"project confirmed",
"project developer",
"project distributor",
"project modified",
"project type"
"project version",
"Screen Description"
"Section"}});
connect(ui->titleEdit, &QComboBox::currentTextChanged,
this, &AnnotationCommentTab::commentTitleChanged);
}
@@ -52,7 +68,7 @@ Comment AnnotationCommentTab::currentComment() const
{
Comment result;
result.setTitle(ui->titleEdit->text().trimmed());
result.setTitle(ui->titleEdit->currentText().trimmed());
result.setAuthor(ui->authorEdit->text().trimmed());
result.setText(m_editor->richText().trimmed());
@@ -77,7 +93,7 @@ void AnnotationCommentTab::setComment(const Comment &comment)
void AnnotationCommentTab::resetUI()
{
ui->titleEdit->setText(m_comment.title());
ui->titleEdit->setCurrentText(m_comment.title());
ui->authorEdit->setText(m_comment.author());
m_editor->setRichText(m_comment.deescapedText());

View File

@@ -24,7 +24,11 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="titleEdit"/>
<widget class="QComboBox" name="titleEdit">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="textLabel">

View File

@@ -14,6 +14,7 @@ SOURCES += modelnodecontextmenu_helper.cpp
SOURCES += selectioncontext.cpp
SOURCES += designeractionmanager.cpp
SOURCES += modelnodeoperations.cpp
SOURCES += navigation2d.cpp
SOURCES += crumblebar.cpp
SOURCES += qmldesignericonprovider.cpp
SOURCES += zoomaction.cpp
@@ -33,6 +34,7 @@ HEADERS += selectioncontext.h
HEADERS += componentcore_constants.h
HEADERS += designeractionmanager.h
HEADERS += modelnodeoperations.h
HEADERS += navigation2d.h
HEADERS += actioninterface.h
HEADERS += crumblebar.h
HEADERS += qmldesignericonprovider.h

View File

@@ -347,25 +347,27 @@ public:
&& !selectionContext().currentSingleSelectedNode().isRootNode()
&& selectionContext().currentSingleSelectedNode().hasParentProperty()) {
ActionTemplate *selectionAction = new ActionTemplate(QString(), &ModelNodeOperations::select);
selectionAction->setParent(menu());
parentNode = selectionContext().currentSingleSelectedNode().parentProperty().parentModelNode();
selectionAction->setText(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select parent: %1")).arg(
captionForModelNode(parentNode)));
if (!ModelNode::isThisOrAncestorLocked(parentNode)) {
ActionTemplate *selectionAction = new ActionTemplate(QString(), &ModelNodeOperations::select);
selectionAction->setParent(menu());
selectionAction->setText(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select parent: %1")).arg(
captionForModelNode(parentNode)));
SelectionContext nodeSelectionContext = selectionContext();
nodeSelectionContext.setTargetNode(parentNode);
selectionAction->setSelectionContext(nodeSelectionContext);
SelectionContext nodeSelectionContext = selectionContext();
nodeSelectionContext.setTargetNode(parentNode);
selectionAction->setSelectionContext(nodeSelectionContext);
menu()->addAction(selectionAction);
menu()->addAction(selectionAction);
}
}
foreach (const ModelNode &node, selectionContext().view()->allModelNodes()) {
for (const ModelNode &node : selectionContext().view()->allModelNodes()) {
if (node != selectionContext().currentSingleSelectedNode()
&& node != parentNode
&& contains(node, selectionContext().scenePosition())
&& !node.isRootNode()) {
&& !node.isRootNode()
&& !ModelNode::isThisOrAncestorLocked(node)) {
selectionContext().setTargetNode(node);
QString what = QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select: %1")).arg(captionForModelNode(node));
ActionTemplate *selectionAction = new ActionTemplate(what, &ModelNodeOperations::select);
@@ -377,6 +379,9 @@ public:
menu()->addAction(selectionAction);
}
}
if (menu()->isEmpty())
action()->setEnabled(false);
}
}
};
@@ -574,11 +579,6 @@ bool multiSelection(const SelectionContext &context)
return !singleSelection(context) && selectionNotEmpty(context);
}
bool singleSelectionAndInBaseState(const SelectionContext &context)
{
return singleSelection(context) && inBaseState(context);
}
bool multiSelectionAndInBaseState(const SelectionContext &context)
{
return multiSelection(context) && inBaseState(context);
@@ -828,6 +828,11 @@ bool studioComponentsAvailable(const SelectionContext &context)
return context.view()->model()->isImportPossible(import, true, true);
}
bool studioComponentsAvailableAndSelectionCanBeLayouted(const SelectionContext &context)
{
return selectionCanBeLayouted(context) && studioComponentsAvailable(context);
}
bool singleSelectedAndUiFile(const SelectionContext &context)
{
if (!singleSelection(context))
@@ -882,6 +887,12 @@ bool raiseAvailable(const SelectionContext &selectionState)
return parentProperty.indexOf(modelNode) < parentProperty.count() - 1;
}
bool anchorsMenuEnabled(const SelectionContext &context)
{
return singleSelectionItemIsNotAnchoredAndSingleSelectionNotRoot(context)
|| singleSelectionItemIsAnchored(context);
}
void DesignerActionManager::createDefaultDesignerActions()
{
using namespace SelectionContextFunctors;
@@ -996,11 +1007,10 @@ void DesignerActionManager::createDefaultDesignerActions()
&setVisible,
&singleSelectedItem));
addDesignerAction(new ActionGroup(
anchorsCategoryDisplayName,
anchorsCategory,
priorityAnchorsCategory,
&singleSelectionAndInBaseState));
addDesignerAction(new ActionGroup(anchorsCategoryDisplayName,
anchorsCategory,
priorityAnchorsCategory,
&anchorsMenuEnabled));
addDesignerAction(new ModelNodeAction(
anchorsFillCommandId,
@@ -1042,7 +1052,7 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ActionGroup(groupCategoryDisplayName,
groupCategory,
priorityGroupCategory,
&studioComponentsAvailable));
&studioComponentsAvailableAndSelectionCanBeLayouted));
addDesignerAction(new ActionGroup(
flowCategoryDisplayName,

View File

@@ -0,0 +1,91 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "navigation2d.h"
#include <QGestureEvent>
#include <QWheelEvent>
namespace QmlDesigner {
Navigation2dScrollBar::Navigation2dScrollBar(QWidget *parent)
: QScrollBar(parent)
{}
bool Navigation2dScrollBar::postEvent(QEvent *event)
{
if (event->type() == QEvent::Wheel) {
wheelEvent(static_cast<QWheelEvent *>(event));
return true;
}
return false;
}
void Navigation2dScrollBar::wheelEvent(QWheelEvent *event)
{
if (!event->angleDelta().isNull())
QScrollBar::wheelEvent(event);
}
Navigation2dFilter::Navigation2dFilter(QWidget *parent, Navigation2dScrollBar *scrollbar)
: QObject(parent)
, m_scrollbar(scrollbar)
{
if (parent)
parent->grabGesture(Qt::PinchGesture);
}
bool Navigation2dFilter::eventFilter(QObject *, QEvent *event)
{
if (event->type() == QEvent::Gesture)
return gestureEvent(static_cast<QGestureEvent *>(event));
else if (event->type() == QEvent::Wheel && m_scrollbar)
return wheelEvent(static_cast<QWheelEvent *>(event));
return QObject::event(event);
}
bool Navigation2dFilter::gestureEvent(QGestureEvent *event)
{
if (QPinchGesture *pinch = static_cast<QPinchGesture *>(event->gesture(Qt::PinchGesture))) {
QPinchGesture::ChangeFlags changeFlags = pinch->changeFlags();
if (changeFlags & QPinchGesture::ScaleFactorChanged) {
emit zoomChanged(-(1.0 - pinch->scaleFactor()), pinch->startCenterPoint());
event->accept();
return true;
}
}
return false;
}
bool Navigation2dFilter::wheelEvent(QWheelEvent *event)
{
if (m_scrollbar->postEvent(event))
event->ignore();
return false;
}
} // End namespace QmlDesigner.

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QScrollBar>
QT_FORWARD_DECLARE_CLASS(QGestureEvent)
QT_FORWARD_DECLARE_CLASS(QWheelEvent)
namespace QmlDesigner {
class Navigation2dScrollBar : public QScrollBar
{
Q_OBJECT
public:
Navigation2dScrollBar(QWidget *parent = nullptr);
bool postEvent(QEvent *event);
protected:
void wheelEvent(QWheelEvent *event) override;
};
class Navigation2dFilter : public QObject
{
Q_OBJECT
signals:
void zoomChanged(double scale, const QPointF &pos);
public:
Navigation2dFilter(QWidget *parent = nullptr, Navigation2dScrollBar *scrollbar = nullptr);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private:
bool gestureEvent(QGestureEvent *event);
bool wheelEvent(QWheelEvent *event);
Navigation2dScrollBar *m_scrollbar = nullptr;
};
} // namespace QmlDesigner

View File

@@ -107,6 +107,8 @@ public:
idAliasOff,
idAliasOn,
listView,
lockOff,
lockOn,
mergeCells,
minus,
plus,
@@ -129,6 +131,8 @@ public:
undo,
upDownIcon,
upDownSquare2,
visibilityOff,
visibilityOn,
wildcard,
zoomAll,
zoomIn,

View File

@@ -75,6 +75,23 @@ ConnectionModel::ConnectionModel(ConnectionView *parent)
connect(this, &QStandardItemModel::dataChanged, this, &ConnectionModel::handleDataChanged);
}
Qt::ItemFlags ConnectionModel::flags(const QModelIndex &modelIndex) const
{
if (!modelIndex.isValid())
return Qt::ItemIsEnabled;
if (!m_connectionView || !m_connectionView->model())
return Qt::ItemIsEnabled;
const int internalId = data(index(modelIndex.row(), TargetModelNodeRow), UserRoles::InternalIdRole).toInt();
ModelNode modelNode = m_connectionView->modelNodeForInternalId(internalId);
if (modelNode.isValid() && ModelNode::isThisOrAncestorLocked(modelNode))
return Qt::ItemIsEnabled;
return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
}
void ConnectionModel::resetModel()
{
beginResetModel();
@@ -82,7 +99,7 @@ void ConnectionModel::resetModel()
setHorizontalHeaderLabels(QStringList({ tr("Target"), tr("Signal Handler"), tr("Action") }));
if (connectionView()->isAttached()) {
for (const ModelNode modelNode : connectionView()->allModelNodes())
for (const ModelNode &modelNode : connectionView()->allModelNodes())
addModelNode(modelNode);
}
@@ -94,8 +111,8 @@ void ConnectionModel::resetModel()
SignalHandlerProperty ConnectionModel::signalHandlerPropertyForRow(int rowNumber) const
{
const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
const int internalId = data(index(rowNumber, TargetModelNodeRow), UserRoles::InternalIdRole).toInt();
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), UserRoles::TargetPropertyNameRole).toString();
ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId);
if (modelNode.isValid())
@@ -256,8 +273,8 @@ void ConnectionModel::updateTargetNode(int rowNumber)
void ConnectionModel::updateCustomData(QStandardItem *item, const SignalHandlerProperty &signalHandlerProperty)
{
item->setData(signalHandlerProperty.parentModelNode().internalId(), Qt::UserRole + 1);
item->setData(signalHandlerProperty.name(), Qt::UserRole + 2);
item->setData(signalHandlerProperty.parentModelNode().internalId(), UserRoles::InternalIdRole);
item->setData(signalHandlerProperty.name(), UserRoles::TargetPropertyNameRole);
}
ModelNode ConnectionModel::getTargetNodeForConnection(const ModelNode &connection) const

View File

@@ -48,7 +48,14 @@ public:
TargetPropertyNameRow = 1,
SourceRow = 2
};
enum UserRoles {
InternalIdRole = Qt::UserRole + 1,
TargetPropertyNameRole
};
ConnectionModel(ConnectionView *parent = nullptr);
Qt::ItemFlags flags(const QModelIndex &modelIndex) const override;
void resetModel();
SignalHandlerProperty signalHandlerPropertyForRow(int rowNumber) const;
ConnectionView *connectionView() const;

View File

@@ -36,6 +36,8 @@
#include <variantproperty.h>
#include <signalhandlerproperty.h>
#include <QTableView>
namespace QmlDesigner {
namespace Internal {
@@ -162,6 +164,33 @@ void ConnectionView::selectedNodesChanged(const QList<ModelNode> & selectedNodeL
emit connectionViewWidget()->setEnabledAddButton(selectedNodeList.count() == 1);
}
void ConnectionView::auxiliaryDataChanged(const ModelNode &node,
const PropertyName &name,
const QVariant &data)
{
Q_UNUSED(node)
// Check if the auxiliary data is actually the locked property or if it is unlocked
if (name != QmlDesigner::lockedProperty || !data.toBool())
return;
QItemSelectionModel *selectionModel = connectionTableView()->selectionModel();
if (!selectionModel->hasSelection())
return;
QModelIndex modelIndex = selectionModel->currentIndex();
if (!modelIndex.isValid() || !model())
return;
const int internalId = connectionModel()->data(connectionModel()->index(modelIndex.row(),
ConnectionModel::TargetModelNodeRow),
ConnectionModel::UserRoles::InternalIdRole).toInt();
ModelNode modelNode = modelNodeForInternalId(internalId);
if (modelNode.isValid() && ModelNode::isThisOrAncestorLocked(modelNode))
selectionModel->clearSelection();
}
void ConnectionView::importsChanged(const QList<Import> & /*addedImports*/, const QList<Import> & /*removedImports*/)
{
backendModel()->resetModel();

View File

@@ -69,6 +69,7 @@ public:
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;

View File

@@ -27,6 +27,7 @@
#include "axis.h"
#include "curveeditormodel.h"
#include "curveitem.h"
#include "navigation2d.h"
#include "treeitem.h"
#include "utils.h"
@@ -79,6 +80,13 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
applyZoom(m_zoomX, m_zoomY);
update();
QmlDesigner::Navigation2dFilter *filter = new QmlDesigner::Navigation2dFilter(this);
auto zoomChanged = &QmlDesigner::Navigation2dFilter::zoomChanged;
connect(filter, zoomChanged, [this](double scale, const QPointF &pos) {
applyZoom(m_zoomX + scale, m_zoomY, mapToGlobal(pos.toPoint()));
});
installEventFilter(filter);
}
GraphicsView::~GraphicsView()

View File

@@ -41,8 +41,11 @@ struct HandleGeometry
handle = QRectF(topLeft, -topLeft);
toKeyframe = QLineF(QPointF(0.0, 0.0), -pos);
angle = -toKeyframe.angle() + 45.0;
bbox = handle.united(QRectF(-pos, QSizeF(1.0,1.0)));
}
QRectF bbox;
QRectF handle;
QLineF toKeyframe;
@@ -97,7 +100,7 @@ HandleItem::Slot HandleItem::slot() const
QRectF HandleItem::boundingRect() const
{
HandleGeometry geom(pos(), m_style);
return geom.handle;
return geom.bbox;
}
bool HandleItem::contains(const QPointF &point) const

View File

@@ -189,7 +189,7 @@ FormEditorItem *AbstractFormEditorTool::topMovableFormEditorItem(const QList<QGr
FormEditorItem* AbstractFormEditorTool::nearestFormEditorItem(const QPointF &point, const QList<QGraphicsItem*> &itemList)
{
FormEditorItem* nearestItem = nullptr;
foreach (QGraphicsItem *item, itemList) {
for (QGraphicsItem *item : itemList) {
FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
if (formEditorItem && formEditorItem->flowHitTest(point))
@@ -201,6 +201,9 @@ FormEditorItem* AbstractFormEditorTool::nearestFormEditorItem(const QPointF &poi
if (formEditorItem->parentItem() && !formEditorItem->parentItem()->isContentVisible())
continue;
if (formEditorItem && ModelNode::isThisOrAncestorLocked(formEditorItem->qmlItemNode().modelNode()))
continue;
if (!nearestItem)
nearestItem = formEditorItem;
else if (formEditorItem->selectionWeigth(point, 1) < nearestItem->selectionWeigth(point, 0))

View File

@@ -250,7 +250,6 @@ void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSc
if (m_dragNode.isValid())
view()->setSelectedModelNode(m_dragNode);
m_dragNode = QmlItemNode();
view()->changeToSelectionTool();

View File

@@ -286,6 +286,7 @@ bool FormEditorItem::flowHitTest(const QPointF & ) const
void FormEditorItem::setFrameColor(const QColor &color)
{
m_frameColor = color;
update();
}
FormEditorItem::~FormEditorItem()

View File

@@ -90,10 +90,10 @@ void RubberBandSelectionManipulator::select(SelectionType selectionType)
if (!m_beginFormEditorItem)
return;
QList<QGraphicsItem*> itemList = m_editorView->scene()->items(m_selectionRectangleElement.rect(), Qt::IntersectsItemBoundingRect);
QList<QGraphicsItem *> itemList = m_editorView->scene()->items(m_selectionRectangleElement.rect(), Qt::IntersectsItemBoundingRect);
QList<QmlItemNode> newNodeList;
foreach (QGraphicsItem* item, itemList)
for (QGraphicsItem *item : itemList)
{
FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
@@ -137,7 +137,7 @@ void RubberBandSelectionManipulator::select(SelectionType selectionType)
}
void RubberBandSelectionManipulator::setItems(const QList<FormEditorItem*> &itemList)
void RubberBandSelectionManipulator::setItems(const QList<FormEditorItem *> &itemList)
{
m_itemList = itemList;
}

View File

@@ -49,6 +49,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/editormanager.h>
#include <utils/algorithm.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@@ -57,6 +58,7 @@
#include <QDebug>
#include <QApplication>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QRandomGenerator>
@@ -375,9 +377,41 @@ void DesignDocument::deleteSelected()
if (!currentModel())
return;
QStringList lockedNodes;
for (const ModelNode &modelNode : view()->selectedModelNodes()) {
for (const ModelNode &node : modelNode.allSubModelNodesAndThisNode()) {
if (node.isValid() && !node.isRootNode() && node.locked())
lockedNodes.push_back(node.id());
}
}
if (!lockedNodes.empty()) {
Utils::sort(lockedNodes);
QString detailedText = QString("<b>" + tr("Locked items:") + "</b><br>");
for (const auto &id : qAsConst(lockedNodes))
detailedText.append("- " + id + "<br>");
detailedText.chop(QString("<br>").size());
QMessageBox msgBox;
msgBox.setTextFormat(Qt::RichText);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("Delete/Cut Item"));
msgBox.setText(QString(tr("Deleting or cutting this item will modify locked items.") + "<br><br>%1")
.arg(detailedText));
msgBox.setInformativeText(tr("Do you want to continue by removing the item (Delete) or removing it and copying it to the clipboard (Cut)?"));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Ok);
if (msgBox.exec() == QMessageBox::Cancel)
return;
}
rewriterView()->executeInTransaction("DesignDocument::deleteSelected", [this](){
QList<ModelNode> toDelete = view()->selectedModelNodes();
foreach (ModelNode node, toDelete) {
for (ModelNode node : toDelete) {
if (node.isValid() && !node.isRootNode() && QmlObjectNode::isValidQmlObjectNode(node))
QmlObjectNode(node).destroy();
}
@@ -545,7 +579,7 @@ void DesignDocument::paste()
}
view.setSelectedModelNodes({pastedNode});
});
NodeMetaInfo::clearCache();
view.model()->clearMetaInfoCache();
}
}

View File

@@ -7,6 +7,7 @@ qtHaveModule(quick3dassetimport) {
# Input
HEADERS += itemlibraryview.h \
$$PWD/itemlibraryiconimageprovider.h \
itemlibrarywidget.h \
itemlibrarymodel.h \
itemlibraryresourceview.h \
@@ -19,6 +20,7 @@ HEADERS += itemlibraryview.h \
customfilesystemmodel.h
SOURCES += itemlibraryview.cpp \
$$PWD/itemlibraryiconimageprovider.cpp \
itemlibrarywidget.cpp \
itemlibrarymodel.cpp \
itemlibraryresourceview.cpp \

View File

@@ -502,7 +502,6 @@ bool ItemLibraryAssetImporter::generateComponentIcon(int size, const QString &ic
QProcessUniquePointer process = puppetCreator.createPuppetProcess(
"custom",
{},
this,
std::function<void()>(),
[&](int exitCode, QProcess::ExitStatus exitStatus) {
processFinished(exitCode, exitStatus);

View File

@@ -0,0 +1,93 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "itemlibraryiconimageprovider.h"
#include <projectexplorer/target.h>
#include <utils/stylehelper.h>
#include <QMetaObject>
#include <QQuickImageResponse>
namespace QmlDesigner {
class ImageRespose : public QQuickImageResponse
{
public:
QQuickTextureFactory *textureFactory() const override
{
return QQuickTextureFactory::textureFactoryForImage(m_image);
}
void setImage(const QImage &image)
{
m_image = image;
emit finished();
}
void abort()
{
m_image = QImage{
Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/item-default-icon.png")};
emit finished();
}
private:
QImage m_image;
};
QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QString &id,
const QSize &)
{
auto response = std::make_unique<ImageRespose>();
m_cache.requestIcon(
id,
[response = QPointer<ImageRespose>(response.get())](const QImage &image) {
QMetaObject::invokeMethod(
response,
[response, image] {
if (response)
response->setImage(image);
},
Qt::QueuedConnection);
},
[response = QPointer<ImageRespose>(response.get())] {
QMetaObject::invokeMethod(
response,
[response] {
if (response)
response->abort();
},
Qt::QueuedConnection);
});
return response.release();
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <nodeinstanceview.h>
#include <rewriterview.h>
#include <coreplugin/icore.h>
#include <imagecache.h>
#include <imagecache/imagecachecollector.h>
#include <imagecache/imagecacheconnectionmanager.h>
#include <imagecache/imagecachegenerator.h>
#include <imagecache/imagecachestorage.h>
#include <imagecache/timestampprovider.h>
#include <sqlitedatabase.h>
#include <QQuickAsyncImageProvider>
namespace QmlDesigner {
class ItemLibraryIconImageProvider : public QQuickAsyncImageProvider
{
public:
ItemLibraryIconImageProvider(ImageCache &imageCache)
: m_cache{imageCache}
{}
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
private:
ImageCache &m_cache;
};
} // namespace QmlDesigner

View File

@@ -47,8 +47,18 @@ QString ItemLibraryItem::typeName() const
QString ItemLibraryItem::itemLibraryIconPath() const
{
//Prepend image provider prefix
return QStringLiteral("image://qmldesigner_itemlibrary/") + m_itemLibraryEntry.libraryEntryIconPath();
if (m_itemLibraryEntry.customComponentSource().isEmpty()) {
return QStringLiteral("image://qmldesigner_itemlibrary/")
+ m_itemLibraryEntry.libraryEntryIconPath();
} else {
return QStringLiteral("image://itemlibrary_preview/")
+ m_itemLibraryEntry.customComponentSource();
}
}
QString ItemLibraryItem::componentPath() const
{
return m_itemLibraryEntry.customComponentSource();
}
bool ItemLibraryItem::setVisible(bool isVisible)

View File

@@ -42,6 +42,7 @@ class ItemLibraryItem: public QObject {
Q_PROPERTY(QString itemName READ itemName FINAL)
Q_PROPERTY(QString itemLibraryIconPath READ itemLibraryIconPath FINAL)
Q_PROPERTY(bool itemVisible READ isVisible NOTIFY visibilityChanged FINAL)
Q_PROPERTY(QString componentPath READ componentPath FINAL)
public:
ItemLibraryItem(QObject *parent);
@@ -50,6 +51,7 @@ public:
QString itemName() const;
QString typeName() const;
QString itemLibraryIconPath() const;
QString componentPath() const;
bool setVisible(bool isVisible);
bool isVisible() const;

View File

@@ -29,6 +29,8 @@
#include "itemlibraryitem.h"
#include "itemlibrarysection.h"
#include <components/previewtooltip/previewtooltipbackend.h>
#include <model.h>
#include <nodehints.h>
#include <nodemetainfo.h>

View File

@@ -25,24 +25,47 @@
#include "itemlibraryview.h"
#include "itemlibrarywidget.h"
#include "metainfo.h"
#include <bindingproperty.h>
#include <coreplugin/icore.h>
#include <imagecache.h>
#include <imagecache/imagecachecollector.h>
#include <imagecache/imagecacheconnectionmanager.h>
#include <imagecache/imagecachegenerator.h>
#include <imagecache/imagecachestorage.h>
#include <imagecache/timestampprovider.h>
#include <import.h>
#include <importmanagerview.h>
#include <qmlitemnode.h>
#include <rewriterview.h>
#include <bindingproperty.h>
#include <nodelistproperty.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/target.h>
#include <rewriterview.h>
#include <sqlitedatabase.h>
#include <utils/algorithm.h>
#include <qmldesignerplugin.h>
#include "metainfo.h"
#include <qmlitemnode.h>
namespace QmlDesigner {
class ImageCacheData
{
public:
Sqlite::Database database{
Utils::PathString{Core::ICore::cacheResourcePath() + "/imagecache-v1.db"}};
ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager};
ImageCacheGenerator generator{collector, storage};
TimeStampProvider timeStampProvider;
ImageCache cache{storage, generator, timeStampProvider};
};
ItemLibraryView::ItemLibraryView(QObject* parent)
: AbstractView(parent),
m_importManagerView(new ImportManagerView(this))
{
m_imageCacheData = std::make_unique<ImageCacheData>();
}
ItemLibraryView::~ItemLibraryView() = default;
@@ -55,7 +78,7 @@ bool ItemLibraryView::hasWidget() const
WidgetInfo ItemLibraryView::widgetInfo()
{
if (m_widget.isNull()) {
m_widget = new ItemLibraryWidget;
m_widget = new ItemLibraryWidget{m_imageCacheData->cache};
m_widget->setImportsWidget(m_importManagerView->widgetInfo().widget);
}
@@ -70,6 +93,16 @@ WidgetInfo ItemLibraryView::widgetInfo()
void ItemLibraryView::modelAttached(Model *model)
{
AbstractView::modelAttached(model);
auto target = QmlDesignerPlugin::instance()->currentDesignDocument()->currentTarget();
m_imageCacheData->cache.clean();
if (target) {
auto clonedTarget = std::make_unique<ProjectExplorer::Target>(
target->project(), target->kit()->clone(), ProjectExplorer::Target::_constructor_tag{});
m_imageCacheData->collector.setTarget(std::move(clonedTarget));
}
m_widget->clearSearchFilter();
m_widget->setModel(model);
updateImports();
@@ -83,6 +116,8 @@ void ItemLibraryView::modelAboutToBeDetached(Model *model)
{
model->detachView(m_importManagerView);
m_imageCacheData->collector.setTarget({});
AbstractView::modelAboutToBeDetached(model);
m_widget->setModel(nullptr);
@@ -124,7 +159,7 @@ void ItemLibraryView::importsChanged(const QList<Import> &addedImports, const QL
void ItemLibraryView::setResourcePath(const QString &resourcePath)
{
if (m_widget.isNull())
m_widget = new ItemLibraryWidget;
m_widget = new ItemLibraryWidget{m_imageCacheData->cache};
m_widget->setResourcePath(resourcePath);
}
@@ -142,4 +177,4 @@ void ItemLibraryView::updateImports()
m_widget->delayedUpdateModel();
}
} //QmlDesigner
} // namespace QmlDesigner

View File

@@ -34,6 +34,7 @@ namespace QmlDesigner {
class ItemLibraryWidget;
class ImportManagerView;
class ImageCacheData;
class ItemLibraryView : public AbstractView
{
@@ -58,6 +59,7 @@ protected:
void updateImports();
private:
std::unique_ptr<ImageCacheData> m_imageCacheData;
QPointer<ItemLibraryWidget> m_widget;
ImportManagerView *m_importManagerView;
bool m_hasErrors = false;

View File

@@ -27,19 +27,21 @@
#include "customfilesystemmodel.h"
#include "itemlibraryassetimportdialog.h"
#include "itemlibraryiconimageprovider.h"
#include <theme.h>
#include <itemlibrarymodel.h>
#include <itemlibraryimageprovider.h>
#include <itemlibraryinfo.h>
#include <metainfo.h>
#include <model.h>
#include <rewritingexception.h>
#include <qmldesignerplugin.h>
#include <qmldesignerconstants.h>
#include <designeractionmanager.h>
#include <designermcumanager.h>
#include <itemlibraryimageprovider.h>
#include <itemlibraryinfo.h>
#include <itemlibrarymodel.h>
#include <metainfo.h>
#include <model.h>
#include <previewtooltip/previewtooltipbackend.h>
#include <rewritingexception.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
#include <utils/algorithm.h>
#include <utils/flowlayout.h>
@@ -81,14 +83,14 @@ static QString propertyEditorResourcesPath() {
return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/propertyEditorQmlSources");
}
ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
QFrame(parent),
m_itemIconSize(24, 24),
m_itemViewQuickWidget(new QQuickWidget(this)),
m_resourcesView(new ItemLibraryResourceView(this)),
m_importTagsWidget(new QWidget(this)),
m_addResourcesWidget(new QWidget(this)),
m_filterFlag(QtBasic)
ItemLibraryWidget::ItemLibraryWidget(ImageCache &imageCache)
: m_itemIconSize(24, 24)
, m_itemViewQuickWidget(new QQuickWidget(this))
, m_resourcesView(new ItemLibraryResourceView(this))
, m_importTagsWidget(new QWidget(this))
, m_addResourcesWidget(new QWidget(this))
, m_imageCache{imageCache}
, m_filterFlag(QtBasic)
{
m_compressionTimer.setInterval(200);
m_compressionTimer.setSingleShot(true);
@@ -102,16 +104,20 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
m_itemViewQuickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_itemLibraryModel = new ItemLibraryModel(this);
m_itemViewQuickWidget->rootContext()->setContextProperties(
QVector<QQmlContext::PropertyPair>{
{{"itemLibraryModel"}, QVariant::fromValue(m_itemLibraryModel.data())},
{{"itemLibraryIconWidth"}, m_itemIconSize.width()},
{{"itemLibraryIconHeight"}, m_itemIconSize.height()},
{{"rootView"}, QVariant::fromValue(this)},
{{"highlightColor"}, Utils::StyleHelper::notTooBrightHighlightColor()}
}
);
m_itemViewQuickWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
m_itemViewQuickWidget->rootContext()->setContextProperties(QVector<QQmlContext::PropertyPair>{
{{"itemLibraryModel"}, QVariant::fromValue(m_itemLibraryModel.data())},
{{"itemLibraryIconWidth"}, m_itemIconSize.width()},
{{"itemLibraryIconHeight"}, m_itemIconSize.height()},
{{"rootView"}, QVariant::fromValue(this)},
{{"highlightColor"}, Utils::StyleHelper::notTooBrightHighlightColor()},
});
m_previewTooltipBackend = std::make_unique<PreviewTooltipBackend>(m_imageCache);
m_itemViewQuickWidget->rootContext()->setContextProperty("tooltipBackend",
m_previewTooltipBackend.get());
m_itemViewQuickWidget->setClearColor(
Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
/* create Resources view and its model */
m_resourcesFileSystemModel = new CustomFileSystemModel(this);
@@ -119,6 +125,7 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
/* create image provider for loading item icons */
m_itemViewQuickWidget->engine()->addImageProvider(QStringLiteral("qmldesigner_itemlibrary"), new Internal::ItemLibraryImageProvider);
Theme::setupTheme(m_itemViewQuickWidget->engine());
/* other widgets */
@@ -243,6 +250,8 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
reloadQmlSource();
}
ItemLibraryWidget::~ItemLibraryWidget() = default;
void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo)
{
if (m_itemLibraryInfo.data() == itemLibraryInfo)
@@ -306,9 +315,14 @@ void ItemLibraryWidget::delayedUpdateModel()
void ItemLibraryWidget::setModel(Model *model)
{
m_itemViewQuickWidget->engine()->removeImageProvider("itemlibrary_preview");
m_model = model;
if (!model)
return;
m_itemViewQuickWidget->engine()->addImageProvider("itemlibrary_preview",
new ItemLibraryIconImageProvider{m_imageCache});
setItemLibraryInfo(model->metaInfo().itemLibraryInfo());
}
@@ -318,7 +332,8 @@ void ItemLibraryWidget::setCurrentIndexOfStackedWidget(int index)
m_filterLineEdit->setVisible(false);
m_importTagsWidget->setVisible(true);
m_addResourcesWidget->setVisible(false);
} if (index == 1) {
}
if (index == 1) {
m_filterLineEdit->setVisible(true);
m_importTagsWidget->setVisible(false);
m_addResourcesWidget->setVisible(true);
@@ -564,5 +579,4 @@ void ItemLibraryWidget::addResources()
}
}
}
}
} // namespace QmlDesigner

View File

@@ -37,6 +37,8 @@
#include <QQmlPropertyMap>
#include <QTimer>
#include <memory>
QT_BEGIN_NAMESPACE
class QStackedWidget;
class QShortcut;
@@ -52,6 +54,9 @@ class CustomFileSystemModel;
class ItemLibraryModel;
class ItemLibraryResourceView;
class PreviewTooltipBackend;
class ImageCache;
class ImageCacheCollector;
class ItemLibraryWidget : public QFrame
{
@@ -63,7 +68,8 @@ class ItemLibraryWidget : public QFrame
};
public:
ItemLibraryWidget(QWidget *parent = nullptr);
ItemLibraryWidget(ImageCache &imageCache);
~ItemLibraryWidget();
void setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo);
QList<QToolButton *> createToolBarWidgets();
@@ -115,9 +121,10 @@ private:
QScopedPointer<ItemLibraryResourceView> m_resourcesView;
QScopedPointer<QWidget> m_importTagsWidget;
QScopedPointer<QWidget> m_addResourcesWidget;
std::unique_ptr<PreviewTooltipBackend> m_previewTooltipBackend;
QShortcut *m_qmlSourceUpdateShortcut;
ImageCache &m_imageCache;
QPointer<Model> m_model;
FilterChangeFlag m_filterFlag;
ItemLibraryEntry m_currentitemLibraryEntry;

View File

@@ -82,6 +82,12 @@ void IconCheckboxItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &styleOption,
const QModelIndex &modelIndex) const
{
bool isVisibilityIcon = modelIndex.column() != NavigatorTreeModel::ColumnType::Visibility;
// We need to invert the check status if visibility icon
bool checked = isVisibilityIcon ? isChecked(modelIndex) : !isChecked(modelIndex);
if (!(styleOption.state & QStyle::State_MouseOver) && !checked)
return;
if (rowIsPropertyRole(modelIndex.model(), modelIndex))
return; //Do not paint icons for property rows

View File

@@ -200,10 +200,10 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
if (!modelNode.isValid())
return QVariant();
if (role == ItemIsVisibleRole) //independent of column
if (role == ItemIsVisibleRole) // independent of column
return m_view->isNodeInvisible(modelNode) ? Qt::Unchecked : Qt::Checked;
if (index.column() == 0) {
if (index.column() == ColumnType::Name) {
if (role == Qt::DisplayRole) {
return modelNode.displayName();
} else if (role == Qt::DecorationRole) {
@@ -240,18 +240,24 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
} else if (role == ModelNodeRole) {
return QVariant::fromValue<ModelNode>(modelNode);
}
} else if (index.column() == 1) { //export
} else if (index.column() == ColumnType::Alias) { // export
if (role == Qt::CheckStateRole)
return currentQmlObjectNode.isAliasExported() ? Qt::Checked : Qt::Unchecked;
return currentQmlObjectNode.isAliasExported() ? Qt::Checked : Qt::Unchecked;
else if (role == Qt::ToolTipRole)
return tr("Toggles whether this item is exported as an "
"alias property of the root item.");
} else if (index.column() == 2) { //visible
} else if (index.column() == ColumnType::Visibility) { // visible
if (role == Qt::CheckStateRole)
return m_view->isNodeInvisible(modelNode) ? Qt::Unchecked : Qt::Checked;
else if (role == Qt::ToolTipRole)
return tr("Toggles the visibility of this item in the form editor.\n"
"This is independent of the visibility property in QML.");
} else if (index.column() == ColumnType::Lock) { // lock
if (role == Qt::CheckStateRole)
return modelNode.locked() ? Qt::Checked : Qt::Unchecked;
else if (role == Qt::ToolTipRole)
return tr("Toggles whether this item is locked.\n"
"Locked items can't be modified or selected.");
}
return QVariant();
@@ -259,7 +265,16 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
Qt::ItemFlags NavigatorTreeModel::flags(const QModelIndex &index) const
{
if (index.column() == 0)
if (index.column() == ColumnType::Alias
|| index.column() == ColumnType::Visibility
|| index.column() == ColumnType::Lock)
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren;
const ModelNode modelNode = modelNodeForIndex(index);
if (ModelNode::isThisOrAncestorLocked(modelNode))
return Qt::NoItemFlags;
if (index.column() == ColumnType::Name)
return Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable
@@ -378,7 +393,7 @@ int NavigatorTreeModel::columnCount(const QModelIndex &parent) const
if (parent.column() > 0)
return 0;
return 3;
return ColumnType::Count;
}
ModelNode NavigatorTreeModel::modelNodeForIndex(const QModelIndex &index) const
@@ -755,7 +770,8 @@ void NavigatorTreeModel::moveNodesInteractive(NodeAbstractProperty &parentProper
auto doMoveNodesInteractive = [&parentProperty, modelNodes, targetIndex](){
const TypeName propertyQmlType = parentProperty.parentModelNode().metaInfo().propertyTypeName(parentProperty.name());
foreach (const ModelNode &modelNode, modelNodes) {
int idx = targetIndex;
for (const ModelNode &modelNode : modelNodes) {
if (modelNode.isValid()
&& modelNode != parentProperty.parentModelNode()
&& !modelNode.isAncestorOf(parentProperty.parentModelNode())
@@ -764,10 +780,9 @@ void NavigatorTreeModel::moveNodesInteractive(NodeAbstractProperty &parentProper
//once the MetaInfo is part of instances we can do this right
bool nodeCanBeMovedToParentProperty = removeModelNodeFromNodeProperty(parentProperty, modelNode);
if (nodeCanBeMovedToParentProperty) {
reparentModelNodeToNodeProperty(parentProperty, modelNode);
slideModelNodeInList(parentProperty, modelNode, targetIndex);
slideModelNodeInList(parentProperty, modelNode, idx++);
}
}
}
@@ -792,11 +807,13 @@ Qt::DropActions NavigatorTreeModel::supportedDragActions() const
bool NavigatorTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
ModelNode modelNode = modelNodeForIndex(index);
if (index.column() == 1 && role == Qt::CheckStateRole) {
if (index.column() == ColumnType::Alias && role == Qt::CheckStateRole) {
QTC_ASSERT(m_view, return false);
m_view->handleChangedExport(modelNode, value.toInt() != 0);
} else if (index.column() == 2 && role == Qt::CheckStateRole) {
} else if (index.column() == ColumnType::Visibility && role == Qt::CheckStateRole) {
QmlVisualNode(modelNode).setVisibilityOverride(value.toInt() == 0);
} else if (index.column() == ColumnType::Lock && role == Qt::CheckStateRole) {
modelNode.setLocked(value.toInt() != 0);
}
return true;
@@ -806,7 +823,7 @@ void NavigatorTreeModel::notifyDataChanged(const ModelNode &modelNode)
{
const QModelIndex index = indexForModelNode(modelNode);
const QAbstractItemModel *model = index.model();
const QModelIndex sibling = model ? model->sibling(index.row(), 2, index) : QModelIndex();
const QModelIndex sibling = model ? model->sibling(index.row(), ColumnType::Count - 1, index) : QModelIndex();
emit dataChanged(index, sibling);
}

View File

@@ -49,6 +49,14 @@ class NavigatorTreeModel : public QAbstractItemModel, public NavigatorModelInter
public:
enum ColumnType {
Name = 0,
Alias,
Visibility,
Lock,
Count
};
explicit NavigatorTreeModel(QObject *parent = nullptr);
~NavigatorTreeModel() override;

View File

@@ -168,6 +168,7 @@ NavigatorTreeView::NavigatorTreeView(QWidget *parent)
setMinimumWidth(240);
setRootIsDecorated(false);
setIndentation(indentation() * 0.5);
viewport()->setAttribute(Qt::WA_Hover);
m_toolTipHideTimer.setSingleShot(true);
connect(&m_toolTipHideTimer, &QTimer::timeout, [this]() {

View File

@@ -41,6 +41,7 @@
#include <qmlitemnode.h>
#include <rewritingexception.h>
#include <nodeinstanceview.h>
#include <theme.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
@@ -48,6 +49,7 @@
#include <utils/algorithm.h>
#include <utils/icon.h>
#include <utils/utilsicons.h>
#include <utils/stylehelper.h>
#include <QHeaderView>
#include <QTimer>
@@ -138,13 +140,14 @@ void NavigatorView::modelAttached(Model *model)
QTreeView *treeView = treeWidget();
treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
treeView->header()->resizeSection(1,26);
treeView->header()->setSectionResizeMode(NavigatorTreeModel::ColumnType::Name, QHeaderView::Stretch);
treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Alias, 26);
treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Visibility, 26);
treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Lock, 26);
treeView->setIndentation(20);
m_currentModelInterface->setFilter(false);
QTimer::singleShot(0, this, [this, treeView]() {
m_currentModelInterface->setFilter(
DesignerSettings::getValue(DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS).toBool());
@@ -166,10 +169,6 @@ void NavigatorView::modelAttached(Model *model)
}
}
});
#ifdef _LOCK_ITEMS_
treeView->header()->resizeSection(2,20);
#endif
}
void NavigatorView::modelAboutToBeDetached(Model *model)
@@ -304,7 +303,7 @@ void NavigatorView::nodeIdChanged(const ModelNode& modelNode, const QString & /*
m_currentModelInterface->notifyDataChanged(modelNode);
}
void NavigatorView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& /*propertyList*/)
void NavigatorView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &/*propertyList*/)
{
}
@@ -321,7 +320,7 @@ void NavigatorView::propertiesRemoved(const QList<AbstractProperty> &propertyLis
m_currentModelInterface->notifyModelNodesRemoved(modelNodes);
}
void NavigatorView::rootNodeTypeChanged(const QString & /*type*/, int /*majorVersion*/, int /*minorVersion*/)
void NavigatorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/)
{
m_currentModelInterface->notifyDataChanged(rootModelNode());
}
@@ -332,9 +331,12 @@ void NavigatorView::nodeTypeChanged(const ModelNode &modelNode, const TypeName &
}
void NavigatorView::auxiliaryDataChanged(const ModelNode &modelNode,
const PropertyName & /*name*/,
const QVariant & /*data*/)
const PropertyName &name,
const QVariant &data)
{
Q_UNUSED(name)
Q_UNUSED(data)
m_currentModelInterface->notifyDataChanged(modelNode);
}
@@ -344,8 +346,8 @@ void NavigatorView::instanceErrorChanged(const QVector<ModelNode> &errorNodeList
m_currentModelInterface->notifyDataChanged(modelNode);
}
void NavigatorView::nodeOrderChanged(const NodeListProperty & listProperty,
const ModelNode & /*node*/,
void NavigatorView::nodeOrderChanged(const NodeListProperty &listProperty,
const ModelNode &/*node*/,
int /*oldIndex*/)
{
m_currentModelInterface->notifyModelNodesMoved(listProperty.directSubNodes());
@@ -613,33 +615,50 @@ void NavigatorView::setupWidget()
connect(m_widget.data(), &NavigatorWidget::reverseOrderToggled, this, &NavigatorView::reverseOrderToggled);
#ifndef QMLDESIGNER_TEST
const QString fontName = "qtds_propertyIconFont.ttf";
const QIcon visibilityOnIcon =
Utils::StyleHelper::getIconFromIconFont(fontName,
Theme::getIconUnicode(Theme::Icon::visibilityOn),
28, 28, QColor(Qt::white));
const QIcon visibilityOffIcon =
Utils::StyleHelper::getIconFromIconFont(fontName,
Theme::getIconUnicode(Theme::Icon::visibilityOff),
28, 28, QColor(Qt::white));
const QIcon aliasOnIcon =
Utils::StyleHelper::getIconFromIconFont(fontName,
Theme::getIconUnicode(Theme::Icon::idAliasOn),
28, 28, QColor(Qt::red));
const QIcon aliasOffIcon =
Utils::StyleHelper::getIconFromIconFont(fontName,
Theme::getIconUnicode(Theme::Icon::idAliasOff),
28, 28, QColor(Qt::white));
const QIcon lockOnIcon =
Utils::StyleHelper::getIconFromIconFont(fontName,
Theme::getIconUnicode(Theme::Icon::lockOn),
28, 28, QColor(Qt::white));
const QIcon lockOffIcon =
Utils::StyleHelper::getIconFromIconFont(fontName,
Theme::getIconUnicode(Theme::Icon::lockOff),
28, 28, QColor(Qt::white));
auto idDelegate = new NameItemDelegate(this);
IconCheckboxItemDelegate *showDelegate =
new IconCheckboxItemDelegate(this,
Utils::Icons::EYE_OPEN_TOOLBAR.icon(),
Utils::Icons::EYE_CLOSED_TOOLBAR.icon());
IconCheckboxItemDelegate *exportDelegate =
new IconCheckboxItemDelegate(this,
Icons::EXPORT_CHECKED.icon(),
Icons::EXPORT_UNCHECKED.icon());
IconCheckboxItemDelegate *visibilityDelegate =
new IconCheckboxItemDelegate(this, visibilityOnIcon, visibilityOffIcon);
IconCheckboxItemDelegate *aliasDelegate =
new IconCheckboxItemDelegate(this, aliasOnIcon, aliasOffIcon);
#ifdef _LOCK_ITEMS_
IconCheckboxItemDelegate *lockDelegate =
new IconCheckboxItemDelegate(this,
Utils::Icons::LOCKED_TOOLBAR.icon(),
Utils::Icons::UNLOCKED_TOOLBAR.icon());
#endif
new IconCheckboxItemDelegate(this, lockOnIcon, lockOffIcon);
treeWidget()->setItemDelegateForColumn(0, idDelegate);
#ifdef _LOCK_ITEMS_
treeWidget()->setItemDelegateForColumn(1,lockDelegate);
treeWidget()->setItemDelegateForColumn(2,showDelegate);
#else
treeWidget()->setItemDelegateForColumn(1, exportDelegate);
treeWidget()->setItemDelegateForColumn(2, showDelegate);
#endif
treeWidget()->setItemDelegateForColumn(NavigatorTreeModel::ColumnType::Name, idDelegate);
treeWidget()->setItemDelegateForColumn(NavigatorTreeModel::ColumnType::Alias, aliasDelegate);
treeWidget()->setItemDelegateForColumn(NavigatorTreeModel::ColumnType::Visibility, visibilityDelegate);
treeWidget()->setItemDelegateForColumn(NavigatorTreeModel::ColumnType::Lock, lockDelegate);
#endif //QMLDESIGNER_TEST
}

View File

@@ -82,7 +82,7 @@ public:
void propertiesRemoved(const QList<AbstractProperty>& propertyList) override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList ,
const QList<ModelNode> &lastSelectedNodeList) override;
const QList<ModelNode> &lastSelectedNodeList) override;
void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
void instanceErrorChanged(const QVector<ModelNode> &errorNodeList) override;

View File

@@ -78,7 +78,7 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view)
#endif
}
void NavigatorWidget::setTreeModel(QAbstractItemModel* model)
void NavigatorWidget::setTreeModel(QAbstractItemModel *model)
{
m_treeView->setModel(model);
}
@@ -92,7 +92,6 @@ QList<QToolButton *> NavigatorWidget::createToolBarWidgets()
{
QList<QToolButton *> buttons;
auto button = new QToolButton();
button->setIcon(Icons::ARROW_LEFT.icon());
button->setToolTip(tr("Become last sibling of parent (CTRL + Left)."));
@@ -180,7 +179,6 @@ void NavigatorWidget::enableNavigator()
m_treeView->setEnabled(true);
}
NavigatorView *NavigatorWidget::navigatorView() const
{
return m_navigatorView.data();

View File

@@ -82,12 +82,6 @@
</property>
<item>
<widget class="QLabel" name="imageLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
@@ -100,9 +94,6 @@
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string notr="true">&lt;image&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>

View File

@@ -0,0 +1,63 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "previewimagetooltip.h"
#include "ui_previewimagetooltip.h"
#include <utils/theme/theme.h>
#include <QtGui/qpixmap.h>
namespace QmlDesigner {
PreviewImageTooltip::PreviewImageTooltip(QWidget *parent)
: QWidget(parent)
, m_ui(std::make_unique<Ui::PreviewImageTooltip>())
{
// setAttribute(Qt::WA_TransparentForMouseEvents);
setWindowFlags(Qt::ToolTip);
m_ui->setupUi(this);
setStyleSheet(QString("QWidget { background-color: %1 }").arg(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal).name()));
}
PreviewImageTooltip::~PreviewImageTooltip() = default;
void PreviewImageTooltip::setComponentPath(const QString &path)
{
m_ui->componentPathLabel->setText(path);
}
void PreviewImageTooltip::setComponentName(const QString &name)
{
m_ui->componentNameLabel->setText(name);
}
void PreviewImageTooltip::setImage(const QImage &image)
{
resize(image.width() + 20 + m_ui->componentNameLabel->width(),
std::max(image.height() + 20, height()));
m_ui->imageLabel->setPixmap(QPixmap::fromImage({image}));
}
}

View File

@@ -0,0 +1,53 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QtWidgets/qwidget.h>
#include <QtGui/qpixmap.h>
#include <memory>
namespace QmlDesigner {
namespace Ui {
class PreviewImageTooltip;
}
class PreviewImageTooltip : public QWidget
{
Q_OBJECT
public:
explicit PreviewImageTooltip(QWidget *parent = {});
~PreviewImageTooltip();
void setComponentPath(const QString &path);
void setComponentName(const QString &name);
void setImage(const QImage &pixmap);
private:
std::unique_ptr<Ui::PreviewImageTooltip> m_ui;
};
}

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QmlDesigner::PreviewImageTooltip</class>
<widget class="QWidget" name="QmlDesigner::PreviewImageTooltip">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>1000</width>
<height>1000</height>
</size>
</property>
<property name="windowTitle">
<string/>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="sizeGripEnabled" stdset="0">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QLabel" name="componentPathLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="2">
<widget class="QLabel" name="imageLabel">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Utils::ElidingLabel" name="componentNameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Utils::ElidingLabel</class>
<extends>QLabel</extends>
<header location="global">utils/elidinglabel.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,110 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "previewtooltipbackend.h"
#include "previewimagetooltip.h"
#include <coreplugin/icore.h>
#include <imagecache.h>
#include <QApplication>
#include <QDesktopWidget>
#include <QMetaObject>
namespace QmlDesigner {
PreviewTooltipBackend::PreviewTooltipBackend(ImageCache &cache)
: m_cache{cache}
{}
PreviewTooltipBackend::~PreviewTooltipBackend()
{
hideTooltip();
}
void PreviewTooltipBackend::showTooltip()
{
if (m_componentPath.isEmpty())
return;
m_tooltip = std::make_unique<PreviewImageTooltip>();
m_tooltip->setComponentName(m_componentName);
m_tooltip->setComponentPath(m_componentPath);
m_cache.requestImage(
m_componentPath,
[tooltip = QPointer<PreviewImageTooltip>(m_tooltip.get())](const QImage &image) {
QMetaObject::invokeMethod(tooltip, [tooltip, image] {
if (tooltip)
tooltip->setImage(image);
});
},
[] {});
auto desktopWidget = QApplication::desktop();
auto mousePosition = desktopWidget->cursor().pos();
mousePosition += {20, 20};
m_tooltip->move(mousePosition);
m_tooltip->show();
}
void PreviewTooltipBackend::hideTooltip()
{
if (m_tooltip)
m_tooltip->hide();
m_tooltip.reset();
}
QString QmlDesigner::PreviewTooltipBackend::componentPath() const
{
return m_componentPath;
}
void QmlDesigner::PreviewTooltipBackend::setComponentPath(const QString &path)
{
m_componentPath = path;
if (m_componentPath != path)
emit componentPathChanged();
}
QString QmlDesigner::PreviewTooltipBackend::componentName() const
{
return m_componentName;
}
void QmlDesigner::PreviewTooltipBackend::setComponentName(const QString &name)
{
m_componentName = name;
if (m_componentName != name)
emit componentNameChanged();
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,71 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QObject>
#include <QQmlEngine>
#include <memory>
namespace QmlDesigner {
class PreviewImageTooltip;
class ImageCache;
class PreviewTooltipBackend : public QObject
{
Q_OBJECT
Q_PROPERTY(QString componentPath READ componentPath WRITE setComponentPath NOTIFY componentPathChanged)
Q_PROPERTY(QString componentName READ componentName WRITE setComponentName NOTIFY componentNameChanged)
public:
PreviewTooltipBackend(ImageCache &cache);
~PreviewTooltipBackend();
Q_INVOKABLE void showTooltip();
Q_INVOKABLE void hideTooltip();
QString componentPath() const;
void setComponentPath(const QString &path);
QString componentName() const;
void setComponentName(const QString &path);
signals:
void componentPathChanged();
void componentNameChanged();
private:
QString m_componentPath;
QString m_componentName;
std::unique_ptr<PreviewImageTooltip> m_tooltip;
ImageCache &m_cache;
};
}
QML_DECLARE_TYPE(QmlDesigner::PreviewTooltipBackend)

View File

@@ -0,0 +1,11 @@
HEADERS += \
$$PWD/previewtooltipbackend.h \
$$PWD/previewimagetooltip.h
SOURCES += \
$$PWD/previewtooltipbackend.cpp \
$$PWD/previewimagetooltip.cpp
FORMS += $$PWD/previewimagetooltip.ui

View File

@@ -29,15 +29,21 @@
#include <model.h>
#include <utils/algorithm.h>
#include <QFileDialog>
#include <QDirIterator>
#include <qmlmodelnodeproxy.h>
static QString s_lastBrowserPath;
FileResourcesModel::FileResourcesModel(QObject *parent) :
QObject(parent), m_filter(QLatin1String("(*.*)")), m_lock(false)
FileResourcesModel::FileResourcesModel(QObject *parent)
: QObject(parent)
, m_filter(QLatin1String("(*.*)"))
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
{
connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged,
this, &FileResourcesModel::refreshModel);
}
void FileResourcesModel::setModelNodeBackend(const QVariant &modelNodeBackend)
@@ -163,7 +169,6 @@ QVariant FileResourcesModel::modelNodeBackend() const
bool filterMetaIcons(const QString &fileName)
{
QFileInfo info(fileName);
if (info.dir().path().split('/').contains("designer")) {
@@ -189,12 +194,20 @@ bool filterMetaIcons(const QString &fileName)
void FileResourcesModel::setupModel()
{
m_lock = true;
m_dirPath = QFileInfo(m_path.toLocalFile()).dir();
refreshModel();
m_fileSystemWatcher->removeDirectories(m_fileSystemWatcher->directories());
m_fileSystemWatcher->addDirectory(m_dirPath.absolutePath(),
Utils::FileSystemWatcher::WatchAllChanges);
}
void FileResourcesModel::refreshModel()
{
m_fullPathModel.clear();
m_fileNameModel.clear();
m_dirPath = QFileInfo(m_path.toLocalFile()).dir();
QStringList filterList = m_filter.split(QLatin1Char(' '));
QDirIterator it(m_dirPath.absolutePath(), filterList, QDir::Files, QDirIterator::Subdirectories);
@@ -203,11 +216,15 @@ void FileResourcesModel::setupModel()
if (filterMetaIcons(absolutePath)) {
QString filePath = m_dirPath.relativeFilePath(absolutePath);
m_fullPathModel.append(filePath);
m_fileNameModel.append(filePath.mid(filePath.lastIndexOf('/') + 1));
}
}
m_lock = false;
Utils::sort(m_fullPathModel, [](const QString &s1, const QString &s2) {
return s1.mid(s1.lastIndexOf('/') + 1).toLower() < s2.mid(s2.lastIndexOf('/') + 1).toLower();
});
for (const QString &fullPath : qAsConst(m_fullPathModel))
m_fileNameModel.append(fullPath.mid(fullPath.lastIndexOf('/') + 1));
emit fullPathModelChanged();
emit fileNameModelChanged();

View File

@@ -27,6 +27,8 @@
#include <qmlitemnode.h>
#include <utils/filesystemwatcher.h>
#include <QDir>
#include <QObject>
#include <QStringList>
@@ -60,6 +62,7 @@ public:
QStringList fullPathModel() const;
QStringList fileNameModel() const;
void setupModel();
void refreshModel();
Q_INVOKABLE void openFileDialog();
@@ -79,12 +82,11 @@ private:
QUrl m_path;
QDir m_dirPath;
QString m_filter;
bool m_lock;
QString m_currentPath;
QString m_lastModelPath;
QStringList m_fullPathModel;
QStringList m_fileNameModel;
Utils::FileSystemWatcher *m_fileSystemWatcher;
};
QML_DECLARE_TYPE(FileResourcesModel)

View File

@@ -30,6 +30,7 @@
#include <QDebug>
#include <QRegularExpression>
#include <QMessageBox>
#include <cmath>
#include <memory>
@@ -42,6 +43,7 @@
#include <qmlitemnode.h>
#include <qmlstate.h>
#include <annotationeditor/annotationeditor.h>
#include <utils/algorithm.h>
namespace QmlDesigner {
@@ -92,11 +94,46 @@ void StatesEditorView::removeState(int nodeId)
if (nodeId > 0 && hasModelNodeForInternalId(nodeId)) {
ModelNode stateNode(modelNodeForInternalId(nodeId));
Q_ASSERT(stateNode.metaInfo().isSubclassOf("QtQuick.State"));
QmlModelState modelState(stateNode);
if (modelState.isValid()) {
QStringList lockedTargets;
const auto propertyChanges = modelState.propertyChanges();
for (const QmlPropertyChanges &change : propertyChanges) {
const ModelNode target = change.target();
if (target.locked())
lockedTargets.push_back(target.id());
}
if (!lockedTargets.empty()) {
Utils::sort(lockedTargets);
QString detailedText = QString("<b>" + tr("Locked items:") + "</b><br>");
for (const auto &id : qAsConst(lockedTargets))
detailedText.append("- " + id + "<br>");
detailedText.chop(QString("<br>").size());
QMessageBox msgBox;
msgBox.setTextFormat(Qt::RichText);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("Remove State"));
msgBox.setText(QString(tr("Removing this state will modify locked items.") + "<br><br>%1")
.arg(detailedText));
msgBox.setInformativeText(tr("Do you want to continue by removing the state?"));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Ok);
if (msgBox.exec() == QMessageBox::Cancel)
return;
}
}
NodeListProperty parentProperty = stateNode.parentProperty().toNodeListProperty();
if (parentProperty.count() <= 1) {
setCurrentState(baseState());
} else if (parentProperty.isValid()){
} else if (parentProperty.isValid()) {
int index = parentProperty.indexOf(stateNode);
if (index == 0)
setCurrentState(parentProperty.at(1));
@@ -104,7 +141,6 @@ void StatesEditorView::removeState(int nodeId)
setCurrentState(parentProperty.at(index - 1));
}
stateNode.destroy();
}
} catch (const RewritingException &e) {

View File

@@ -63,6 +63,11 @@ TimelineGraphicsLayout::TimelineGraphicsLayout(TimelineGraphicsScene *scene, Tim
TimelineGraphicsLayout::~TimelineGraphicsLayout() = default;
int TimelineGraphicsLayout::zoom() const
{
return m_rulerItem->zoom();
}
double TimelineGraphicsLayout::rulerWidth() const
{
return m_rulerItem->preferredWidth();
@@ -133,12 +138,12 @@ void TimelineGraphicsLayout::setTimeline(const QmlTimeline &timeline)
if (auto *scene = timelineScene())
if (auto *view = scene->timelineView())
if (!timeline.isValid() && view->isAttached())
emit scaleFactorChanged(0);
emit zoomChanged(0);
}
void TimelineGraphicsLayout::setRulerScaleFactor(int factor)
void TimelineGraphicsLayout::setZoom(int factor)
{
m_rulerItem->setRulerScaleFactor(factor);
m_rulerItem->setZoom(factor);
}
void TimelineGraphicsLayout::invalidate()

View File

@@ -44,7 +44,7 @@ class TimelineGraphicsLayout : public TimelineItem
signals:
void rulerClicked(const QPointF &pos);
void scaleFactorChanged(int factor);
void zoomChanged(int factor);
public:
TimelineGraphicsLayout(TimelineGraphicsScene *scene, TimelineItem *parent = nullptr);
@@ -52,6 +52,8 @@ public:
~TimelineGraphicsLayout() override;
public:
int zoom() const;
double rulerWidth() const;
double rulerScaling() const;
@@ -66,7 +68,7 @@ public:
void setTimeline(const QmlTimeline &timeline);
void setRulerScaleFactor(int factor);
void setZoom(int factor);
void invalidate();

View File

@@ -123,9 +123,9 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *parent)
auto changeScale = [this](int factor) {
timelineWidget()->changeScaleFactor(factor);
setRulerScaling(qreal(factor));
setZoom(factor);
};
connect(m_layout, &TimelineGraphicsLayout::scaleFactorChanged, changeScale);
connect(m_layout, &TimelineGraphicsLayout::zoomChanged, changeScale);
}
TimelineGraphicsScene::~TimelineGraphicsScene()
@@ -144,7 +144,7 @@ void TimelineGraphicsScene::onShow()
setCurrentFrame(cf);
}
emit m_layout->scaleFactorChanged(0);
emit m_layout->zoomChanged(0);
}
}
@@ -271,6 +271,11 @@ void TimelineGraphicsScene::setEndFrame(int frame)
timeline.modelNode().variantProperty("endFrame").setValue(frame);
}
int TimelineGraphicsScene::zoom() const
{
return m_layout->zoom();
}
qreal TimelineGraphicsScene::rulerScaling() const
{
return m_layout->rulerScaling();
@@ -332,15 +337,20 @@ QVector<qreal> TimelineGraphicsScene::keyframePositions(const QmlTimelineKeyfram
return positions;
}
void TimelineGraphicsScene::setRulerScaling(int scaleFactor)
void TimelineGraphicsScene::setZoom(int scaleFactor)
{
setZoom(scaleFactor, currentFramePosition());
}
void TimelineGraphicsScene::setZoom(int scaleFactor, double pivot)
{
const qreal oldOffset = scrollOffset();
const qreal oldScaling = m_layout->rulerScaling();
const qreal oldPosition = mapToScene(currentFramePosition());
m_layout->setRulerScaleFactor(scaleFactor);
const qreal oldPosition = mapToScene(pivot);
m_layout->setZoom(scaleFactor);
const qreal newScaling = m_layout->rulerScaling();
const qreal newPosition = mapToScene(currentFramePosition());
const qreal newPosition = mapToScene(pivot);
const qreal newOffset = oldOffset + (newPosition - oldPosition);
@@ -428,6 +438,18 @@ void TimelineGraphicsScene::invalidateKeyframesForTarget(const ModelNode &target
TimelineSectionItem::updateFramesForTarget(child, target);
}
void TimelineGraphicsScene::invalidateHeightForTarget(const ModelNode &target)
{
if (!target.isValid())
return;
const auto children = m_layout->childItems();
for (auto child : children)
TimelineSectionItem::updateHeightForTarget(child, target);
invalidateLayout();
}
void TimelineGraphicsScene::invalidateScene()
{
ModelNode node = timelineView()->modelNodeForId(
@@ -502,7 +524,7 @@ QRectF AbstractScrollGraphicsScene::selectionBounds() const
}
void AbstractScrollGraphicsScene::selectKeyframes(const SelectionMode &mode,
const QList<TimelineKeyframeItem *> &items)
const QList<TimelineKeyframeItem *> &items)
{
if (mode == SelectionMode::Remove || mode == SelectionMode::Toggle) {
for (auto *item : items) {
@@ -731,7 +753,7 @@ void TimelineGraphicsScene::deleteKeyframeGroup(const ModelNode &group)
if (!QmlTimelineKeyframeGroup::isValidQmlTimelineKeyframeGroup(group))
return;
timelineView()->executeInTransaction("TimelineGraphicsScene::handleKeyframeGroupDeletion", [group](){
timelineView()->executeInTransaction("TimelineGraphicsScene::handleKeyframeGroupDeletion", [group]() {
ModelNode nonConst = group;
nonConst.destroy();
});
@@ -739,7 +761,7 @@ void TimelineGraphicsScene::deleteKeyframeGroup(const ModelNode &group)
void TimelineGraphicsScene::deleteKeyframes(const QList<ModelNode> &frames)
{
timelineView()->executeInTransaction("TimelineGraphicsScene::handleKeyframeDeletion", [frames](){
timelineView()->executeInTransaction("TimelineGraphicsScene::handleKeyframeDeletion", [frames]() {
for (auto keyframe : frames) {
if (keyframe.isValid()) {
ModelNode frame = keyframe;
@@ -764,7 +786,7 @@ AbstractView *TimelineGraphicsScene::abstractView() const
int AbstractScrollGraphicsScene::getScrollOffset(QGraphicsScene *scene)
{
auto scrollScene = qobject_cast<AbstractScrollGraphicsScene*>(scene);
auto scrollScene = qobject_cast<AbstractScrollGraphicsScene *>(scene);
if (scrollScene)
return scrollScene->scrollOffset();
return 0;

View File

@@ -58,7 +58,6 @@ class AbstractScrollGraphicsScene : public QGraphicsScene
public:
AbstractScrollGraphicsScene(QWidget *parent);
;
int scrollOffset() const;
void setScrollOffset(int offset);
@@ -74,6 +73,7 @@ public:
bool isKeyframeSelected(TimelineKeyframeItem *keyframe) const;
bool multipleKeyframesSelected() const;
virtual int zoom() const = 0;
virtual qreal rulerScaling() const = 0;
virtual int rulerWidth() const = 0;
virtual qreal rulerDuration() const = 0;
@@ -134,6 +134,7 @@ public:
TimelineWidget *timelineWidget() const;
TimelineToolBar *toolBar() const;
int zoom() const override;
qreal rulerScaling() const override;
int rulerWidth() const override;
qreal rulerDuration() const override;
@@ -152,12 +153,14 @@ public:
qreal snap(qreal frame, bool snapToPlayhead = true) override;
void setRulerScaling(int scaling);
void setZoom(int scaling);
void setZoom(int scaling, double pivot);
void commitCurrentFrame(qreal frame);
void invalidateSectionForTarget(const ModelNode &modelNode);
void invalidateKeyframesForTarget(const ModelNode &modelNode);
void invalidateHeightForTarget(const ModelNode &modelNode);
void invalidateScene();
void invalidateScrollbar() override;
@@ -203,7 +206,6 @@ private:
QList<QGraphicsItem *> itemsAt(const QPointF &pos);
private:
TimelineWidget *m_parent = nullptr;
TimelineGraphicsLayout *m_layout = nullptr;

View File

@@ -156,4 +156,9 @@ TimelineFrameHandle *TimelineMovableAbstractItem::asTimelineFrameHandle()
return nullptr;
}
bool TimelineMovableAbstractItem::isLocked() const
{
return false;
}
} // namespace QmlDesigner

View File

@@ -69,6 +69,8 @@ public:
virtual TimelineKeyframeItem *asTimelineKeyframeItem();
virtual TimelineFrameHandle *asTimelineFrameHandle();
virtual bool isLocked() const;
protected:
int scrollOffset() const;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;

View File

@@ -70,6 +70,9 @@ void TimelineMoveTool::mousePressEvent(TimelineMovableAbstractItem *item,
{
Q_UNUSED(item)
if (currentItem() && currentItem()->isLocked())
return;
if (auto *current = currentItem()->asTimelineKeyframeItem()) {
const qreal sourceFrame = qRound(current->mapFromSceneToFrame(current->rect().center().x()));
const qreal targetFrame = qRound(current->mapFromSceneToFrame(event->scenePos().x()));
@@ -85,6 +88,9 @@ void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
if (!currentItem())
return;
if (currentItem()->isLocked())
return;
if (auto *current = currentItem()->asTimelineKeyframeItem()) {
// prevent dragging if deselecting a keyframe (Ctrl+click and drag a selected keyframe)
if (!current->highlighted())

View File

@@ -171,6 +171,17 @@ void TimelineSectionItem::updateFramesForTarget(QGraphicsItem *item, const Model
}
}
void TimelineSectionItem::updateHeightForTarget(QGraphicsItem *item, const ModelNode &target)
{
if (!target.isValid())
return;
if (auto sectionItem = qgraphicsitem_cast<TimelineSectionItem *>(item)) {
if (sectionItem->targetNode() == target)
sectionItem->updateHeight();
}
}
void TimelineSectionItem::moveAllFrames(qreal offset)
{
if (m_timeline.isValid())
@@ -313,7 +324,8 @@ void TimelineSectionItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
if (event->button() == Qt::LeftButton) {
event->accept();
toggleCollapsed();
if (!ModelNode::isThisOrAncestorLocked(m_targetNode))
toggleCollapsed();
}
}
@@ -345,7 +357,8 @@ void TimelineSectionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if (m_targetNode.isValid())
m_targetNode.view()->setSelectedModelNode(m_targetNode);
} else {
toggleCollapsed();
if (!ModelNode::isThisOrAncestorLocked(m_targetNode))
toggleCollapsed();
}
update();
}
@@ -414,6 +427,12 @@ void TimelineSectionItem::updateFrames()
update();
}
void TimelineSectionItem::updateHeight()
{
invalidateHeight();
update();
}
void TimelineSectionItem::invalidateHeight()
{
int height = 0;
@@ -464,7 +483,8 @@ void TimelineSectionItem::invalidateFrames()
bool TimelineSectionItem::collapsed() const
{
return m_targetNode.isValid() && !m_targetNode.hasAuxiliaryData("timeline_expanded");
return m_targetNode.isValid()
&& (!m_targetNode.hasAuxiliaryData("timeline_expanded") || m_targetNode.locked());
}
void TimelineSectionItem::createPropertyItems()
@@ -549,9 +569,9 @@ void TimelineRulerSectionItem::invalidateRulerSize(const qreal length)
m_end = length;
}
void TimelineRulerSectionItem::setRulerScaleFactor(int scaling)
void TimelineRulerSectionItem::setZoom(int zoom)
{
qreal blend = qreal(scaling) / 100.0;
qreal blend = qreal(zoom) / 100.0;
qreal width = size().width() - qreal(TimelineConstants::sectionWidth);
qreal duration = rulerDuration();
@@ -572,7 +592,7 @@ void TimelineRulerSectionItem::setRulerScaleFactor(int scaling)
update();
}
int TimelineRulerSectionItem::getRulerScaleFactor() const
int TimelineRulerSectionItem::zoom() const
{
qreal width = size().width() - qreal(TimelineConstants::sectionWidth);
qreal duration = rulerDuration();
@@ -589,7 +609,7 @@ int TimelineRulerSectionItem::getRulerScaleFactor() const
qreal rcount = width / m_scaling;
qreal rblend = TimelineUtils::reverseLerp(rcount, minCount, maxCount);
int rfactor = std::round(rblend * 100);
int rfactor = static_cast<int>(std::round(rblend * 100));
return TimelineUtils::clamp(rfactor, 0, 100);
}
@@ -766,7 +786,7 @@ void TimelineRulerSectionItem::resizeEvent(QGraphicsSceneResizeEvent *event)
{
QGraphicsWidget::resizeEvent(event);
auto factor = getRulerScaleFactor();
auto factor = zoom();
if (factor < 0) {
if (event->oldSize().width() < event->newSize().width())
@@ -775,7 +795,7 @@ void TimelineRulerSectionItem::resizeEvent(QGraphicsSceneResizeEvent *event)
factor = 100;
}
emit scaleFactorChanged(factor);
emit zoomChanged(factor);
}
void TimelineRulerSectionItem::setSizeHints(int width)
@@ -845,6 +865,11 @@ void TimelineBarItem::commitPosition(const QPointF & /*point*/)
m_oldRect = QRectF();
}
bool TimelineBarItem::isLocked() const
{
return sectionItem()->targetNode().isValid() && sectionItem()->targetNode().locked();
}
void TimelineBarItem::scrollOffsetChanged()
{
sectionItem()->invalidateBar();
@@ -904,7 +929,9 @@ void TimelineBarItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
const auto p = event->pos();
QRectF left, right;
if (handleRects(rect(), left, right)) {
if (isLocked() && rect().contains(p)) {
setCursor(QCursor(Qt::ForbiddenCursor));
} else if (handleRects(rect(), left, right)) {
if (left.contains(p) || right.contains(p)) {
if (cursor().shape() != Qt::SizeHorCursor)
setCursor(QCursor(Qt::SizeHorCursor));
@@ -920,6 +947,9 @@ void TimelineBarItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
void TimelineBarItem::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
{
if (isLocked())
return;
QMenu menu;
QAction* overrideColor = menu.addAction(tr("Override Color"));

View File

@@ -50,6 +50,8 @@ public:
void itemMoved(const QPointF &start, const QPointF &end) override;
void commitPosition(const QPointF &point) override;
bool isLocked() const override;
protected:
void scrollOffsetChanged() override;
void paint(QPainter *painter,
@@ -100,6 +102,7 @@ public:
static void updateData(QGraphicsItem *item);
static void updateDataForTarget(QGraphicsItem *item, const ModelNode &target, bool *b);
static void updateFramesForTarget(QGraphicsItem *item, const ModelNode &target);
static void updateHeightForTarget(QGraphicsItem *item, const ModelNode &target);
void moveAllFrames(qreal offset);
void scaleAllFrames(qreal scale);
@@ -121,6 +124,7 @@ protected:
private:
void updateData();
void updateFrames();
void updateHeight();
void invalidateHeight();
void invalidateProperties();
void invalidateFrames();
@@ -145,7 +149,7 @@ class TimelineRulerSectionItem : public TimelineItem
signals:
void rulerClicked(const QPointF &pos);
void scaleFactorChanged(int scale);
void zoomChanged(int zoom);
public:
static TimelineRulerSectionItem *create(QGraphicsScene *parentScene, TimelineItem *parent);
@@ -153,9 +157,9 @@ public:
void invalidateRulerSize(const QmlTimeline &timeline);
void invalidateRulerSize(const qreal length);
void setRulerScaleFactor(int scaling);
void setZoom(int zoom);
int getRulerScaleFactor() const;
int zoom() const;
qreal getFrameTick() const;
qreal rulerScaling() const;

View File

@@ -236,6 +236,18 @@ void TimelineView::selectedNodesChanged(const QList<ModelNode> & /*selectedNodeL
m_timelineWidget->graphicsScene()->update();
}
void TimelineView::auxiliaryDataChanged(const ModelNode &modelNode,
const PropertyName &name,
const QVariant &data)
{
if (name == QmlDesigner::lockedProperty && data.toBool() && modelNode.isValid()) {
for (const auto &node : modelNode.allSubModelNodesAndThisNode()) {
if (node.hasAuxiliaryData("timeline_expanded"))
m_timelineWidget->graphicsScene()->invalidateHeightForTarget(node);
}
}
}
void TimelineView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList)
{
for (const auto &property : propertyList) {

View File

@@ -62,6 +62,9 @@ public:
PropertyChangeFlags propertyChange) override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
void auxiliaryDataChanged(const ModelNode &node,
const PropertyName &name,
const QVariant &data) override;
void propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList) override;
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;

View File

@@ -34,6 +34,7 @@
#include "timelinepropertyitem.h"
#include "timelinetoolbar.h"
#include "timelineview.h"
#include "navigation2d.h"
#include <qmldesignerplugin.h>
#include <qmlstate.h>
@@ -60,6 +61,8 @@
#include <QtGlobal>
#include <QSpacerItem>
#include <cmath>
namespace QmlDesigner {
class Eventfilter : public QObject
@@ -114,7 +117,7 @@ TimelineWidget::TimelineWidget(TimelineView *view)
, m_toolbar(new TimelineToolBar(this))
, m_rulerView(new QGraphicsView(this))
, m_graphicsView(new QGraphicsView(this))
, m_scrollbar(new QScrollBar(this))
, m_scrollbar(new Navigation2dScrollBar(this))
, m_statusBar(new QLabel(this))
, m_timelineView(view)
, m_graphicsScene(new TimelineGraphicsScene(this))
@@ -153,6 +156,7 @@ TimelineWidget::TimelineWidget(TimelineView *view)
m_graphicsView->setFrameShape(QFrame::NoFrame);
m_graphicsView->setFrameShadow(QFrame::Plain);
m_graphicsView->setLineWidth(0);
m_graphicsView->setVerticalScrollBar(new Navigation2dScrollBar);
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@@ -247,6 +251,14 @@ TimelineWidget::TimelineWidget(TimelineView *view)
connect(m_addButton, &QPushButton::clicked, this, [this]() {
m_timelineView->addNewTimelineDialog();
});
Navigation2dFilter *filter = new Navigation2dFilter(this, m_scrollbar);
connect(filter, &Navigation2dFilter::zoomChanged, [this](double scale, const QPointF& pos) {
int s = static_cast<int>(std::round(scale*100.));
double ps = m_graphicsScene->mapFromScene(pos.x());
m_graphicsScene->setZoom(std::clamp(m_graphicsScene->zoom() + s, 0, 100), ps);
});
installEventFilter(filter);
}
void TimelineWidget::connectToolbar()
@@ -258,8 +270,8 @@ void TimelineWidget::connectToolbar()
connect(graphicsScene(), &TimelineGraphicsScene::scroll, this, &TimelineWidget::scroll);
auto setRulerScaling = [this](int val) { m_graphicsScene->setRulerScaling(val); };
connect(m_toolbar, &TimelineToolBar::scaleFactorChanged, setRulerScaling);
auto setZoomFactor = [this](int val) { m_graphicsScene->setZoom(val); };
connect(m_toolbar, &TimelineToolBar::scaleFactorChanged, setZoomFactor);
auto setToFirstFrame = [this]() {
graphicsScene()->setCurrentFrame(graphicsScene()->startFrame());
@@ -428,7 +440,7 @@ void TimelineWidget::init()
// setScaleFactor uses QSignalBlocker.
m_toolbar->setScaleFactor(0);
m_graphicsScene->setRulerScaling(0);
m_graphicsScene->setZoom(0);
}
void TimelineWidget::reset()

Some files were not shown because too many files have changed in this diff Show More