forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.11'
Change-Id: I6389fd3583ca0638fa6b94c03d2442a584b604bc
This commit is contained in:
16
dist/changes-4.10.1.md
vendored
16
dist/changes-4.10.1.md
vendored
@@ -19,9 +19,13 @@ you can check out from the public Git repository. For example:
|
||||
|
||||
* Fixed that text moved around when resizing and zooming (QTCREATORBUG-4756)
|
||||
|
||||
## All Projects
|
||||
|
||||
* Fixed `Qt Creator Plugin` wizard (QTCREATORBUG-22945)
|
||||
|
||||
## Debugging
|
||||
|
||||
* Fixed more layout restoration issues (QTCREATORBUG-22286, QTCREATORBUG-22938)
|
||||
* Fixed more layout restoration issues (QTCREATORBUG-22286, QTCREATORBUG-22415, QTCREATORBUG-22938)
|
||||
|
||||
### LLDB
|
||||
|
||||
@@ -36,7 +40,13 @@ you can check out from the public Git repository. For example:
|
||||
|
||||
### macOS
|
||||
|
||||
* Fixed debugging with Xcode 11 (QTCREATORBUG-22955)
|
||||
* Fixed window stacking order after closing file dialog (QTCREATORBUG-22906)
|
||||
* Fixed window size after exiting fullscreen
|
||||
|
||||
### QNX
|
||||
|
||||
* Fixed that QNX compiler could not be selected for C
|
||||
|
||||
## Credits for these changes go to:
|
||||
|
||||
@@ -44,7 +54,9 @@ Aleksei German
|
||||
Alexander Akulich
|
||||
Andre Hartmann
|
||||
André Pönitz
|
||||
Christian Kandeler
|
||||
Christian Stenger
|
||||
Cristian Adam
|
||||
David Schulz
|
||||
Eike Ziller
|
||||
Knud Dollereder
|
||||
@@ -53,5 +65,5 @@ Lisandro Damián Nicanor Pérez Meyer
|
||||
Nikolai Kosjar
|
||||
Orgad Shaneh
|
||||
Richard Weickelt
|
||||
Sergey Belyashov
|
||||
Thomas Hartmann
|
||||
|
||||
|
@@ -136,8 +136,6 @@ class PlainDumper:
|
||||
printer = self.printer.gen_printer(value.nativeValue)
|
||||
except:
|
||||
printer = self.printer.invoke(value.nativeValue)
|
||||
lister = getattr(printer, 'children', None)
|
||||
children = [] if lister is None else list(lister())
|
||||
d.putType(value.nativeValue.type.name)
|
||||
val = printer.to_string()
|
||||
if isinstance(val, str):
|
||||
@@ -149,11 +147,20 @@ class PlainDumper:
|
||||
d.putCharArrayValue(val.address, val.length,
|
||||
val.type.target().sizeof)
|
||||
|
||||
d.putNumChild(len(children))
|
||||
if d.isExpanded():
|
||||
with Children(d):
|
||||
for child in children:
|
||||
d.putSubItem(child[0], d.fromNativeValue(gdb.Value(child[1])))
|
||||
lister = getattr(printer, 'children', None)
|
||||
if lister is None:
|
||||
d.putNumChild(0)
|
||||
else:
|
||||
if d.isExpanded():
|
||||
children = lister()
|
||||
with Children(d):
|
||||
i = 0
|
||||
for (name, child) in children:
|
||||
d.putSubItem(name, d.fromNativeValue(child))
|
||||
i += 1
|
||||
if i > 1000:
|
||||
break
|
||||
d.putNumChild(1)
|
||||
|
||||
def importPlainDumpers(args):
|
||||
if args == 'off':
|
||||
|
@@ -44,8 +44,8 @@ QString FakeMetaEnum::name() const
|
||||
void FakeMetaEnum::setName(const QString &name)
|
||||
{ m_name = name; }
|
||||
|
||||
void FakeMetaEnum::addKey(const QString &key, int value)
|
||||
{ m_keys.append(key); m_values.append(value); }
|
||||
void FakeMetaEnum::addKey(const QString &key)
|
||||
{ m_keys.append(key); }
|
||||
|
||||
QString FakeMetaEnum::key(int index) const
|
||||
{ return m_keys.at(index); }
|
||||
@@ -71,10 +71,6 @@ void FakeMetaEnum::addToHash(QCryptographicHash &hash) const
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
|
||||
}
|
||||
len = m_values.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (int value, m_values)
|
||||
hash.addData(reinterpret_cast<const char *>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
QString FakeMetaEnum::describe(int baseIndent) const
|
||||
@@ -82,16 +78,14 @@ QString FakeMetaEnum::describe(int baseIndent) const
|
||||
QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
|
||||
QString res = QLatin1String("Enum ");
|
||||
res += name();
|
||||
res += QLatin1String(":{");
|
||||
res += QLatin1String(": [");
|
||||
for (int i = 0; i < keyCount(); ++i) {
|
||||
res += newLine;
|
||||
res += QLatin1String(" ");
|
||||
res += key(i);
|
||||
res += QLatin1String(": ");
|
||||
res += QString::number(m_values.value(i, -1));
|
||||
}
|
||||
res += newLine;
|
||||
res += QLatin1Char('}');
|
||||
res += QLatin1Char(']');
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@@ -43,7 +43,6 @@ namespace LanguageUtils {
|
||||
class LANGUAGEUTILS_EXPORT FakeMetaEnum {
|
||||
QString m_name;
|
||||
QStringList m_keys;
|
||||
QList<int> m_values;
|
||||
|
||||
public:
|
||||
FakeMetaEnum();
|
||||
@@ -54,7 +53,7 @@ public:
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
void addKey(const QString &key, int value);
|
||||
void addKey(const QString &key);
|
||||
QString key(int index) const;
|
||||
int keyCount() const;
|
||||
QStringList keys() const;
|
||||
|
@@ -737,7 +737,7 @@ static LanguageUtils::FakeMetaObject::Ptr buildFakeMetaObject(
|
||||
Symbol *enumMember = e->memberAt(j);
|
||||
if (!enumMember->name())
|
||||
continue;
|
||||
metaEnum.addKey(namePrinter.prettyName(enumMember->name()), 0);
|
||||
metaEnum.addKey(namePrinter.prettyName(enumMember->name()));
|
||||
}
|
||||
fmo->addEnum(metaEnum);
|
||||
}
|
||||
|
@@ -649,39 +649,34 @@ void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUt
|
||||
return;
|
||||
}
|
||||
|
||||
ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
|
||||
auto *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
|
||||
if (!expStmt) {
|
||||
addError(ast->statement->firstSourceLocation(), tr("Expected object literal after colon."));
|
||||
addError(ast->statement->firstSourceLocation(), tr("Expected expression after colon."));
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectPattern *objectLit = AST::cast<ObjectPattern *>(expStmt->expression);
|
||||
if (!objectLit) {
|
||||
addError(expStmt->firstSourceLocation(), tr("Expected object literal after colon."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
|
||||
PatternProperty *assignement = AST::cast<PatternProperty *>(it->property);
|
||||
if (assignement) {
|
||||
StringLiteralPropertyName *propName = AST::cast<StringLiteralPropertyName *>(assignement->name);
|
||||
NumericLiteral *value = AST::cast<NumericLiteral *>(assignement->initializer);
|
||||
UnaryMinusExpression *minus = AST::cast<UnaryMinusExpression *>(assignement->initializer);
|
||||
if (minus)
|
||||
value = AST::cast<NumericLiteral *>(minus->expression);
|
||||
if (!propName || !value) {
|
||||
addError(objectLit->firstSourceLocation(), tr("Expected object literal to contain only 'string: number' elements."));
|
||||
continue;
|
||||
if (auto *objectLit = AST::cast<ObjectPattern *>(expStmt->expression)) {
|
||||
for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
|
||||
if (PatternProperty *assignement = it->property) {
|
||||
if (auto *name = AST::cast<StringLiteralPropertyName *>(assignement->name)) {
|
||||
fme->addKey(name->id.toString());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
double v = value->value;
|
||||
if (minus)
|
||||
v = -v;
|
||||
fme->addKey(propName->id.toString(), v);
|
||||
continue;
|
||||
addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
|
||||
}
|
||||
PatternPropertyList *getterSetter = AST::cast<PatternPropertyList *>(it->next);
|
||||
if (getterSetter)
|
||||
addError(objectLit->firstSourceLocation(), tr("Enum should not contain getter and setters, but only 'string: number' elements."));
|
||||
} else if (auto *arrayLit = AST::cast<ArrayPattern *>(expStmt->expression)) {
|
||||
for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
|
||||
if (PatternElement *element = it->element) {
|
||||
if (auto *name = AST::cast<StringLiteral *>(element->initializer)) {
|
||||
fme->addKey(name->value.toString());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
|
||||
}
|
||||
} else {
|
||||
addError(ast->statement->firstSourceLocation(),
|
||||
tr("Expected either array or object literal as enum definition."));
|
||||
}
|
||||
}
|
||||
|
@@ -381,27 +381,41 @@ QList<ToolChain *> SdccToolChainFactory::autoDetect(const QList<ToolChain *> &al
|
||||
|
||||
if (Utils::HostOsInfo::isWindowsHost()) {
|
||||
|
||||
#ifdef Q_OS_WIN64
|
||||
static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\SDCC";
|
||||
#else
|
||||
static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\SDCC";
|
||||
#endif
|
||||
|
||||
QSettings registry(kRegistryNode, QSettings::NativeFormat);
|
||||
QString compilerPath = registry.value("Default").toString();
|
||||
if (!compilerPath.isEmpty()) {
|
||||
// Tries to detect the candidate from the 32-bit
|
||||
// or 64-bit system registry format.
|
||||
auto probeCandidate = [](QSettings::Format format) {
|
||||
QSettings registry("HKEY_LOCAL_MACHINE\\SOFTWARE\\SDCC",
|
||||
format);
|
||||
QString compilerPath = registry.value("Default").toString();
|
||||
if (compilerPath.isEmpty())
|
||||
return Candidate{};
|
||||
// Build full compiler path.
|
||||
compilerPath += "\\bin\\sdcc.exe";
|
||||
const FilePath fn = FilePath::fromString(
|
||||
QFileInfo(compilerPath).absoluteFilePath());
|
||||
if (compilerExists(fn)) {
|
||||
// Build compiler version.
|
||||
const QString version = QString("%1.%2.%3").arg(
|
||||
registry.value("VersionMajor").toString(),
|
||||
registry.value("VersionMinor").toString(),
|
||||
registry.value("VersionRevision").toString());
|
||||
candidates.push_back({fn, version});
|
||||
}
|
||||
if (!compilerExists(fn))
|
||||
return Candidate{};
|
||||
// Build compiler version.
|
||||
const QString version = QString("%1.%2.%3").arg(
|
||||
registry.value("VersionMajor").toString(),
|
||||
registry.value("VersionMinor").toString(),
|
||||
registry.value("VersionRevision").toString());
|
||||
return Candidate{fn, version};
|
||||
};
|
||||
|
||||
const QSettings::Format allowedFormats[] = {
|
||||
QSettings::NativeFormat,
|
||||
#ifdef Q_OS_WIN
|
||||
QSettings::Registry32Format,
|
||||
QSettings::Registry64Format
|
||||
#endif
|
||||
};
|
||||
|
||||
for (const QSettings::Format format : allowedFormats) {
|
||||
const auto candidate = probeCandidate(format);
|
||||
if (candidate.compilerPath.isEmpty() || candidates.contains(candidate))
|
||||
continue;
|
||||
candidates.push_back(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -33,8 +33,9 @@
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <remotelinux/remotelinuxcheckforfreediskspacestep.h>
|
||||
#include <remotelinux/genericdirectuploadstep.h>
|
||||
#include <remotelinux/makeinstallstep.h>
|
||||
#include <remotelinux/remotelinuxcheckforfreediskspacestep.h>
|
||||
#include <remotelinux/remotelinuxdeployconfiguration.h>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
@@ -51,6 +52,11 @@ QdbDeployConfigurationFactory::QdbDeployConfigurationFactory()
|
||||
"Deploy to Boot2Qt target"));
|
||||
setUseDeploymentDataView();
|
||||
|
||||
addInitialStep(RemoteLinux::MakeInstallStep::stepId(), [](Target *target) {
|
||||
const Project * const prj = target->project();
|
||||
return prj->deploymentKnowledge() == DeploymentKnowledge::Bad
|
||||
&& prj->hasMakeInstallEquivalent();
|
||||
});
|
||||
addInitialStep(RemoteLinuxCheckForFreeDiskSpaceStep::stepId());
|
||||
addInitialStep(QdbStopApplicationStep::stepId());
|
||||
addInitialStep(GenericDirectUploadStep::stepId());
|
||||
|
@@ -46,6 +46,7 @@
|
||||
|
||||
#include <remotelinux/remotelinuxcheckforfreediskspacestep.h>
|
||||
#include <remotelinux/genericdirectuploadstep.h>
|
||||
#include <remotelinux/makeinstallstep.h>
|
||||
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/fileutils.h>
|
||||
@@ -175,8 +176,8 @@ public:
|
||||
|
||||
QdbDeployStepFactory<RemoteLinux::RemoteLinuxCheckForFreeDiskSpaceStep>
|
||||
m_checkForFreeDiskSpaceStepFactory;
|
||||
QdbDeployStepFactory<RemoteLinux::GenericDirectUploadStep>
|
||||
m_directUploadStepFactory;
|
||||
QdbDeployStepFactory<RemoteLinux::GenericDirectUploadStep> m_directUploadStepFactory;
|
||||
QdbDeployStepFactory<RemoteLinux::MakeInstallStep> m_makeInstallStepFactory;
|
||||
|
||||
const QList<Core::Id> supportedRunConfigs {
|
||||
m_runConfigFactory.id(),
|
||||
|
@@ -2285,8 +2285,8 @@ void DebuggerEngine::openDisassemblerView(const Location &location)
|
||||
|
||||
void DebuggerEngine::raiseWatchersWindow()
|
||||
{
|
||||
if (d->m_watchersView) {
|
||||
if (auto dock = qobject_cast<QDockWidget *>(d->m_watchersView->parentWidget())) {
|
||||
if (d->m_watchersView && d->m_watchersWindow) {
|
||||
if (auto dock = qobject_cast<QDockWidget *>(d->m_watchersWindow->parentWidget())) {
|
||||
if (QAction *act = dock->toggleViewAction()) {
|
||||
if (!act->isChecked())
|
||||
QTimer::singleShot(1, act, [act] { act->trigger(); });
|
||||
|
@@ -45,11 +45,13 @@
|
||||
#include <texteditor/texteditoractionhandler.h>
|
||||
#include <texteditor/texteditorconstants.h>
|
||||
|
||||
#include <utils/executeondestruction.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/synchronousprocess.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QRegularExpression>
|
||||
#include <QTimer>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
@@ -58,6 +60,7 @@ namespace Python {
|
||||
namespace Internal {
|
||||
|
||||
static constexpr char startPylsInfoBarId[] = "PythonEditor::StartPyls";
|
||||
static constexpr char installPylsInfoBarId[] = "PythonEditor::InstallPyls";
|
||||
|
||||
struct PythonForProject
|
||||
{
|
||||
@@ -193,6 +196,90 @@ static LanguageClient::Client *registerLanguageServer(const PythonForProject &py
|
||||
return LanguageClient::LanguageClientManager::clientForSetting(settings).value(0);
|
||||
}
|
||||
|
||||
class PythonLSInstallHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PythonLSInstallHelper(const PythonForProject &python, QPointer<TextEditor::TextDocument> document)
|
||||
: m_python(python)
|
||||
, m_document(document)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
auto killTimer = new QTimer(&m_process);
|
||||
|
||||
connect(&m_process,
|
||||
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this,
|
||||
&PythonLSInstallHelper::installFinished);
|
||||
connect(&m_process,
|
||||
&QProcess::readyReadStandardError,
|
||||
this,
|
||||
&PythonLSInstallHelper::errorAvailable);
|
||||
connect(&m_process,
|
||||
&QProcess::readyReadStandardOutput,
|
||||
this,
|
||||
&PythonLSInstallHelper::outputAvailable);
|
||||
connect(killTimer, &QTimer::timeout, [this]() {
|
||||
SynchronousProcess::stopProcess(m_process);
|
||||
Core::MessageManager::write(tr("The Python language server installation timed out."));
|
||||
});
|
||||
|
||||
// on windows the pyls 0.28.3 crashes with pylint so just install the pyflakes linter
|
||||
const QString &pylsVersion = HostOsInfo::isWindowsHost()
|
||||
? QString{"python-language-server[pyflakes]"}
|
||||
: QString{"python-language-server[all]"};
|
||||
|
||||
m_process.start(m_python.path.toString(),
|
||||
{"-m", "pip", "install", pylsVersion});
|
||||
|
||||
Core::MessageManager::write(tr("Running '%1 %2' to install python language server")
|
||||
.arg(m_process.program(), m_process.arguments().join(' ')));
|
||||
|
||||
killTimer->start(5 /*minutes*/ * 60 * 1000);
|
||||
}
|
||||
|
||||
private:
|
||||
void installFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (exitStatus == QProcess::NormalExit && exitCode == 0) {
|
||||
if (LanguageClient::Client *client = registerLanguageServer(m_python))
|
||||
LanguageClient::LanguageClientManager::reOpenDocumentWithClient(m_document, client);
|
||||
} else {
|
||||
Core::MessageManager::write(
|
||||
tr("Installing the Python language server failed with exit code %1").arg(exitCode));
|
||||
}
|
||||
deleteLater();
|
||||
}
|
||||
void outputAvailable()
|
||||
{
|
||||
const QString &stdOut = QString::fromLocal8Bit(m_process.readAllStandardOutput().trimmed());
|
||||
if (!stdOut.isEmpty())
|
||||
Core::MessageManager::write(stdOut);
|
||||
}
|
||||
|
||||
void errorAvailable()
|
||||
{
|
||||
const QString &stdErr = QString::fromLocal8Bit(m_process.readAllStandardError().trimmed());
|
||||
if (!stdErr.isEmpty())
|
||||
Core::MessageManager::write(stdErr);
|
||||
}
|
||||
|
||||
QProcess m_process;
|
||||
const PythonForProject m_python;
|
||||
QPointer<TextEditor::TextDocument> m_document;
|
||||
};
|
||||
|
||||
static void installPythonLanguageServer(const PythonForProject &python,
|
||||
QPointer<TextEditor::TextDocument> document)
|
||||
{
|
||||
document->infoBar()->removeInfo(installPylsInfoBarId);
|
||||
|
||||
auto install = new PythonLSInstallHelper(python, document);
|
||||
install->run();
|
||||
}
|
||||
|
||||
static void setupPythonLanguageServer(const PythonForProject &python,
|
||||
QPointer<TextEditor::TextDocument> document)
|
||||
{
|
||||
@@ -206,13 +293,25 @@ static void updateEditorInfoBar(const PythonForProject &python, TextEditor::Text
|
||||
const PythonLanguageServerState &lsState = checkPythonLanguageServer(python.path, document);
|
||||
|
||||
if (lsState.state == PythonLanguageServerState::CanNotBeInstalled
|
||||
|| lsState.state == PythonLanguageServerState::AlreadyConfigured
|
||||
|| lsState.state == PythonLanguageServerState::CanBeInstalled /* TODO */) {
|
||||
|| lsState.state == PythonLanguageServerState::AlreadyConfigured) {
|
||||
return;
|
||||
}
|
||||
|
||||
Core::InfoBar *infoBar = document->infoBar();
|
||||
if (lsState.state == PythonLanguageServerState::AlreadyInstalled
|
||||
if (lsState.state == PythonLanguageServerState::CanBeInstalled
|
||||
&& infoBar->canInfoBeAdded(installPylsInfoBarId)) {
|
||||
auto message
|
||||
= PythonEditorFactory::tr(
|
||||
"Install and set up Python language server for %1 (%2). "
|
||||
"The language server provides Python specific completions and annotations.")
|
||||
.arg(python.name(), python.path.toUserOutput());
|
||||
Core::InfoBarEntry info(installPylsInfoBarId,
|
||||
message,
|
||||
Core::InfoBarEntry::GlobalSuppression::Enabled);
|
||||
info.setCustomButtonInfo(TextEditor::BaseTextEditor::tr("Install"),
|
||||
[=]() { installPythonLanguageServer(python, document); });
|
||||
infoBar->addInfo(info);
|
||||
} else if (lsState.state == PythonLanguageServerState::AlreadyInstalled
|
||||
&& infoBar->canInfoBeAdded(startPylsInfoBarId)) {
|
||||
auto message = PythonEditorFactory::tr("Found a Python language server for %1 (%2). "
|
||||
"Should this one be set up for this document?")
|
||||
@@ -264,3 +363,5 @@ PythonEditorFactory::PythonEditorFactory()
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Python
|
||||
|
||||
#include "pythoneditor.moc"
|
||||
|
@@ -267,6 +267,17 @@ extend_qtc_plugin(QmlDesigner
|
||||
itemlibrarysectionmodel.cpp itemlibrarysectionmodel.h
|
||||
itemlibraryview.cpp itemlibraryview.h
|
||||
itemlibrarywidget.cpp itemlibrarywidget.h
|
||||
itemlibraryassetimportdialog.cpp itemlibraryassetimportdialog.h
|
||||
itemlibraryassetimportdialog.ui
|
||||
itemlibraryassetimporter.cpp itemlibraryassetimporter.h
|
||||
)
|
||||
|
||||
find_package(Qt5 COMPONENTS Quick3DAssetImport QUIET)
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
CONDITION TARGET Qt5::Quick3DAssetImport
|
||||
FEATURE_INFO "Qt Quick 3D asset import"
|
||||
DEPENDS Qt5::Quick3DAssetImportPrivate
|
||||
DEFINES IMPORT_QUICK3D_ASSETS
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 492 B |
Binary file not shown.
After Width: | Height: | Size: 942 B |
@@ -1,5 +1,10 @@
|
||||
VPATH += $$PWD
|
||||
|
||||
qtHaveModule(quick3dassetimport) {
|
||||
QT *= quick3dassetimport-private
|
||||
DEFINES *= IMPORT_QUICK3D_ASSETS
|
||||
}
|
||||
|
||||
# Input
|
||||
HEADERS += itemlibraryview.h \
|
||||
itemlibrarywidget.h \
|
||||
@@ -9,6 +14,8 @@ HEADERS += itemlibraryview.h \
|
||||
itemlibrarysectionmodel.h \
|
||||
itemlibraryitem.h \
|
||||
itemlibrarysection.h \
|
||||
itemlibraryassetimportdialog.h \
|
||||
itemlibraryassetimporter.h \
|
||||
customfilesystemmodel.h
|
||||
|
||||
SOURCES += itemlibraryview.cpp \
|
||||
@@ -19,6 +26,9 @@ SOURCES += itemlibraryview.cpp \
|
||||
itemlibrarysectionmodel.cpp \
|
||||
itemlibraryitem.cpp \
|
||||
itemlibrarysection.cpp \
|
||||
itemlibraryassetimportdialog.cpp \
|
||||
itemlibraryassetimporter.cpp \
|
||||
customfilesystemmodel.cpp
|
||||
|
||||
RESOURCES += itemlibrary.qrc
|
||||
|
||||
FORMS += itemlibraryassetimportdialog.ui
|
||||
|
@@ -3,5 +3,7 @@
|
||||
<file>images/item-default-icon.png</file>
|
||||
<file>images/item-invalid-icon.png</file>
|
||||
<file>images/item-default-icon@2x.png</file>
|
||||
<file>images/item-3D_model-icon.png</file>
|
||||
<file>images/item-3D_model-icon@2x.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -0,0 +1,229 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "itemlibraryassetimportdialog.h"
|
||||
#include "ui_itemlibraryassetimportdialog.h"
|
||||
|
||||
#include "qmldesignerplugin.h"
|
||||
#include "qmldesignerconstants.h"
|
||||
#include "model.h"
|
||||
|
||||
#include "utils/outputformatter.h"
|
||||
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
#include <QtWidgets/qpushbutton.h>
|
||||
#include <QtWidgets/qformlayout.h>
|
||||
#include <QtWidgets/qlabel.h>
|
||||
#include <QtWidgets/qscrollbar.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
namespace {
|
||||
|
||||
static void addFormattedMessage(Utils::OutputFormatter *formatter, const QString &str,
|
||||
const QString &srcPath, Utils::OutputFormat format) {
|
||||
if (!formatter)
|
||||
return;
|
||||
QString msg = str;
|
||||
if (!srcPath.isEmpty())
|
||||
msg += QStringLiteral(": \"%1\"").arg(srcPath);
|
||||
msg += QLatin1Char('\n');
|
||||
formatter->appendMessage(msg, format);
|
||||
formatter->plainTextEdit()->verticalScrollBar()->setValue(
|
||||
formatter->plainTextEdit()->verticalScrollBar()->maximum());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &importFiles,
|
||||
const QString &defaulTargetDirectory, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::ItemLibraryAssetImportDialog),
|
||||
m_importer(this)
|
||||
{
|
||||
setModal(true);
|
||||
ui->setupUi(this);
|
||||
|
||||
m_outputFormatter = new Utils::OutputFormatter;
|
||||
m_outputFormatter->setPlainTextEdit(ui->plainTextEdit);
|
||||
|
||||
// Skip unsupported assets
|
||||
bool skipSome = false;
|
||||
for (const auto &file : importFiles) {
|
||||
if (m_importer.isQuick3DAsset(file))
|
||||
m_quick3DFiles << file;
|
||||
else
|
||||
skipSome = true;
|
||||
}
|
||||
|
||||
if (skipSome)
|
||||
addWarning("Cannot import 3D and other assets simultaneously. Skipping non-3D assets.");
|
||||
|
||||
// Import button will be used in near future when we add import options. Hide for now.
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->hide();
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Import"));
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked,
|
||||
this, &ItemLibraryAssetImportDialog::onImport);
|
||||
|
||||
ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
|
||||
|
||||
// Import is always done under known folder. The order of preference for folder is:
|
||||
// 1) An existing QUICK_3D_ASSETS_FOLDER under DEFAULT_ASSET_IMPORT_FOLDER project import path
|
||||
// 2) An existing QUICK_3D_ASSETS_FOLDER under any project import path
|
||||
// 3) New QUICK_3D_ASSETS_FOLDER under DEFAULT_ASSET_IMPORT_FOLDER project import path
|
||||
// 4) New QUICK_3D_ASSETS_FOLDER under any project import path
|
||||
// 5) New QUICK_3D_ASSETS_FOLDER under new DEFAULT_ASSET_IMPORT_FOLDER under project
|
||||
const QString defaultAssetFolder = QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER);
|
||||
const QString quick3DFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
|
||||
QString candidatePath = defaulTargetDirectory + defaultAssetFolder + quick3DFolder;
|
||||
int candidatePriority = 5;
|
||||
QStringList importPaths;
|
||||
|
||||
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||
if (doc) {
|
||||
Model *model = doc->currentModel();
|
||||
if (model)
|
||||
importPaths = model->importPaths();
|
||||
}
|
||||
|
||||
for (auto importPath : qAsConst(importPaths)) {
|
||||
if (importPath.startsWith(defaulTargetDirectory)) {
|
||||
const bool isDefaultFolder = importPath.endsWith(defaultAssetFolder);
|
||||
const QString assetFolder = importPath + quick3DFolder;
|
||||
const bool exists = QFileInfo(assetFolder).exists();
|
||||
if (exists) {
|
||||
if (isDefaultFolder) {
|
||||
// Priority one location, stop looking
|
||||
candidatePath = assetFolder;
|
||||
break;
|
||||
} else if (candidatePriority > 2) {
|
||||
candidatePriority = 2;
|
||||
candidatePath = assetFolder;
|
||||
}
|
||||
} else {
|
||||
if (candidatePriority > 3 && isDefaultFolder) {
|
||||
candidatePriority = 3;
|
||||
candidatePath = assetFolder;
|
||||
} else if (candidatePriority > 4) {
|
||||
candidatePriority = 4;
|
||||
candidatePath = assetFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_quick3DImportPath = candidatePath;
|
||||
|
||||
// Queue import immediately until we have some options
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
|
||||
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &ItemLibraryAssetImportDialog::onClose);
|
||||
|
||||
connect(&m_importer, &ItemLibraryAssetImporter::errorReported,
|
||||
this, &ItemLibraryAssetImportDialog::addError);
|
||||
connect(&m_importer, &ItemLibraryAssetImporter::warningReported,
|
||||
this, &ItemLibraryAssetImportDialog::addWarning);
|
||||
connect(&m_importer, &ItemLibraryAssetImporter::infoReported,
|
||||
this, &ItemLibraryAssetImportDialog::addInfo);
|
||||
connect(&m_importer, &ItemLibraryAssetImporter::importFinished,
|
||||
this, &ItemLibraryAssetImportDialog::onImportFinished);
|
||||
connect(&m_importer, &ItemLibraryAssetImporter::progressChanged,
|
||||
this, &ItemLibraryAssetImportDialog::setImportProgress);
|
||||
}
|
||||
|
||||
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::setImportUiState(bool importing)
|
||||
{
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!importing);
|
||||
ui->buttonBox->button(QDialogButtonBox::Close)->setText(importing ? tr("Cancel") : tr("Close"));
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::addError(const QString &error, const QString &srcPath)
|
||||
{
|
||||
addFormattedMessage(m_outputFormatter, error, srcPath, Utils::StdErrFormat);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::addWarning(const QString &warning, const QString &srcPath)
|
||||
{
|
||||
addFormattedMessage(m_outputFormatter, warning, srcPath, Utils::StdOutFormat);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::addInfo(const QString &info, const QString &srcPath)
|
||||
{
|
||||
addFormattedMessage(m_outputFormatter, info, srcPath, Utils::NormalMessageFormat);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onImport()
|
||||
{
|
||||
setImportUiState(true);
|
||||
ui->progressBar->setValue(0);
|
||||
ui->plainTextEdit->clear();
|
||||
|
||||
if (!m_quick3DFiles.isEmpty())
|
||||
m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::setImportProgress(int value, const QString &text)
|
||||
{
|
||||
ui->progressLabel->setText(text);
|
||||
if (value < 0)
|
||||
ui->progressBar->setRange(0, 0);
|
||||
else
|
||||
ui->progressBar->setRange(0, 100);
|
||||
ui->progressBar->setValue(value);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onImportFinished()
|
||||
{
|
||||
setImportUiState(false);
|
||||
if (m_importer.isCancelled()) {
|
||||
QString interruptStr = tr("Import interrupted.");
|
||||
addError(interruptStr);
|
||||
setImportProgress(0, interruptStr);
|
||||
} else {
|
||||
QString doneStr = tr("Import done.");
|
||||
addInfo(doneStr);
|
||||
setImportProgress(100, doneStr);
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onClose()
|
||||
{
|
||||
if (m_importer.isImporting()) {
|
||||
addInfo(tr("Canceling import."));
|
||||
m_importer.cancelImport();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
close();
|
||||
deleteLater();
|
||||
}
|
||||
}
|
@@ -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 "itemlibraryassetimporter.h"
|
||||
|
||||
#include <QtWidgets/qdialog.h>
|
||||
|
||||
namespace Utils {
|
||||
class OutputFormatter;
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
class ItemLibraryAssetImporter;
|
||||
|
||||
namespace Ui {
|
||||
class ItemLibraryAssetImportDialog;
|
||||
}
|
||||
|
||||
class ItemLibraryAssetImportDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ItemLibraryAssetImportDialog(const QStringList &importFiles,
|
||||
const QString &defaulTargetDirectory, QWidget *parent = nullptr);
|
||||
~ItemLibraryAssetImportDialog();
|
||||
|
||||
private slots:
|
||||
void addError(const QString &error, const QString &srcPath = {});
|
||||
void addWarning(const QString &warning, const QString &srcPath = {});
|
||||
void addInfo(const QString &info, const QString &srcPath = {});
|
||||
|
||||
private:
|
||||
void setImportUiState(bool importing);
|
||||
|
||||
void onImport();
|
||||
void setImportProgress(int value, const QString &text);
|
||||
void onImportFinished();
|
||||
void onClose();
|
||||
|
||||
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
|
||||
Utils::OutputFormatter *m_outputFormatter = nullptr;
|
||||
|
||||
QStringList m_quick3DFiles;
|
||||
QString m_quick3DImportPath;
|
||||
ItemLibraryAssetImporter m_importer;
|
||||
};
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QmlDesigner::ItemLibraryAssetImportDialog</class>
|
||||
<widget class="QDialog" name="QmlDesigner::ItemLibraryAssetImportDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Asset Import</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="plainTextEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="progressLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@@ -0,0 +1,322 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "itemlibraryassetimporter.h"
|
||||
#include "qmldesignerplugin.h"
|
||||
#include "qmldesignerconstants.h"
|
||||
|
||||
#include "rewriterview.h"
|
||||
#include "model.h"
|
||||
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qsavefile.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <QtWidgets/qmessagebox.h>
|
||||
|
||||
#ifdef IMPORT_QUICK3D_ASSETS
|
||||
#include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
Q_LOGGING_CATEGORY(importerLog, "qtc.itemlibrary.assetImporter", QtWarningMsg)
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
ItemLibraryAssetImporter::ItemLibraryAssetImporter(QObject *parent) :
|
||||
QObject (parent)
|
||||
{
|
||||
}
|
||||
|
||||
ItemLibraryAssetImporter::~ItemLibraryAssetImporter() {
|
||||
cancelImport();
|
||||
};
|
||||
|
||||
void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
|
||||
const QString &importPath)
|
||||
{
|
||||
if (m_isImporting)
|
||||
cancelImport();
|
||||
reset();
|
||||
m_isImporting = true;
|
||||
|
||||
#ifdef IMPORT_QUICK3D_ASSETS
|
||||
if (!QDir().mkpath(importPath)) {
|
||||
addError(tr("Cannot create import directory."), importPath);
|
||||
notifyFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
m_importPath = importPath;
|
||||
|
||||
parseFiles(inputFiles);
|
||||
|
||||
if (!isCancelled()) {
|
||||
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||
Model *model = doc ? doc->currentModel() : nullptr;
|
||||
if (model && !m_quick3DAddedImports.isEmpty()) {
|
||||
const QString progressTitle = tr("Updating data model.");
|
||||
addInfo(progressTitle);
|
||||
notifyProgress(0, progressTitle);
|
||||
|
||||
// Trigger underlying qmljs snapshot update by making a non-change to the doc
|
||||
model->rewriterView()->textModifier()->replace(0, 0, {});
|
||||
|
||||
// There is a inbuilt delay before rewriter change actually updates the data model,
|
||||
// so we need to wait for a moment to allow the change to take effect.
|
||||
// Otherwise subsequent subcomponent manager update won't detect new imports properly.
|
||||
QTimer *timer = new QTimer(parent());
|
||||
static int counter;
|
||||
counter = 0;
|
||||
timer->callOnTimeout([this, timer, progressTitle, doc]() {
|
||||
if (!isCancelled()) {
|
||||
notifyProgress(++counter * 10, progressTitle);
|
||||
if (counter >= 10) {
|
||||
doc->updateSubcomponentManager();
|
||||
timer->stop();
|
||||
notifyFinished();
|
||||
}
|
||||
} else {
|
||||
timer->stop();
|
||||
}
|
||||
});
|
||||
timer->start(100);
|
||||
} else {
|
||||
notifyFinished();
|
||||
}
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(inputFiles)
|
||||
Q_UNUSED(importPath)
|
||||
addError(tr("Importing 3D assets requires building against Qt Quick 3D module."));
|
||||
notifyFinished();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ItemLibraryAssetImporter::isImporting() const
|
||||
{
|
||||
return m_isImporting;
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::cancelImport()
|
||||
{
|
||||
m_cancelled = true;
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::addError(const QString &errMsg, const QString &srcPath) const
|
||||
{
|
||||
qCDebug(importerLog) << "Error: "<< errMsg << srcPath;
|
||||
emit errorReported(errMsg, srcPath);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::addWarning(const QString &warningMsg, const QString &srcPath) const
|
||||
{
|
||||
qCDebug(importerLog) << "Warning: " << warningMsg << srcPath;
|
||||
emit warningReported(warningMsg, srcPath);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &srcPath) const
|
||||
{
|
||||
qCDebug(importerLog) << "Info: " << infoMsg << srcPath;
|
||||
emit infoReported(infoMsg, srcPath);
|
||||
}
|
||||
|
||||
bool ItemLibraryAssetImporter::isQuick3DAsset(const QString &fileName) const
|
||||
{
|
||||
static QStringList quick3DExt;
|
||||
if (quick3DExt.isEmpty()) {
|
||||
quick3DExt << QString(Constants::FbxExtension)
|
||||
<< QString(Constants::ColladaExtension)
|
||||
<< QString(Constants::ObjExtension)
|
||||
<< QString(Constants::BlenderExtension)
|
||||
<< QString(Constants::GltfExtension);
|
||||
}
|
||||
return quick3DExt.contains(QFileInfo(fileName).suffix());
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::notifyFinished()
|
||||
{
|
||||
m_isImporting = false;
|
||||
emit importFinished();
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::reset()
|
||||
{
|
||||
m_isImporting = false;
|
||||
m_cancelled = false;
|
||||
|
||||
#ifdef IMPORT_QUICK3D_ASSETS
|
||||
m_quick3DAddedImports.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths)
|
||||
{
|
||||
if (isCancelled())
|
||||
return;
|
||||
const QString progressTitle = tr("Parsing files.");
|
||||
addInfo(progressTitle);
|
||||
notifyProgress(0, progressTitle);
|
||||
uint count = 0;
|
||||
double quota = 100.0 / filePaths.count();
|
||||
std::function<void(double)> progress = [this, quota, &count, &progressTitle](double value) {
|
||||
notifyProgress(qRound(quota * (count + value)), progressTitle);
|
||||
};
|
||||
for (const QString &file : filePaths) {
|
||||
if (isCancelled())
|
||||
return;
|
||||
if (isQuick3DAsset(file))
|
||||
parseQuick3DAsset(file);
|
||||
notifyProgress(qRound(++count * quota), progressTitle);
|
||||
}
|
||||
notifyProgress(100, progressTitle);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file)
|
||||
{
|
||||
#ifdef IMPORT_QUICK3D_ASSETS
|
||||
addInfo(tr("Parsing 3D Model"), file);
|
||||
if (!m_quick3DAssetImporter)
|
||||
m_quick3DAssetImporter.reset(new QSSGAssetImportManager);
|
||||
|
||||
QString errorString;
|
||||
|
||||
QDir rootDir(m_importPath);
|
||||
QFileInfo sourceInfo(file);
|
||||
QString assetName = sourceInfo.completeBaseName();
|
||||
|
||||
if (!assetName.isEmpty()) {
|
||||
// Fix name so it plays nice with imports
|
||||
for (QChar ¤tChar : assetName) {
|
||||
if (!currentChar.isLetter() && !currentChar.isDigit())
|
||||
currentChar = QLatin1Char('_');
|
||||
}
|
||||
QCharRef firstChar = assetName[0];
|
||||
if (firstChar.isDigit())
|
||||
firstChar = QLatin1Char('_');
|
||||
if (firstChar.isLower())
|
||||
firstChar = firstChar.toUpper();
|
||||
}
|
||||
|
||||
QDir outDir = rootDir;
|
||||
if (outDir.exists(assetName)) {
|
||||
if (confirmAssetOverwrite(assetName)) {
|
||||
if (outDir.cd(assetName)) {
|
||||
outDir.removeRecursively();
|
||||
outDir.cdUp();
|
||||
outDir.mkpath(assetName);
|
||||
} // If cd fails here, it will fail below, too, so no error handling here
|
||||
} else {
|
||||
addWarning(tr("Skipped import of existing asset: \"%1\"").arg(assetName));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
outDir.mkpath(assetName);
|
||||
}
|
||||
if (!outDir.cd(assetName)) {
|
||||
addError(tr("Could not access asset directory: \"%1\"").arg(outDir.filePath(assetName)));
|
||||
return;
|
||||
}
|
||||
|
||||
addInfo(tr("Generating 3D assets into: \"%1\"").arg(outDir.absolutePath()));
|
||||
|
||||
if (m_quick3DAssetImporter->importFile(
|
||||
sourceInfo.absoluteFilePath(), outDir,
|
||||
&errorString) != QSSGAssetImportManager::ImportState::Success) {
|
||||
addError(tr("Failed to import 3D asset with error: %1").arg(errorString),
|
||||
sourceInfo.absoluteFilePath());
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate qmldir file
|
||||
outDir.setNameFilters({QStringLiteral("*.qml")});
|
||||
const QFileInfoList qmlFiles = outDir.entryInfoList(QDir::Files);
|
||||
|
||||
if (!qmlFiles.isEmpty()) {
|
||||
QString qmldirFileName = outDir.absoluteFilePath(QStringLiteral("qmldir"));
|
||||
QSaveFile qmldirFile(qmldirFileName);
|
||||
QString version = QStringLiteral("1.0");
|
||||
if (qmldirFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
for (const auto &fi : qmlFiles) {
|
||||
QString qmlInfo;
|
||||
qmlInfo.append(fi.baseName());
|
||||
qmlInfo.append(QLatin1Char(' '));
|
||||
qmlInfo.append(version);
|
||||
qmlInfo.append(QLatin1Char(' '));
|
||||
qmlInfo.append(fi.fileName());
|
||||
qmldirFile.write(qmlInfo.toUtf8());
|
||||
}
|
||||
QString assetFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
|
||||
assetFolder = assetFolder.mid(assetFolder.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
m_quick3DAddedImports.insert(
|
||||
qmldirFileName,
|
||||
Import::createLibraryImport(
|
||||
QStringLiteral("%1.%2").arg(assetFolder).arg(assetName), version));
|
||||
qmldirFile.commit();
|
||||
} else {
|
||||
addError(tr("Failed to create qmldir file for asset: \"%1\"").arg(assetName));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the original asset into a subdirectory
|
||||
QString origAssetDirName = QStringLiteral("source model");
|
||||
QDir origAssetDir = outDir;
|
||||
|
||||
origAssetDir.mkpath(origAssetDirName);
|
||||
origAssetDir.cd(origAssetDirName);
|
||||
QFile::copy(sourceInfo.absoluteFilePath(), origAssetDir.filePath(sourceInfo.fileName()));
|
||||
#else
|
||||
Q_UNUSED(file)
|
||||
#endif
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::notifyProgress(int value, const QString &text) const
|
||||
{
|
||||
emit progressChanged(value, text);
|
||||
keepUiAlive();
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::keepUiAlive() const
|
||||
{
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
||||
bool ItemLibraryAssetImporter::confirmAssetOverwrite(const QString &assetName)
|
||||
{
|
||||
const QString title = tr("Overwrite Existing Asset?");
|
||||
const QString question = tr("Asset already exists. Overwrite?\n\"%1\"").arg(assetName);
|
||||
return QMessageBox::question(qobject_cast<QWidget *>(parent()),
|
||||
title, question,
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
|
||||
}
|
||||
|
||||
bool ItemLibraryAssetImporter::isCancelled() const
|
||||
{
|
||||
keepUiAlive();
|
||||
return m_cancelled;
|
||||
}
|
||||
|
||||
} // QmlDesigner
|
@@ -0,0 +1,84 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <QtCore/qobject.h>
|
||||
#include <QtCore/qstringlist.h>
|
||||
#include <QtCore/qhash.h>
|
||||
|
||||
#include "import.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSSGAssetImportManager;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ItemLibraryAssetImporter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ItemLibraryAssetImporter(QObject *parent = nullptr);
|
||||
~ItemLibraryAssetImporter();
|
||||
|
||||
void importQuick3D(const QStringList &inputFiles, const QString &importPath);
|
||||
|
||||
bool isImporting() const;
|
||||
void cancelImport();
|
||||
bool isCancelled() const;
|
||||
|
||||
void addError(const QString &errMsg, const QString &srcPath = {}) const;
|
||||
void addWarning(const QString &warningMsg, const QString &srcPath = {}) const;
|
||||
void addInfo(const QString &infoMsg, const QString &srcPath = {}) const;
|
||||
|
||||
bool isQuick3DAsset(const QString &fileName) const;
|
||||
|
||||
signals:
|
||||
void errorReported(const QString &, const QString &) const;
|
||||
void warningReported(const QString &, const QString &) const;
|
||||
void infoReported(const QString &, const QString &) const;
|
||||
void progressChanged(int value, const QString &text) const;
|
||||
void importFinished();
|
||||
|
||||
private:
|
||||
void notifyFinished();
|
||||
void reset();
|
||||
void parseFiles(const QStringList &filePaths);
|
||||
void parseQuick3DAsset(const QString &file);
|
||||
|
||||
void notifyProgress(int value, const QString &text) const;
|
||||
void keepUiAlive() const;
|
||||
bool confirmAssetOverwrite(const QString &assetName);
|
||||
|
||||
#ifdef IMPORT_QUICK3D_ASSETS
|
||||
QScopedPointer<QSSGAssetImportManager> m_quick3DAssetImporter;
|
||||
QHash<QString, Import> m_quick3DAddedImports;
|
||||
#endif
|
||||
bool m_isImporting = false;
|
||||
bool m_cancelled = false;
|
||||
QString m_importPath;
|
||||
};
|
||||
} // QmlDesigner
|
@@ -26,6 +26,7 @@
|
||||
#include "itemlibrarywidget.h"
|
||||
|
||||
#include "customfilesystemmodel.h"
|
||||
#include "itemlibraryassetimportdialog.h"
|
||||
|
||||
#include <theme.h>
|
||||
|
||||
@@ -36,6 +37,8 @@
|
||||
#include <model.h>
|
||||
#include <rewritingexception.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
#include <designeractionmanager.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/flowlayout.h>
|
||||
@@ -183,6 +186,43 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
|
||||
flowLayout->addWidget(button);
|
||||
connect(button, &QToolButton::clicked, this, &ItemLibraryWidget::addResources);
|
||||
|
||||
#ifdef IMPORT_QUICK3D_ASSETS
|
||||
DesignerActionManager *actionManager =
|
||||
&QmlDesignerPlugin::instance()->viewManager().designerActionManager();
|
||||
|
||||
auto handle3DModel = [](const QStringList &fileNames, const QString &defaultDir) -> bool {
|
||||
auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir);
|
||||
importDlg->show();
|
||||
return true;
|
||||
};
|
||||
|
||||
const QString category = tr("3D Models");
|
||||
|
||||
auto add3DHandler = [&actionManager, &handle3DModel, &category](const char *ext) {
|
||||
const QString filter = QStringLiteral("*.%1").arg(QString::fromLatin1(ext));
|
||||
actionManager->registerAddResourceHandler(
|
||||
AddResourceHandler(category, filter, handle3DModel, 10));
|
||||
};
|
||||
|
||||
// Skip if 3D model handlers have already been added
|
||||
const QList<AddResourceHandler> handlers = actionManager->addResourceHandler();
|
||||
bool categoryAlreadyAdded = false;
|
||||
for (const auto &handler : handlers) {
|
||||
if (handler.category == category) {
|
||||
categoryAlreadyAdded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!categoryAlreadyAdded) {
|
||||
add3DHandler(Constants::FbxExtension);
|
||||
add3DHandler(Constants::ColladaExtension);
|
||||
add3DHandler(Constants::ObjExtension);
|
||||
add3DHandler(Constants::BlenderExtension);
|
||||
add3DHandler(Constants::GltfExtension);
|
||||
}
|
||||
#endif
|
||||
|
||||
// init the first load of the QML UI elements
|
||||
reloadQmlSource();
|
||||
}
|
||||
@@ -192,13 +232,19 @@ void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo)
|
||||
if (m_itemLibraryInfo.data() == itemLibraryInfo)
|
||||
return;
|
||||
|
||||
if (m_itemLibraryInfo)
|
||||
if (m_itemLibraryInfo) {
|
||||
disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged,
|
||||
this, &ItemLibraryWidget::delayedUpdateModel);
|
||||
disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::importTagsChanged,
|
||||
this, &ItemLibraryWidget::delayedUpdateModel);
|
||||
}
|
||||
m_itemLibraryInfo = itemLibraryInfo;
|
||||
if (itemLibraryInfo)
|
||||
if (itemLibraryInfo) {
|
||||
connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged,
|
||||
this, &ItemLibraryWidget::delayedUpdateModel);
|
||||
connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::importTagsChanged,
|
||||
this, &ItemLibraryWidget::delayedUpdateModel);
|
||||
}
|
||||
delayedUpdateModel();
|
||||
}
|
||||
|
||||
@@ -383,7 +429,22 @@ void ItemLibraryWidget::addPossibleImport(const QString &name)
|
||||
QTC_ASSERT(m_model, return);
|
||||
const Import import = m_model->highestPossibleImport(name);
|
||||
try {
|
||||
m_model->changeImports({Import::createLibraryImport(name, import.version())}, {});
|
||||
QList<Import> addedImports = {Import::createLibraryImport(name, import.version())};
|
||||
// Special case for adding an import for 3D asset - also add QtQuick3D import
|
||||
const QString asset3DPrefix = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER + 1)
|
||||
+ QLatin1Char('.');
|
||||
if (name.startsWith(asset3DPrefix)) {
|
||||
const QString q3Dlib = QLatin1String(Constants::QT_QUICK_3D_MODULE_NAME);
|
||||
Import q3DImport = m_model->highestPossibleImport(q3Dlib);
|
||||
if (q3DImport.url() == q3Dlib)
|
||||
addedImports.prepend(Import::createLibraryImport(q3Dlib, q3DImport.version()));
|
||||
}
|
||||
RewriterTransaction transaction
|
||||
= m_model->rewriterView()->beginRewriterTransaction(
|
||||
QByteArrayLiteral("ItemLibraryWidget::addPossibleImport"));
|
||||
|
||||
m_model->changeImports(addedImports, {});
|
||||
transaction.commit();
|
||||
}
|
||||
catch (const RewritingException &e) {
|
||||
e.showException();
|
||||
|
@@ -114,6 +114,7 @@ public:
|
||||
|
||||
signals:
|
||||
void entriesChanged();
|
||||
void importTagsChanged();
|
||||
|
||||
private: // functions
|
||||
ItemLibraryInfo(QObject *parent = nullptr);
|
||||
|
@@ -65,6 +65,8 @@ private: // functions
|
||||
void registerQmlFile(const QFileInfo &fileInfo, const QString &qualifier, bool addToLibrary);
|
||||
Model *model() const;
|
||||
QStringList importPaths() const;
|
||||
void parseQuick3DAssetDir(const QString &assetPath);
|
||||
QStringList quick3DAssetPaths() const;
|
||||
|
||||
private: // variables
|
||||
QFileSystemWatcher m_watcher;
|
||||
|
@@ -356,7 +356,10 @@ void ItemLibraryInfo::addBlacklistImports(const QStringList &list)
|
||||
|
||||
void ItemLibraryInfo::addShowTagsForImports(const QStringList &list)
|
||||
{
|
||||
m_showTagsForImports.append(list);
|
||||
if (!list.isEmpty()) {
|
||||
m_showTagsForImports.append(list);
|
||||
emit importTagsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryInfo::setBaseInfo(ItemLibraryInfo *baseInfo)
|
||||
|
@@ -85,8 +85,7 @@ void SubComponentManager::addImport(int pos, const Import &import)
|
||||
url.replace(QLatin1Char('.'), QLatin1Char('/'));
|
||||
|
||||
foreach (const QString &path, importPaths()) {
|
||||
url = path + QLatin1Char('/') + url;
|
||||
QFileInfo dirInfo = QFileInfo(url);
|
||||
QFileInfo dirInfo = QFileInfo(path + QLatin1Char('/') + url);
|
||||
if (dirInfo.exists() && dirInfo.isDir()) {
|
||||
const QString canonicalDirPath = dirInfo.canonicalFilePath();
|
||||
m_watcher.addPath(canonicalDirPath);
|
||||
@@ -126,14 +125,19 @@ void SubComponentManager::parseDirectories()
|
||||
if (!m_filePath.isEmpty()) {
|
||||
const QString file = m_filePath.toLocalFile();
|
||||
QFileInfo dirInfo = QFileInfo(QFileInfo(file).path());
|
||||
const QString canonicalPath = dirInfo.canonicalFilePath();
|
||||
if (dirInfo.exists() && dirInfo.isDir())
|
||||
parseDirectory(dirInfo.canonicalFilePath());
|
||||
parseDirectory(canonicalPath);
|
||||
|
||||
foreach (const QString &subDir, QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot)) {
|
||||
parseDirectory(dirInfo.canonicalFilePath() + QLatin1String("/") + subDir, true, subDir.toUtf8());
|
||||
parseDirectory(canonicalPath + QLatin1Char('/') + subDir, true, subDir.toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
const QStringList assetPaths = quick3DAssetPaths();
|
||||
for (const auto &assetPath : assetPaths)
|
||||
parseDirectory(assetPath);
|
||||
|
||||
foreach (const Import &import, m_imports) {
|
||||
if (import.isFileImport()) {
|
||||
QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile());
|
||||
@@ -169,6 +173,11 @@ void SubComponentManager::parseDirectory(const QString &canonicalDirPath, bool a
|
||||
if (!model() || !model()->rewriterView())
|
||||
return;
|
||||
|
||||
if (canonicalDirPath.endsWith(QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER))) {
|
||||
parseQuick3DAssetDir(canonicalDirPath);
|
||||
return;
|
||||
}
|
||||
|
||||
QDir designerDir(canonicalDirPath + QLatin1String(Constants::QML_DESIGNER_SUBFOLDER));
|
||||
if (designerDir.exists()) {
|
||||
QStringList filter;
|
||||
@@ -325,7 +334,7 @@ void SubComponentManager::registerQmlFile(const QFileInfo &fileInfo, const QStri
|
||||
ItemLibraryEntry itemLibraryEntry;
|
||||
itemLibraryEntry.setType(componentName.toUtf8());
|
||||
itemLibraryEntry.setName(baseComponentName);
|
||||
itemLibraryEntry.setCategory(QLatin1String("My QML Components"));
|
||||
itemLibraryEntry.setCategory(tr("My QML Components"));
|
||||
if (!qualifier.isEmpty()) {
|
||||
itemLibraryEntry.setRequiredImport(fixedQualifier);
|
||||
}
|
||||
@@ -348,6 +357,75 @@ QStringList SubComponentManager::importPaths() const
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
void SubComponentManager::parseQuick3DAssetDir(const QString &assetPath)
|
||||
{
|
||||
QDir assetDir(assetPath);
|
||||
const QString assetImportRoot = assetPath.mid(assetPath.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
QStringList assets = assetDir.entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot);
|
||||
for (QString &asset : assets)
|
||||
asset.prepend(assetImportRoot + QLatin1Char('.'));
|
||||
|
||||
QStringList newFlowTags;
|
||||
const QStringList flowTags = model()->metaInfo().itemLibraryInfo()->showTagsForImports();
|
||||
const QString quick3Dlib = QLatin1String(Constants::QT_QUICK_3D_MODULE_NAME);
|
||||
const QList<Import> possibleImports = model()->possibleImports();
|
||||
|
||||
auto isPossibleImport = [&possibleImports](const QString &asset) {
|
||||
for (const Import &import : possibleImports) {
|
||||
if (import.url() == asset)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// If there are 3D assets in import path, add a flow tag for QtQuick3D
|
||||
if (!assets.isEmpty() && !flowTags.contains(quick3Dlib) && isPossibleImport(quick3Dlib))
|
||||
newFlowTags << quick3Dlib;
|
||||
|
||||
// Create item library entries for Quick3D assets that are imported by document
|
||||
const QString iconPath = QStringLiteral(":/ItemLibrary/images/item-3D_model-icon.png");
|
||||
for (auto &import : qAsConst(m_imports)) {
|
||||
if (import.isLibraryImport() && assets.contains(import.url())) {
|
||||
assets.removeOne(import.url());
|
||||
ItemLibraryEntry itemLibraryEntry;
|
||||
const QString name = import.url().mid(import.url().indexOf(QLatin1Char('.')) + 1);
|
||||
const QString type = import.url() + QLatin1Char('.') + name;
|
||||
// For now we assume version is always 1.0 as that's what importer hardcodes
|
||||
itemLibraryEntry.setType(type.toUtf8(), 1, 0);
|
||||
itemLibraryEntry.setName(name);
|
||||
itemLibraryEntry.setCategory(tr("My Quick3D Components"));
|
||||
itemLibraryEntry.setRequiredImport(import.url());
|
||||
itemLibraryEntry.setLibraryEntryIconPath(iconPath);
|
||||
itemLibraryEntry.setTypeIcon(QIcon(iconPath));
|
||||
|
||||
if (!model()->metaInfo().itemLibraryInfo()->containsEntry(itemLibraryEntry))
|
||||
model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry});
|
||||
}
|
||||
}
|
||||
|
||||
// Create flow tags for the rest, if they are possible imports
|
||||
if (!assets.isEmpty()) {
|
||||
for (const QString &asset : qAsConst(assets)) {
|
||||
if (!flowTags.contains(asset) && isPossibleImport(asset))
|
||||
newFlowTags << asset;
|
||||
}
|
||||
}
|
||||
|
||||
if (!newFlowTags.isEmpty())
|
||||
model()->metaInfo().itemLibraryInfo()->addShowTagsForImports(newFlowTags);
|
||||
}
|
||||
|
||||
QStringList SubComponentManager::quick3DAssetPaths() const
|
||||
{
|
||||
const auto impPaths = importPaths();
|
||||
QStringList retPaths;
|
||||
for (const auto &impPath : impPaths) {
|
||||
const QString assetPath = impPath + QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
|
||||
if (QFileInfo(assetPath).exists())
|
||||
retPaths << assetPath;
|
||||
}
|
||||
return retPaths;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class SubComponentManager
|
||||
@@ -392,6 +470,14 @@ void SubComponentManager::update(const QUrl &filePath, const QList<Import> &impo
|
||||
m_dirToQualifier.remove(oldDir.canonicalFilePath(), QString());
|
||||
if (!m_dirToQualifier.contains(oldDir.canonicalFilePath()))
|
||||
m_watcher.removePath(oldDir.filePath());
|
||||
|
||||
// Remove old watched asset paths
|
||||
const QStringList watchPaths = m_watcher.directories();
|
||||
const QString &quick3DAssetFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
|
||||
for (const auto &watchPath : watchPaths) {
|
||||
if (watchPath.endsWith(quick3DAssetFolder))
|
||||
m_watcher.removePath(watchPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (!newDir.filePath().isEmpty())
|
||||
@@ -417,7 +503,13 @@ void SubComponentManager::update(const QUrl &filePath, const QList<Import> &impo
|
||||
addImport(ii, imports.at(ii));
|
||||
}
|
||||
|
||||
m_watcher.addPath(newDir.absoluteFilePath());
|
||||
const QString newPath = newDir.absoluteFilePath();
|
||||
m_watcher.addPath(newPath);
|
||||
|
||||
// Watch existing asset paths, including a global ones if they exist
|
||||
const auto assetPaths = quick3DAssetPaths();
|
||||
for (const auto &assetPath : assetPaths)
|
||||
m_watcher.addPath(assetPath);
|
||||
|
||||
parseDirectories();
|
||||
}
|
||||
|
@@ -50,6 +50,15 @@ const char GO_INTO_COMPONENT[] = "QmlDesigner.GoIntoComponent";
|
||||
const char EXPORT_AS_IMAGE[] = "QmlDesigner.ExportAsImage";
|
||||
|
||||
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";
|
||||
const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets";
|
||||
const char DEFAULT_ASSET_IMPORT_FOLDER[] = "/asset_imports";
|
||||
const char QT_QUICK_3D_MODULE_NAME[] = "QtQuick3D";
|
||||
|
||||
const char FbxExtension[] = "fbx";
|
||||
const char ColladaExtension[] = "dae";
|
||||
const char ObjExtension[] = "obj";
|
||||
const char BlenderExtension[] = "blend";
|
||||
const char GltfExtension[] = "gltf";
|
||||
|
||||
namespace Internal {
|
||||
enum { debug = 0 };
|
||||
|
@@ -524,6 +524,11 @@ Project {
|
||||
"integration/utilitypanelcontroller.cpp",
|
||||
"integration/utilitypanelcontroller.h",
|
||||
"itemlibrary/itemlibrary.qrc",
|
||||
"itemlibrary/itemlibraryassetimportdialog.cpp",
|
||||
"itemlibrary/itemlibraryassetimportdialog.h",
|
||||
"itemlibrary/itemlibraryassetimportdialog.ui",
|
||||
"itemlibrary/itemlibraryassetimporter.cpp",
|
||||
"itemlibrary/itemlibraryassetimporter.h",
|
||||
"itemlibrary/itemlibraryimageprovider.cpp",
|
||||
"itemlibrary/itemlibraryimageprovider.h",
|
||||
"itemlibrary/itemlibraryitem.cpp",
|
||||
|
@@ -55,6 +55,7 @@
|
||||
#include <projectexplorer/toolchain.h>
|
||||
|
||||
#include <remotelinux/genericdirectuploadstep.h>
|
||||
#include <remotelinux/makeinstallstep.h>
|
||||
#include <remotelinux/remotelinuxcheckforfreediskspacestep.h>
|
||||
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
@@ -90,6 +91,11 @@ public:
|
||||
addSupportedTargetDeviceType(Constants::QNX_QNX_OS_TYPE);
|
||||
setUseDeploymentDataView();
|
||||
|
||||
addInitialStep(RemoteLinux::MakeInstallStep::stepId(), [](Target *target) {
|
||||
const Project * const prj = target->project();
|
||||
return prj->deploymentKnowledge() == DeploymentKnowledge::Bad
|
||||
&& prj->hasMakeInstallEquivalent();
|
||||
});
|
||||
addInitialStep(DeviceCheckBuildStep::stepId());
|
||||
addInitialStep(RemoteLinux::RemoteLinuxCheckForFreeDiskSpaceStep::stepId());
|
||||
addInitialStep(RemoteLinux::GenericDirectUploadStep::stepId());
|
||||
@@ -110,6 +116,7 @@ public:
|
||||
QnxDeployConfigurationFactory deployConfigFactory;
|
||||
GenericQnxDeployStepFactory<RemoteLinux::GenericDirectUploadStep> directUploadDeployFactory;
|
||||
GenericQnxDeployStepFactory<RemoteLinux::RemoteLinuxCheckForFreeDiskSpaceStep> checkForFreeDiskSpaceDeployFactory;
|
||||
GenericQnxDeployStepFactory<RemoteLinux::MakeInstallStep> makeInstallDeployFactory;
|
||||
GenericQnxDeployStepFactory<DeviceCheckBuildStep> checkBuildDeployFactory;
|
||||
QnxRunConfigurationFactory runConfigFactory;
|
||||
QnxSettingsPage settingsPage;
|
||||
|
@@ -45,7 +45,6 @@ using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace RemoteLinux {
|
||||
namespace Internal {
|
||||
|
||||
const char MakeAspectId[] = "RemoteLinux.MakeInstall.Make";
|
||||
const char InstallRootAspectId[] = "RemoteLinux.MakeInstall.InstallRoot";
|
||||
@@ -228,5 +227,4 @@ bool MakeInstallStep::fromMap(const QVariantMap &map)
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace RemoteLinux
|
||||
|
@@ -25,15 +25,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "remotelinux_export.h"
|
||||
|
||||
#include <projectexplorer/deploymentdata.h>
|
||||
#include <projectexplorer/makestep.h>
|
||||
|
||||
namespace Utils { class FilePath; }
|
||||
|
||||
namespace RemoteLinux {
|
||||
namespace Internal {
|
||||
|
||||
class MakeInstallStep : public ProjectExplorer::MakeStep
|
||||
class REMOTELINUX_EXPORT MakeInstallStep : public ProjectExplorer::MakeStep
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -62,5 +63,4 @@ private:
|
||||
bool m_isCmakeProject = false;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace RemoteLinux
|
||||
|
Submodule src/shared/qbs updated: 94fe404a5a...aec975a3f9
Reference in New Issue
Block a user