forked from qt-creator/qt-creator
Merge "Merge remote-tracking branch 'origin/qds/dev'"
This commit is contained in:
@@ -289,6 +289,7 @@ public:
|
||||
|
||||
MainWindow *m_mainwindow = nullptr;
|
||||
QTimer m_trimTimer;
|
||||
QString m_prependAboutInformation;
|
||||
QStringList m_aboutInformation;
|
||||
Context m_highPrioAdditionalContexts;
|
||||
Context m_lowPrioAdditionalContexts{Constants::C_GLOBAL};
|
||||
@@ -1158,7 +1159,9 @@ void ICore::saveSettings(SaveSettingsReason reason)
|
||||
*/
|
||||
QStringList ICore::additionalAboutInformation()
|
||||
{
|
||||
return d->m_aboutInformation;
|
||||
auto aboutInformation = d->m_aboutInformation;
|
||||
aboutInformation.prepend(d->m_prependAboutInformation);
|
||||
return aboutInformation;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1169,6 +1172,14 @@ void ICore::clearAboutInformation()
|
||||
d->m_aboutInformation.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void ICore::setPrependAboutInformation(const QString &line)
|
||||
{
|
||||
d->m_prependAboutInformation = line;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
|
||||
@@ -142,6 +142,7 @@ public:
|
||||
static Utils::FilePath pathRelativeToActiveProject(const Utils::FilePath &path);
|
||||
static QStringList additionalAboutInformation();
|
||||
static void clearAboutInformation();
|
||||
static void setPrependAboutInformation(const QString &line);
|
||||
static void appendAboutInformation(const QString &line);
|
||||
static QString aboutInformationCompact();
|
||||
static QString aboutInformationHtml();
|
||||
|
||||
@@ -846,7 +846,8 @@ R"(
|
||||
|
||||
QString parentChanged{
|
||||
R"(
|
||||
onParentChanged: {
|
||||
function setupParentLayer()
|
||||
{
|
||||
if (_oldParent && _oldParent !== parent) {
|
||||
_oldParent.layer.enabled = false
|
||||
_oldParent.layer.effect = null
|
||||
@@ -860,26 +861,21 @@ R"(
|
||||
if (visible) {
|
||||
parent.layer.enabled = true
|
||||
parent.layer.effect = effectComponent
|
||||
%6
|
||||
%4%1%5%3
|
||||
} else {
|
||||
parent.layer.enabled = false
|
||||
parent.layer.effect = null
|
||||
%8
|
||||
%4%2
|
||||
}
|
||||
%6
|
||||
%4%1%5%3
|
||||
parent.update()
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
parent.layer.enabled = true
|
||||
parent.layer.effect = effectComponent
|
||||
%6
|
||||
%4%1%5%3
|
||||
} else {
|
||||
parent.layer.enabled = false
|
||||
parent.layer.effect = null
|
||||
%8
|
||||
%4%2
|
||||
}
|
||||
parent.update()
|
||||
}
|
||||
onParentChanged: setupParentLayer()
|
||||
|
||||
onVisibleChanged: setupParentLayer()
|
||||
|
||||
)"
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <designermcumanager.h>
|
||||
#include <documentmanager.h>
|
||||
#include <import.h>
|
||||
#include <modelnodeoperations.h>
|
||||
#include <qmlchangeset.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
@@ -16,6 +17,8 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace EffectComposer {
|
||||
|
||||
EffectComposerView::EffectComposerView(QmlDesigner::ExternalDependenciesInterface &externalDependencies)
|
||||
@@ -106,8 +109,10 @@ QmlDesigner::WidgetInfo EffectComposerView::widgetInfo()
|
||||
});
|
||||
}
|
||||
|
||||
return createWidgetInfo(m_widget.data(), "EffectComposer",
|
||||
QmlDesigner::WidgetInfo::LeftPane, 0, tr("Effect Composer [beta]"));
|
||||
return createWidgetInfo(m_widget.data(),
|
||||
"EffectComposer",
|
||||
QmlDesigner::WidgetInfo::LeftPane,
|
||||
tr("Effect Composer [beta]"));
|
||||
}
|
||||
|
||||
void EffectComposerView::customNotification([[maybe_unused]] const AbstractView *view,
|
||||
@@ -167,4 +172,48 @@ void EffectComposerView::selectedNodesChanged(const QList<QmlDesigner::ModelNode
|
||||
m_widget->effectComposerModel()->setHasValidTarget(hasValidTarget);
|
||||
}
|
||||
|
||||
void EffectComposerView::nodeAboutToBeRemoved(const QmlDesigner::ModelNode &removedNode)
|
||||
{
|
||||
QList<QmlDesigner::ModelNode> nodes = removedNode.allSubModelNodesAndThisNode();
|
||||
bool effectRemoved = false;
|
||||
for (const QmlDesigner::ModelNode &node : nodes) {
|
||||
QmlDesigner::QmlItemNode qmlNode(node);
|
||||
if (qmlNode.isEffectItem()) {
|
||||
effectRemoved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (effectRemoved)
|
||||
QTimer::singleShot(0, this, &EffectComposerView::removeUnusedEffectImports);
|
||||
}
|
||||
|
||||
void EffectComposerView::removeUnusedEffectImports()
|
||||
{
|
||||
QTC_ASSERT(model(), return);
|
||||
|
||||
const QString effectPrefix = m_componentUtils.composedEffectsTypePrefix();
|
||||
|
||||
const QmlDesigner::Imports &imports = model()->imports();
|
||||
QHash<QString, QmlDesigner::Import> effectImports;
|
||||
for (const QmlDesigner::Import &import : imports) {
|
||||
if (import.url().startsWith(effectPrefix)) {
|
||||
QString type = import.url().split('.').last();
|
||||
effectImports.insert(type, import);
|
||||
}
|
||||
}
|
||||
|
||||
const QList<QmlDesigner::ModelNode> allNodes = allModelNodes();
|
||||
for (const QmlDesigner::ModelNode &node : allNodes) {
|
||||
if (QmlDesigner::QmlItemNode(node).isEffectItem())
|
||||
effectImports.remove(node.simplifiedTypeName());
|
||||
}
|
||||
|
||||
if (!effectImports.isEmpty()) {
|
||||
QmlDesigner::Imports removeImports;
|
||||
for (const QmlDesigner::Import &import : effectImports)
|
||||
removeImports.append(import);
|
||||
model()->changeImports({}, removeImports);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -29,10 +29,12 @@ public:
|
||||
void modelAboutToBeDetached(QmlDesigner::Model *model) override;
|
||||
void selectedNodesChanged(const QList<QmlDesigner::ModelNode> &selectedNodeList,
|
||||
const QList<QmlDesigner::ModelNode> &lastSelectedNodeList) override;
|
||||
void nodeAboutToBeRemoved(const QmlDesigner::ModelNode &removedNode) override;
|
||||
|
||||
private:
|
||||
void customNotification(const AbstractView *view, const QString &identifier,
|
||||
const QList<QmlDesigner::ModelNode> &nodeList, const QList<QVariant> &data) override;
|
||||
void removeUnusedEffectImports();
|
||||
|
||||
QPointer<EffectComposerWidget> m_widget;
|
||||
QString m_currProjectPath;
|
||||
|
||||
@@ -45,7 +45,6 @@ WidgetInfo InsightView::widgetInfo()
|
||||
return createWidgetInfo(m_insightWidget.data(),
|
||||
"QtInsight",
|
||||
WidgetInfo::RightPane,
|
||||
0,
|
||||
tr("Qt Insight"));
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ if (APPLE)
|
||||
set(QmlDesignerPluginInstallPrefix "${IDE_PLUGIN_PATH}/QmlDesigner")
|
||||
endif()
|
||||
|
||||
|
||||
set(BUILD_NOT_DESIGNSTUDIO NOT ${BUILD_NOT_DESIGNSTUDIO})
|
||||
option(QTC_USE_QML_DESIGNER_LITE "Use Qml Designer Lite" ${BUILD_NOT_DESIGNSTUDIO})
|
||||
add_feature_info("Qml Designer Lite" ${QTC_USE_QML_DESIGNER_LITE} "")
|
||||
|
||||
option(USE_PROJECTSTORAGE "Use ProjectStorage" ${QTC_USE_QML_DESIGNER_LITE})
|
||||
|
||||
|
||||
env_with_default("QTC_ENABLE_PROJECT_STORAGE_TRACING" ENV_QTC_ENABLE_PROJECT_STORAGE_TRACING OFF)
|
||||
option(ENABLE_PROJECT_STORAGE_TRACING "Enable sqlite tracing" ${ENV_QTC_ENABLE_PROJECT_STORAGE_TRACING})
|
||||
add_feature_info("Sqlite tracing" ${ENABLE_PROJECT_STORAGE_TRACING} "")
|
||||
@@ -34,9 +34,10 @@ add_feature_info("Meta info tracing" ${ENABLE_METAINFO_TRACING} "")
|
||||
add_qtc_library(QmlDesignerUtils STATIC
|
||||
DEPENDS
|
||||
Qt::Gui Utils Qt::QmlPrivate
|
||||
|
||||
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/utils
|
||||
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/utils
|
||||
PUBLIC_COMPILE_OPTIONS
|
||||
$<$<COMPILE_LANG_AND_ID:CXX,Clang>:-Wno-unneeded-internal-declaration>
|
||||
SOURCES
|
||||
asset.cpp asset.h
|
||||
designeralgorithm.h
|
||||
@@ -47,16 +48,14 @@ add_qtc_library(QmlDesignerUtils STATIC
|
||||
ktximage.cpp ktximage.h
|
||||
imageutils.cpp imageutils.h
|
||||
qmldesignerutils_global.h
|
||||
version.cpp version.h
|
||||
)
|
||||
|
||||
if (TARGET QmlDesignerUtils)
|
||||
target_compile_options(QmlDesignerUtils PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,Clang,GNU>:-Wno-error=maybe-uninitialized>)
|
||||
target_compile_options(QmlDesignerUtils PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,Clang>:-Wno-unneeded-internal-declaration>)
|
||||
endif()
|
||||
|
||||
extend_qtc_library(QmlDesignerUtils
|
||||
CONDITION ENABLE_COMPILE_WARNING_AS_ERROR
|
||||
PROPERTIES COMPILE_WARNING_AS_ERROR ON
|
||||
PUBLIC_COMPILE_OPTIONS
|
||||
$<$<COMPILE_LANG_AND_ID:CXX,Clang,GNU>:-Wno-error=maybe-uninitialized>
|
||||
)
|
||||
|
||||
add_qtc_library(QmlDesignerCore STATIC
|
||||
@@ -95,10 +94,17 @@ add_qtc_library(QmlDesignerCore STATIC
|
||||
PUBLIC_INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/designercore
|
||||
${CMAKE_CURRENT_LIST_DIR}/designercore/include
|
||||
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/designercore
|
||||
)
|
||||
|
||||
extend_qtc_library(QmlDesignerCore
|
||||
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/designercore/designercoreutils
|
||||
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/designercore/designercoreutils
|
||||
SOURCES
|
||||
rewritertransaction.cpp rewritertransaction.h
|
||||
generatedcomponentutils.cpp generatedcomponentutils.h
|
||||
modelmerger.cpp modelmerger.h
|
||||
modelutils.cpp modelutils.h
|
||||
skipiterator.h
|
||||
stylesheetmerger.cpp stylesheetmerger.h
|
||||
uniquename.cpp uniquename.h
|
||||
)
|
||||
|
||||
@@ -117,10 +123,11 @@ extend_qtc_library(QmlDesignerCore
|
||||
extend_qtc_library(QmlDesignerCore
|
||||
CONDITION ENABLE_COMPILE_WARNING_AS_ERROR
|
||||
PROPERTIES COMPILE_WARNING_AS_ERROR ON
|
||||
PUBLIC_COMPILE_OPTIONS $<$<COMPILE_LANG_AND_ID:CXX,Clang,GNU>:-Wno-error=maybe-uninitialized>
|
||||
)
|
||||
|
||||
extend_qtc_library(QmlDesignerCore
|
||||
CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0 AND Qt6_VERSION VERSION_LESS 6.6.0
|
||||
CONDITION IS_SUPPORTED_PROJECTSTORAGE_QT
|
||||
PUBLIC_DEFINES QDS_BUILD_QMLPARSER
|
||||
)
|
||||
extend_qtc_library(QmlDesignerCore
|
||||
@@ -279,9 +286,7 @@ extend_qtc_library(QmlDesignerCore
|
||||
invalidslideindexexception.h
|
||||
mathutils.h
|
||||
modelfwd.h
|
||||
modelmerger.h
|
||||
modelnode.h
|
||||
modelnodepositionstorage.h
|
||||
module.h
|
||||
nodeabstractproperty.h
|
||||
nodeinstance.h
|
||||
@@ -305,9 +310,9 @@ extend_qtc_library(QmlDesignerCore
|
||||
qmltimelinekeyframegroup.h
|
||||
removebasestateexception.h
|
||||
rewritingexception.h
|
||||
rewritertransaction.h
|
||||
signalhandlerproperty.h
|
||||
stringutils.h
|
||||
stylesheetmerger.h
|
||||
synchronousimagecache.h
|
||||
variantproperty.h
|
||||
)
|
||||
@@ -362,8 +367,8 @@ extend_qtc_library(QmlDesignerCore
|
||||
abstractview.cpp
|
||||
anchorline.cpp
|
||||
annotation.cpp
|
||||
auxiliarypropertystorageview.cpp auxiliarypropertystorageview.h
|
||||
bindingproperty.cpp
|
||||
componenttextmodifier.cpp
|
||||
documentmessage.cpp
|
||||
import.cpp
|
||||
internalbindingproperty.cpp
|
||||
@@ -384,25 +389,46 @@ extend_qtc_library(QmlDesignerCore
|
||||
internalvariantproperty.h
|
||||
model.cpp
|
||||
model_p.h
|
||||
modelmerger.cpp
|
||||
modelnode.cpp
|
||||
modelnodepositionrecalculator.cpp
|
||||
modelnodepositionrecalculator.h
|
||||
modelnodepositionstorage.cpp
|
||||
modelresourcemanagementinterface.h
|
||||
modelresourcemanagementfwd.h
|
||||
modelresourcemanagement.cpp modelresourcemanagement.h
|
||||
modeltotextmerger.cpp
|
||||
modeltotextmerger.h
|
||||
modelutils.cpp
|
||||
modelutils.h
|
||||
nodeabstractproperty.cpp
|
||||
nodelistproperty.cpp
|
||||
nodeproperty.cpp
|
||||
signalhandlerproperty.cpp
|
||||
variantproperty.cpp
|
||||
)
|
||||
|
||||
extend_qtc_library(QmlDesignerCore
|
||||
INCLUDES ${CMAKE_CURRENT_LIST_DIR}/designercore/rewriter
|
||||
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/designercore/rewriter
|
||||
SOURCES
|
||||
componenttextmodifier.cpp
|
||||
modelnodepositionrecalculator.cpp
|
||||
modelnodepositionrecalculator.h
|
||||
modelnodepositionstorage.cpp
|
||||
modelnodepositionstorage.h
|
||||
modeltotextmerger.cpp
|
||||
modeltotextmerger.h
|
||||
plaintexteditmodifier.cpp
|
||||
propertycontainer.cpp
|
||||
propertynode.cpp
|
||||
propertyparser.cpp
|
||||
rewriteaction.cpp
|
||||
rewriteaction.h
|
||||
rewriteactioncompressor.cpp
|
||||
rewriteactioncompressor.h
|
||||
rewritertransaction.cpp
|
||||
rewriterview.cpp
|
||||
textmodifier.cpp
|
||||
texttomodelmerger.cpp
|
||||
texttomodelmerger.h
|
||||
)
|
||||
extend_qtc_library(QmlDesignerCore
|
||||
INCLUDES ${CMAKE_CURRENT_LIST_DIR}/designercore/qmltools
|
||||
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/designercore/qmltools
|
||||
SOURCES
|
||||
qml3dnode.cpp
|
||||
qmlanchors.cpp
|
||||
qmlchangeset.cpp
|
||||
@@ -416,18 +442,6 @@ extend_qtc_library(QmlDesignerCore
|
||||
qmltimeline.cpp
|
||||
qmltimelinekeyframegroup.cpp
|
||||
qmlvisualnode.cpp
|
||||
rewriteaction.cpp
|
||||
rewriteaction.h
|
||||
rewriteactioncompressor.cpp
|
||||
rewriteactioncompressor.h
|
||||
rewriterview.cpp
|
||||
signalhandlerproperty.cpp
|
||||
skipiterator.h
|
||||
stylesheetmerger.cpp
|
||||
textmodifier.cpp
|
||||
texttomodelmerger.cpp
|
||||
texttomodelmerger.h
|
||||
variantproperty.cpp
|
||||
)
|
||||
|
||||
extend_qtc_library(QmlDesignerCore
|
||||
@@ -444,6 +458,7 @@ extend_qtc_library(QmlDesignerCore
|
||||
SOURCES_PREFIX designercore/projectstorage
|
||||
PUBLIC_INCLUDES designercore/projectstorage
|
||||
SOURCES_PROPERTIES SKIP_AUTOGEN ON
|
||||
DEFINES QML_DOM_MSVC2019_COMPAT # can be removed for Qt 6.8
|
||||
SOURCES
|
||||
commontypecache.h
|
||||
directorypathcompressor.h
|
||||
@@ -493,7 +508,7 @@ add_qtc_plugin(QmlDesigner
|
||||
PLUGIN_MANUAL_DEPENDS LicenseChecker ${IDE_VERSION} optional
|
||||
DEPENDS
|
||||
QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
|
||||
Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg QmlDesignerCore Sqlite
|
||||
Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg QmlDesignerCore Sqlite Zip
|
||||
PUBLIC_DEPENDS
|
||||
QmlDesignerUtils QmlPuppetCommunication QmlDesignerBase
|
||||
DEFINES
|
||||
@@ -516,10 +531,12 @@ add_qtc_plugin(QmlDesigner
|
||||
${CMAKE_CURRENT_LIST_DIR}/components/propertyeditor
|
||||
${CMAKE_CURRENT_LIST_DIR}/components/stateseditor
|
||||
${CMAKE_CURRENT_LIST_DIR}/components/texteditor
|
||||
${CMAKE_CURRENT_LIST_DIR}/components/designsystem
|
||||
PUBLIC_INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/designercore #can not be a public dependency -> EXCLUDE_FROM_INSTALL in QmlDesignerCore
|
||||
${CMAKE_CURRENT_LIST_DIR}/designercore/include #iwidgetplugin.h is used by other plugins
|
||||
${CMAKE_CURRENT_LIST_DIR}/designercore/designercoreutils
|
||||
SOURCES
|
||||
designmodewidget.cpp designmodewidget.h
|
||||
documentmanager.cpp documentmanager.h
|
||||
@@ -550,6 +567,7 @@ add_qtc_plugin(QmlDesigner
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
CONDITION ENABLE_COMPILE_WARNING_AS_ERROR
|
||||
PROPERTIES COMPILE_WARNING_AS_ERROR ON
|
||||
PUBLIC_COMPILE_OPTIONS $<$<COMPILE_LANG_AND_ID:CXX,Clang,GNU>:-Wno-error=maybe-uninitialized>
|
||||
)
|
||||
|
||||
function(get_and_add_as_subdirectory name repository git_tag build_dir source_dir source_subdir)
|
||||
@@ -659,9 +677,11 @@ extend_qtc_plugin(QmlDesigner
|
||||
edit3dwidget.cpp edit3dwidget.h
|
||||
edit3dcanvas.cpp edit3dcanvas.h
|
||||
edit3dactions.cpp edit3dactions.h
|
||||
edit3dmaterialsaction.cpp edit3dmaterialsaction.h
|
||||
edit3dtoolbarmenu.cpp edit3dtoolbarmenu.h
|
||||
backgroundcolorselection.cpp backgroundcolorselection.h
|
||||
bakelights.cpp bakelights.h
|
||||
indicatoractionwidget.cpp indicatoractionwidget.h
|
||||
snapconfiguration.cpp snapconfiguration.h
|
||||
cameraspeedconfiguration.cpp cameraspeedconfiguration.h
|
||||
bakelightsdatamodel.cpp bakelightsdatamodel.h
|
||||
@@ -813,10 +833,12 @@ extend_qtc_plugin(QmlDesigner
|
||||
propertyeditorvalue.cpp propertyeditorvalue.h
|
||||
propertyeditorview.cpp propertyeditorview.h
|
||||
propertyeditorwidget.cpp propertyeditorwidget.h
|
||||
propertynamevalidator.cpp propertynamevalidator.h
|
||||
tooltip.cpp tooltip.h
|
||||
qmlanchorbindingproxy.cpp qmlanchorbindingproxy.h
|
||||
qmlmodelnodeproxy.cpp qmlmodelnodeproxy.h
|
||||
quick2propertyeditorview.cpp quick2propertyeditorview.h
|
||||
propertyeditorutils.cpp propertyeditorutils.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
@@ -836,6 +858,9 @@ extend_qtc_plugin(QmlDesigner
|
||||
contentlibraryeffectscategory.cpp contentlibraryeffectscategory.h
|
||||
contentlibraryeffectsmodel.cpp contentlibraryeffectsmodel.h
|
||||
contentlibraryusermodel.cpp contentlibraryusermodel.h
|
||||
usercategory.cpp usercategory.h
|
||||
useritemcategory.cpp useritemcategory.h
|
||||
usertexturecategory.cpp usertexturecategory.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
@@ -843,6 +868,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
SOURCES
|
||||
materialeditorcontextobject.cpp materialeditorcontextobject.h
|
||||
materialeditordynamicpropertiesproxymodel.cpp materialeditordynamicpropertiesproxymodel.h
|
||||
materialeditorimageprovider.cpp materialeditorimageprovider.h
|
||||
materialeditorqmlbackend.cpp materialeditorqmlbackend.h
|
||||
materialeditortransaction.cpp materialeditortransaction.h
|
||||
materialeditorview.cpp materialeditorview.h
|
||||
@@ -942,7 +968,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX designercore
|
||||
PUBLIC_INCLUDES designercore
|
||||
SOURCES
|
||||
model/basetexteditmodifier.cpp
|
||||
rewriter/basetexteditmodifier.cpp
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
@@ -1149,6 +1175,14 @@ extend_qtc_plugin(QmlDesigner
|
||||
toolbarbackend.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX components/designsystem
|
||||
SOURCES
|
||||
dsconstants.h
|
||||
dsthememanager.h dsthememanager.cpp
|
||||
dsthemegroup.cpp dsthemegroup.h
|
||||
)
|
||||
|
||||
add_qtc_plugin(assetexporterplugin
|
||||
PLUGIN_CLASS AssetExporterPlugin
|
||||
CONDITION TARGET QmlDesigner
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "exportnotification.h"
|
||||
|
||||
#include <designdocument.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <qmlitemnode.h>
|
||||
|
||||
@@ -63,7 +63,7 @@ WidgetInfo AssetsLibraryView::widgetInfo()
|
||||
this};
|
||||
}
|
||||
|
||||
return createWidgetInfo(m_widget.data(), "Assets", WidgetInfo::LeftPane, 0, tr("Assets"));
|
||||
return createWidgetInfo(m_widget.data(), "Assets", WidgetInfo::LeftPane, tr("Assets"));
|
||||
}
|
||||
|
||||
void AssetsLibraryView::customNotification(const AbstractView * /*view*/,
|
||||
|
||||
@@ -413,9 +413,13 @@ void AssetsLibraryWidget::handleExtFilesDrop(const QList<QUrl> &simpleFilePaths,
|
||||
targetDirPath,
|
||||
isDropOnRoot);
|
||||
if (result.status() == AddFilesResult::Failed) {
|
||||
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
|
||||
tr("Could not add %1 to project.")
|
||||
.arg(simpleFilePathStrings.join(' ')));
|
||||
QWidget *w = Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
|
||||
tr("Could not add %1 to project.")
|
||||
.arg(simpleFilePathStrings.join(' ')));
|
||||
// Avoid multiple modal dialogs open at the same time
|
||||
auto mb = qobject_cast<QMessageBox *>(w);
|
||||
if (mb && !complexFilePathStrings.empty())
|
||||
mb->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -609,6 +613,9 @@ void AssetsLibraryWidget::addResources(const QStringList &files, bool showDialog
|
||||
categoryFileNames.insert(category, fileName);
|
||||
}
|
||||
|
||||
QStringList unsupportedFiles;
|
||||
QStringList failedOpsFiles;
|
||||
|
||||
for (const QString &category : categoryFileNames.uniqueKeys()) {
|
||||
QStringList fileNames = categoryFileNames.values(category);
|
||||
AddResourceOperation operation = categoryToOperation.value(category);
|
||||
@@ -617,9 +624,7 @@ void AssetsLibraryWidget::addResources(const QStringList &files, bool showDialog
|
||||
AddFilesResult result = operation(fileNames,
|
||||
document->fileName().parentDir().toString(), showDialog);
|
||||
if (result.status() == AddFilesResult::Failed) {
|
||||
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
|
||||
tr("Could not add %1 to project.")
|
||||
.arg(fileNames.join(' ')));
|
||||
failedOpsFiles.append(fileNames);
|
||||
} else {
|
||||
if (!result.directory().isEmpty()) {
|
||||
emit directoryCreated(result.directory());
|
||||
@@ -634,11 +639,24 @@ void AssetsLibraryWidget::addResources(const QStringList &files, bool showDialog
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
|
||||
tr("Could not add %1 to project. Unsupported file format.")
|
||||
.arg(fileNames.join(' ')));
|
||||
unsupportedFiles.append(fileNames);
|
||||
}
|
||||
}
|
||||
|
||||
if (!failedOpsFiles.isEmpty()) {
|
||||
QWidget *w = Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
|
||||
tr("Could not add %1 to project.")
|
||||
.arg(failedOpsFiles.join(' ')));
|
||||
// Avoid multiple modal dialogs open at the same time
|
||||
auto mb = qobject_cast<QMessageBox *>(w);
|
||||
if (mb && !unsupportedFiles.isEmpty())
|
||||
mb->exec();
|
||||
}
|
||||
if (!unsupportedFiles.isEmpty()) {
|
||||
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
|
||||
tr("Could not add %1 to project. Unsupported file format.")
|
||||
.arg(unsupportedFiles.join(' ')));
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsLibraryWidget::addAssetsToContentLibrary(const QStringList &assetPaths)
|
||||
|
||||
@@ -9,197 +9,284 @@ namespace QmlDesigner {
|
||||
|
||||
namespace ComponentCoreConstants {
|
||||
|
||||
const char rootCategory[] = "";
|
||||
inline constexpr char rootCategory[] = "";
|
||||
|
||||
const char selectionCategory[] = "Selection";
|
||||
const char connectionsCategory[] = "Connections";
|
||||
const char arrangeCategory[] = "Arrange";
|
||||
const char qmlPreviewCategory[] = "QmlPreview";
|
||||
const char editCategory[] = "Edit";
|
||||
const char anchorsCategory[] = "Anchors";
|
||||
const char positionerCategory[] = "Position";
|
||||
const char groupCategory[] = "Group";
|
||||
const char snappingCategory[] = "Snapping";
|
||||
const char layoutCategory[] = "Layout";
|
||||
const char flowCategory[] = "Flow";
|
||||
const char flowEffectCategory[] = "FlowEffect";
|
||||
const char flowConnectionCategory[] = "FlowConnection";
|
||||
const char stackedContainerCategory[] = "StackedContainer";
|
||||
const char genericToolBarCategory[] = "GenericToolBar";
|
||||
const char eventListCategory[] = "QmlEventList";
|
||||
inline constexpr char selectionCategory[] = "Selection";
|
||||
inline constexpr char connectionsCategory[] = "Connections";
|
||||
inline constexpr char arrangeCategory[] = "Arrange";
|
||||
inline constexpr char qmlPreviewCategory[] = "QmlPreview";
|
||||
inline constexpr char editCategory[] = "Edit";
|
||||
inline constexpr char anchorsCategory[] = "Anchors";
|
||||
inline constexpr char positionerCategory[] = "Position";
|
||||
inline constexpr char groupCategory[] = "Group";
|
||||
inline constexpr char snappingCategory[] = "Snapping";
|
||||
inline constexpr char layoutCategory[] = "Layout";
|
||||
inline constexpr char flowCategory[] = "Flow";
|
||||
inline constexpr char flowEffectCategory[] = "FlowEffect";
|
||||
inline constexpr char flowConnectionCategory[] = "FlowConnection";
|
||||
inline constexpr char stackedContainerCategory[] = "StackedContainer";
|
||||
inline constexpr char genericToolBarCategory[] = "GenericToolBar";
|
||||
inline constexpr char eventListCategory[] = "QmlEventList";
|
||||
|
||||
const char toFrontCommandId[] = "ToFront";
|
||||
const char toBackCommandId[] = "ToBack";
|
||||
const char raiseCommandId[] = "Raise";
|
||||
const char lowerCommandId[] = "Lower";
|
||||
const char resetZCommandId[] = "ResetZ";
|
||||
const char reverseCommandId[] = "Reverse";
|
||||
const char resetSizeCommandId[] = "ResetSize";
|
||||
const char resetPositionCommandId[] = "ResetPosition";
|
||||
const char copyFormatCommandId[] = "CopyFormat";
|
||||
const char applyFormatCommandId[] = "ApplyFormat";
|
||||
const char visiblityCommandId[] = "ToggleVisiblity";
|
||||
const char anchorsFillCommandId[] = "AnchorsFill";
|
||||
const char anchorsResetCommandId[] = "AnchorsReset";
|
||||
inline constexpr char toFrontCommandId[] = "ToFront";
|
||||
inline constexpr char toBackCommandId[] = "ToBack";
|
||||
inline constexpr char raiseCommandId[] = "Raise";
|
||||
inline constexpr char lowerCommandId[] = "Lower";
|
||||
inline constexpr char resetZCommandId[] = "ResetZ";
|
||||
inline constexpr char reverseCommandId[] = "Reverse";
|
||||
inline constexpr char resetSizeCommandId[] = "ResetSize";
|
||||
inline constexpr char resetPositionCommandId[] = "ResetPosition";
|
||||
inline constexpr char copyFormatCommandId[] = "CopyFormat";
|
||||
inline constexpr char applyFormatCommandId[] = "ApplyFormat";
|
||||
inline constexpr char visiblityCommandId[] = "ToggleVisiblity";
|
||||
inline constexpr char anchorsFillCommandId[] = "AnchorsFill";
|
||||
inline constexpr char anchorsResetCommandId[] = "AnchorsReset";
|
||||
|
||||
const char anchorParentTopAndBottomCommandId[] = "AnchorParentTopAndBottom";
|
||||
const char anchorParentLeftAndRightCommandId[] = "AnchorParentLeftAndRight";
|
||||
const char anchorParentTopCommandId[] = "AnchorParentTop";
|
||||
const char anchorParentRightCommandId[] = "AnchorParentRight";
|
||||
const char anchorParentBottomCommandId[] = "AnchorParentBottom";
|
||||
const char anchorParentLeftCommandId[] = "AnchorParentLeft";
|
||||
inline constexpr char anchorParentTopAndBottomCommandId[] = "AnchorParentTopAndBottom";
|
||||
inline constexpr char anchorParentLeftAndRightCommandId[] = "AnchorParentLeftAndRight";
|
||||
inline constexpr char anchorParentTopCommandId[] = "AnchorParentTop";
|
||||
inline constexpr char anchorParentRightCommandId[] = "AnchorParentRight";
|
||||
inline constexpr char anchorParentBottomCommandId[] = "AnchorParentBottom";
|
||||
inline constexpr char anchorParentLeftCommandId[] = "AnchorParentLeft";
|
||||
|
||||
const char removePositionerCommandId[] = "RemovePositioner";
|
||||
const char createFlowActionAreaCommandId[] = "CreateFlowActionArea";
|
||||
const char setFlowStartCommandId[] = "SetFlowStart";
|
||||
const char selectFlowEffectCommandId[] = "SelectFlowEffect";
|
||||
const char layoutRowPositionerCommandId[] = "LayoutRowPositioner";
|
||||
const char layoutColumnPositionerCommandId[] = "LayoutColumnPositioner";
|
||||
const char layoutGridPositionerCommandId[] = "LayoutGridPositioner";
|
||||
const char layoutFlowPositionerCommandId[] = "LayoutFlowPositioner";
|
||||
const char removeLayoutCommandId[] = "RemoveLayout";
|
||||
const char layoutRowLayoutCommandId[] = "LayoutRowLayout";
|
||||
const char layoutColumnLayoutCommandId[] = "LayoutColumnLayout";
|
||||
const char layoutGridLayoutCommandId[] = "LayoutGridLayout";
|
||||
const char layoutFillWidthCommandId[] = "LayoutFillWidth";
|
||||
const char layoutFillHeightCommandId[] = "LayoutFillHeight";
|
||||
const char goIntoComponentCommandId[] = "GoIntoComponent";
|
||||
const char jumpToCodeCommandId[] = "JumpToCode";
|
||||
const char mergeTemplateCommandId[] = "MergeTemplate";
|
||||
const char goToImplementationCommandId[] = "GoToImplementation";
|
||||
const char makeComponentCommandId[] = "MakeComponent";
|
||||
const char editMaterialCommandId[] = "EditMaterial";
|
||||
const char addItemToStackedContainerCommandId[] = "AddItemToStackedContainer";
|
||||
const char addTabBarToStackedContainerCommandId[] = "AddTabBarToStackedContainer";
|
||||
const char increaseIndexOfStackedContainerCommandId[] = "IncreaseIndexOfStackedContainer";
|
||||
const char decreaseIndexOfStackedContainerCommandId[] = "DecreaseIndexOfStackedContainer";
|
||||
const char flowAssignEffectCommandId[] = "AssignFlowEffect";
|
||||
const char flowAssignCustomEffectCommandId[] = "AssignFlowCustomEffect";
|
||||
const char addToGroupItemCommandId[] = "AddToGroupItem";
|
||||
const char fitRootToScreenCommandId[] = "FitRootToScreen";
|
||||
const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
|
||||
const char editAnnotationsCommandId[] = "EditAnnotation";
|
||||
const char addMouseAreaFillCommandId[] = "AddMouseAreaFill";
|
||||
const char editIn3dViewCommandId[] = "editIn3dView";
|
||||
inline constexpr char removePositionerCommandId[] = "RemovePositioner";
|
||||
inline constexpr char createFlowActionAreaCommandId[] = "CreateFlowActionArea";
|
||||
inline constexpr char setFlowStartCommandId[] = "SetFlowStart";
|
||||
inline constexpr char selectFlowEffectCommandId[] = "SelectFlowEffect";
|
||||
inline constexpr char layoutRowPositionerCommandId[] = "LayoutRowPositioner";
|
||||
inline constexpr char layoutColumnPositionerCommandId[] = "LayoutColumnPositioner";
|
||||
inline constexpr char layoutGridPositionerCommandId[] = "LayoutGridPositioner";
|
||||
inline constexpr char layoutFlowPositionerCommandId[] = "LayoutFlowPositioner";
|
||||
inline constexpr char removeLayoutCommandId[] = "RemoveLayout";
|
||||
inline constexpr char layoutRowLayoutCommandId[] = "LayoutRowLayout";
|
||||
inline constexpr char layoutColumnLayoutCommandId[] = "LayoutColumnLayout";
|
||||
inline constexpr char layoutGridLayoutCommandId[] = "LayoutGridLayout";
|
||||
inline constexpr char layoutFillWidthCommandId[] = "LayoutFillWidth";
|
||||
inline constexpr char layoutFillHeightCommandId[] = "LayoutFillHeight";
|
||||
inline constexpr char goIntoComponentCommandId[] = "GoIntoComponent";
|
||||
inline constexpr char jumpToCodeCommandId[] = "JumpToCode";
|
||||
inline constexpr char mergeTemplateCommandId[] = "MergeTemplate";
|
||||
inline constexpr char goToImplementationCommandId[] = "GoToImplementation";
|
||||
inline constexpr char makeComponentCommandId[] = "MakeComponent";
|
||||
inline constexpr char importComponentCommandId[] = "ImportComponent";
|
||||
inline constexpr char exportComponentCommandId[] = "ExportComponent";
|
||||
inline constexpr char editMaterialCommandId[] = "EditMaterial";
|
||||
inline constexpr char addToContentLibraryCommandId[] = "AddToContentLibrary";
|
||||
inline constexpr char addItemToStackedContainerCommandId[] = "AddItemToStackedContainer";
|
||||
inline constexpr char addTabBarToStackedContainerCommandId[] = "AddTabBarToStackedContainer";
|
||||
inline constexpr char increaseIndexOfStackedContainerCommandId[]
|
||||
= "IncreaseIndexOfStackedContainer";
|
||||
inline constexpr char decreaseIndexOfStackedContainerCommandId[]
|
||||
= "DecreaseIndexOfStackedContainer";
|
||||
inline constexpr char flowAssignEffectCommandId[] = "AssignFlowEffect";
|
||||
inline constexpr char flowAssignCustomEffectCommandId[] = "AssignFlowCustomEffect";
|
||||
inline constexpr char addToGroupItemCommandId[] = "AddToGroupItem";
|
||||
inline constexpr char fitRootToScreenCommandId[] = "FitRootToScreen";
|
||||
inline constexpr char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
|
||||
inline constexpr char editAnnotationsCommandId[] = "EditAnnotation";
|
||||
inline constexpr char addMouseAreaFillCommandId[] = "AddMouseAreaFill";
|
||||
inline constexpr char editIn3dViewCommandId[] = "editIn3dView";
|
||||
|
||||
const char openSignalDialogCommandId[] = "OpenSignalDialog";
|
||||
const char update3DAssetCommandId[] = "Update3DAsset";
|
||||
inline constexpr char openSignalDialogCommandId[] = "OpenSignalDialog";
|
||||
inline constexpr char update3DAssetCommandId[] = "Update3DAsset";
|
||||
|
||||
const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection");
|
||||
const char connectionsCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connections");
|
||||
const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect");
|
||||
const char selectEffectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select Effect");
|
||||
const char arrangeCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Arrange");
|
||||
const char editCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit");
|
||||
const char anchorsCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Anchors");
|
||||
const char positionerCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Positioner");
|
||||
const char groupCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Group");
|
||||
const char snappingCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Snapping");
|
||||
const char layoutCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout");
|
||||
const char flowCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow");
|
||||
const char flowEffectCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow Effects");
|
||||
const char stackedContainerCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Stacked Container");
|
||||
inline constexpr char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Selection");
|
||||
inline constexpr char connectionsCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Connections");
|
||||
inline constexpr char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Connect");
|
||||
inline constexpr char selectEffectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Select Effect");
|
||||
inline constexpr char arrangeCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Arrange");
|
||||
inline constexpr char editCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit");
|
||||
inline constexpr char anchorsCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Anchors");
|
||||
inline constexpr char positionerCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Positioner");
|
||||
inline constexpr char groupCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Group");
|
||||
inline constexpr char snappingCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Snapping");
|
||||
inline constexpr char layoutCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Layout");
|
||||
inline constexpr char flowCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow");
|
||||
inline constexpr char flowEffectCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Flow Effects");
|
||||
inline constexpr char stackedContainerCategoryDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Stacked Container");
|
||||
|
||||
const char cutSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Cut");
|
||||
const char copySelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Copy");
|
||||
const char pasteSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Paste");
|
||||
const char deleteSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Delete Selection");
|
||||
inline constexpr char cutSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Cut");
|
||||
inline constexpr char copySelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Copy");
|
||||
inline constexpr char pasteSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Paste");
|
||||
inline constexpr char deleteSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Delete Selection");
|
||||
|
||||
const char toFrontDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Bring to Front");
|
||||
const char toBackDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Send to Back");
|
||||
inline constexpr char toFrontDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Bring to Front");
|
||||
inline constexpr char toBackDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Send to Back");
|
||||
|
||||
const char raiseDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Bring Forward");
|
||||
const char lowerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Send Backward");
|
||||
inline constexpr char raiseDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Bring Forward");
|
||||
inline constexpr char lowerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Send Backward");
|
||||
|
||||
const char undoDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Undo");
|
||||
const char redoDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Redo");
|
||||
inline constexpr char undoDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Undo");
|
||||
inline constexpr char redoDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Redo");
|
||||
|
||||
const char visibilityDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Visibility");
|
||||
inline constexpr char visibilityDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Visibility");
|
||||
|
||||
const char resetSizeDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset Size");
|
||||
const char resetPositionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset Position");
|
||||
const char copyFormatDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Copy Formatting");
|
||||
const char applyFormatDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Apply Formatting");
|
||||
inline constexpr char resetSizeDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Reset Size");
|
||||
inline constexpr char resetPositionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Reset Position");
|
||||
inline constexpr char copyFormatDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Copy Formatting");
|
||||
inline constexpr char applyFormatDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Apply Formatting");
|
||||
|
||||
const char enterComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Component");
|
||||
const char JumpToCodeDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Jump to the Code");
|
||||
const char mergeTemplateDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Merge with Template");
|
||||
const char goToImplementationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Go to Implementation");
|
||||
const char makeComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Create Component");
|
||||
const char editMaterialDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Material");
|
||||
const char editAnnotationsDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotations");
|
||||
const char addMouseAreaFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Mouse Area");
|
||||
const char editIn3dViewDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit in 3D View");
|
||||
inline constexpr char enterComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Edit Component");
|
||||
inline constexpr char JumpToCodeDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Jump to the Code");
|
||||
inline constexpr char mergeTemplateDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Merge with Template");
|
||||
inline constexpr char goToImplementationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Go to Implementation");
|
||||
inline constexpr char makeComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Create Component");
|
||||
inline constexpr char editMaterialDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Edit Material");
|
||||
inline constexpr char addToContentLibraryDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Add to Content Library");
|
||||
inline constexpr char importComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Import Component");
|
||||
inline constexpr char exportComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Export Component");
|
||||
inline constexpr char editAnnotationsDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Edit Annotations");
|
||||
inline constexpr char addMouseAreaFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Add Mouse Area");
|
||||
inline constexpr char editIn3dViewDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Edit in 3D View");
|
||||
|
||||
const char openSignalDialogDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Signal Dialog");
|
||||
const char update3DAssetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Update 3D Asset");
|
||||
inline constexpr char openSignalDialogDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Open Signal Dialog");
|
||||
inline constexpr char update3DAssetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Update 3D Asset");
|
||||
|
||||
const char setIdDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Id");
|
||||
inline constexpr char setIdDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Id");
|
||||
|
||||
const char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset z Property");
|
||||
inline constexpr char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Reset z Property");
|
||||
|
||||
const char reverseDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reverse");
|
||||
inline constexpr char reverseDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reverse");
|
||||
|
||||
const char anchorsFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fill Parent");
|
||||
const char anchorsResetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "No Anchors");
|
||||
inline constexpr char anchorsFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Fill Parent");
|
||||
inline constexpr char anchorsResetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"No Anchors");
|
||||
|
||||
const char anchorParentTopAndBottomDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Top And Bottom");
|
||||
const char anchorParentLeftAndRightDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Left And Right");
|
||||
const char anchorParentTopDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Top");
|
||||
const char anchorParentRightDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Right");
|
||||
const char anchorParentBottomDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Bottom");
|
||||
const char anchorParentLeftDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Left");
|
||||
inline constexpr char anchorParentTopAndBottomDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Top And Bottom");
|
||||
inline constexpr char anchorParentLeftAndRightDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Left And Right");
|
||||
inline constexpr char anchorParentTopDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Top");
|
||||
inline constexpr char anchorParentRightDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Right");
|
||||
inline constexpr char anchorParentBottomDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Bottom");
|
||||
inline constexpr char anchorParentLeftDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Left");
|
||||
|
||||
const char layoutColumnPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Column Positioner");
|
||||
const char layoutRowPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Row Positioner");
|
||||
const char layoutGridPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Grid Positioner");
|
||||
const char layoutFlowPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow Positioner");
|
||||
const char removePositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove Positioner");
|
||||
const char createFlowActionAreaDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Create Flow Action");
|
||||
const char setFlowStartDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Flow Start");
|
||||
const char removeLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove Layout");
|
||||
inline constexpr char layoutColumnPositionerDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Column Positioner");
|
||||
inline constexpr char layoutRowPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Row Positioner");
|
||||
inline constexpr char layoutGridPositionerDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Grid Positioner");
|
||||
inline constexpr char layoutFlowPositionerDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Flow Positioner");
|
||||
inline constexpr char removePositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Remove Positioner");
|
||||
inline constexpr char createFlowActionAreaDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Create Flow Action");
|
||||
inline constexpr char setFlowStartDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Set Flow Start");
|
||||
inline constexpr char removeLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Remove Layout");
|
||||
|
||||
const char addToGroupItemDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Group in GroupItem");
|
||||
const char removeGroupItemDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Remove GroupItem");
|
||||
inline constexpr char addToGroupItemDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Group in GroupItem");
|
||||
inline constexpr char removeGroupItemDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Remove GroupItem");
|
||||
|
||||
const char addItemToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Component");
|
||||
const char addTabBarToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Tab Bar");
|
||||
const char increaseIndexToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Increase Index");
|
||||
const char decreaseIndexToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Decrease Index");
|
||||
inline constexpr char addItemToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Add Component");
|
||||
inline constexpr char addTabBarToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Add Tab Bar");
|
||||
inline constexpr char increaseIndexToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Increase Index");
|
||||
inline constexpr char decreaseIndexToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Decrease Index");
|
||||
|
||||
const char layoutColumnLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Column Layout");
|
||||
const char layoutRowLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Row Layout");
|
||||
const char layoutGridLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Grid Layout");
|
||||
inline constexpr char layoutColumnLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Column Layout");
|
||||
inline constexpr char layoutRowLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Row Layout");
|
||||
inline constexpr char layoutGridLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Grid Layout");
|
||||
|
||||
const char layoutFillWidthDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fill Width");
|
||||
const char layoutFillHeightDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fill Height");
|
||||
inline constexpr char layoutFillWidthDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Fill Width");
|
||||
inline constexpr char layoutFillHeightDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Fill Height");
|
||||
|
||||
const char flowAssignEffectDisplayName[] = "Assign FlowEffect ";
|
||||
const char flowAssignCustomEffectDisplayName[] = "Assign Custom FlowEffect ";
|
||||
inline constexpr char flowAssignEffectDisplayName[] = "Assign FlowEffect ";
|
||||
inline constexpr char flowAssignCustomEffectDisplayName[] = "Assign Custom FlowEffect ";
|
||||
|
||||
const char raiseToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Raise selected component.");
|
||||
const char lowerToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Lower selected component.");
|
||||
inline constexpr char raiseToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Raise selected component.");
|
||||
inline constexpr char lowerToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Lower selected component.");
|
||||
|
||||
const char resetSizeToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset size and use implicit size.");
|
||||
const char resetPositionTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset position and use implicit position.");
|
||||
const char copyFormatTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Copy formatting.");
|
||||
const char applyFormatTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Apply formatting.");
|
||||
inline constexpr char resetSizeToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Reset size and use implicit size.");
|
||||
inline constexpr char resetPositionTooltip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Reset position and use implicit position.");
|
||||
inline constexpr char copyFormatTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Copy formatting.");
|
||||
inline constexpr char applyFormatTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Apply formatting.");
|
||||
|
||||
const char anchorsFillToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fill selected component to parent.");
|
||||
const char anchorsResetToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset anchors for selected component.");
|
||||
inline constexpr char anchorsFillToolTip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Fill selected component to parent.");
|
||||
inline constexpr char anchorsResetToolTip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Reset anchors for selected component.");
|
||||
|
||||
const char layoutColumnLayoutToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout selected components in column layout.");
|
||||
const char layoutRowLayoutToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout selected components in row layout.");
|
||||
const char layoutGridLayoutToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout selected components in grid layout.");
|
||||
inline constexpr char layoutColumnLayoutToolTip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Layout selected components in column layout.");
|
||||
inline constexpr char layoutRowLayoutToolTip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Layout selected components in row layout.");
|
||||
inline constexpr char layoutGridLayoutToolTip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Layout selected components in grid layout.");
|
||||
|
||||
const char increaseIndexOfStackedContainerToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Increase index of stacked container.");
|
||||
const char decreaseIndexOfStackedContainerToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Decrease index of stacked container.");
|
||||
const char addItemToStackedContainerToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add component to stacked container.");
|
||||
const char addFlowActionToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add flow action.");
|
||||
inline constexpr char increaseIndexOfStackedContainerToolTip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Increase index of stacked container.");
|
||||
inline constexpr char decreaseIndexOfStackedContainerToolTip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Decrease index of stacked container.");
|
||||
inline constexpr char addItemToStackedContainerToolTip[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerContextMenu", "Add component to stacked container.");
|
||||
inline constexpr char addFlowActionToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Add flow action.");
|
||||
|
||||
const char editListModelDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Edit List Model...");
|
||||
inline constexpr char editListModelDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||
"Edit List Model...");
|
||||
namespace Priorities {
|
||||
enum PrioritiesEnum : int {
|
||||
Top = 0,
|
||||
@@ -241,20 +328,31 @@ enum PrioritiesEnum : int {
|
||||
SignalsDialog,
|
||||
Refactoring,
|
||||
GenericToolBar,
|
||||
Last
|
||||
Last,
|
||||
/******** Section *****************************/
|
||||
AddingAssetsSection = 7000,
|
||||
Add3DToContentLib,
|
||||
ImportComponent,
|
||||
ExportComponent,
|
||||
};
|
||||
};
|
||||
|
||||
const char addImagesDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Image Files");
|
||||
const char addFontsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Font Files");
|
||||
const char addSoundsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Sound Files");
|
||||
const char addVideosDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Video Files");
|
||||
const char addShadersDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Shader Files");
|
||||
const char add3DAssetsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "3D Assets");
|
||||
const char addQt3DSPresentationsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Qt 3D Studio Presentations");
|
||||
const char addCustomEffectDialogDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Effect Composer Files");
|
||||
inline constexpr char addImagesDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Image Files");
|
||||
inline constexpr char addFontsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Font Files");
|
||||
inline constexpr char addSoundsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Sound Files");
|
||||
inline constexpr char addVideosDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Video Files");
|
||||
inline constexpr char addShadersDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Shader Files");
|
||||
inline constexpr char add3DAssetsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"3D Assets");
|
||||
inline constexpr char addQt3DSPresentationsDisplayString[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerAddResources", "Qt 3D Studio Presentations");
|
||||
inline constexpr char addCustomEffectDialogDisplayString[] = QT_TRANSLATE_NOOP(
|
||||
"QmlDesignerAddResources", "Effect Composer Files");
|
||||
|
||||
} //ComponentCoreConstants
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <actioneditor.h>
|
||||
#include <documentmanager.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <viewmanager.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
@@ -733,7 +733,7 @@ public:
|
||||
signalHandler.view()
|
||||
->emitCustomNotification(EditConnectionNotification,
|
||||
{signalHandler.parentModelNode()},
|
||||
{signalHandler.name()});
|
||||
{signalHandler.name().toByteArray()});
|
||||
//ActionEditor::invokeEditor(signalHandler, removeSignal);
|
||||
});
|
||||
|
||||
@@ -1978,6 +1978,26 @@ void DesignerActionManager::createDefaultDesignerActions()
|
||||
&singleSelection,
|
||||
&singleSelection));
|
||||
|
||||
addDesignerAction(new ModelNodeContextMenuAction(
|
||||
importComponentCommandId,
|
||||
importComponentDisplayName,
|
||||
contextIcon(DesignerIcons::CreateIcon), // TODO: placeholder icon
|
||||
rootCategory,
|
||||
QKeySequence(),
|
||||
Priorities::ImportComponent,
|
||||
&importComponent));
|
||||
|
||||
addDesignerAction(new ModelNodeContextMenuAction(
|
||||
exportComponentCommandId,
|
||||
exportComponentDisplayName,
|
||||
contextIcon(DesignerIcons::CreateIcon), // TODO: placeholder icon
|
||||
rootCategory,
|
||||
QKeySequence(),
|
||||
Priorities::ExportComponent,
|
||||
&exportComponent,
|
||||
&is3DNode,
|
||||
&is3DNode));
|
||||
|
||||
addDesignerAction(new ModelNodeContextMenuAction(
|
||||
editMaterialCommandId,
|
||||
editMaterialDisplayName,
|
||||
@@ -1999,6 +2019,17 @@ void DesignerActionManager::createDefaultDesignerActions()
|
||||
[&] (const SelectionContext& context) { mergeWithTemplate(context, m_externalDependencies); },
|
||||
&SelectionContextFunctors::always));
|
||||
|
||||
addDesignerAction(new ModelNodeContextMenuAction(
|
||||
addToContentLibraryCommandId,
|
||||
addToContentLibraryDisplayName,
|
||||
contextIcon(DesignerIcons::CreateIcon), // TODO: placeholder icon
|
||||
rootCategory,
|
||||
QKeySequence(),
|
||||
Priorities::Add3DToContentLib,
|
||||
&add3DAssetToContentLibrary,
|
||||
&enableAddToContentLib,
|
||||
&enableAddToContentLib));
|
||||
|
||||
addDesignerAction(new ActionGroup(
|
||||
"",
|
||||
genericToolBarCategory,
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
#include "groupitemaction.h"
|
||||
|
||||
#include "designermcumanager.h"
|
||||
#include "nodeabstractproperty.h"
|
||||
#include "nodelistproperty.h"
|
||||
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
using namespace QmlDesigner;
|
||||
@@ -81,6 +82,10 @@ inline bool itemsAreGrouped(const SelectionContext &selection)
|
||||
|
||||
bool groupingEnabled(const SelectionContext &selection)
|
||||
{
|
||||
//StudioComponents.GroupItem is not available in Qt for MCUs
|
||||
if (DesignerMcuManager::instance().isMCUProject())
|
||||
return false;
|
||||
|
||||
if (selection.singleNodeIsSelected())
|
||||
return itemsAreGrouped(selection);
|
||||
else
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "modelnodecontextmenu_helper.h"
|
||||
|
||||
#include <bindingproperty.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <modelnode.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <nodeproperty.h>
|
||||
|
||||
@@ -70,6 +70,23 @@ inline bool isModelOrMaterial(const SelectionContext &selectionState)
|
||||
return node.metaInfo().isQtQuick3DModel() || node.metaInfo().isQtQuick3DMaterial();
|
||||
}
|
||||
|
||||
inline bool enableAddToContentLib(const SelectionContext &selectionState)
|
||||
{
|
||||
ModelNode modelNode = selectionState.currentSingleSelectedNode();
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
bool isInBundle = modelNode.type().startsWith(compUtils.componentBundlesTypePrefix().toLatin1());
|
||||
bool isNode3D = modelNode.metaInfo().isQtQuick3DNode();
|
||||
|
||||
return isNode3D && !isInBundle;
|
||||
}
|
||||
|
||||
inline bool is3DNode(const SelectionContext &selectionState)
|
||||
{
|
||||
ModelNode modelNode = selectionState.currentSingleSelectedNode();
|
||||
|
||||
return modelNode.metaInfo().isQtQuick3DNode();
|
||||
}
|
||||
|
||||
inline bool hasEditableMaterial(const SelectionContext &selectionState)
|
||||
{
|
||||
ModelNode node = selectionState.currentSingleSelectedNode();
|
||||
|
||||
@@ -797,6 +797,23 @@ void moveToComponent(const SelectionContext &selectionContext)
|
||||
selectionContext.view()->model()->rewriterView()->moveToComponent(modelNode);
|
||||
}
|
||||
|
||||
void add3DAssetToContentLibrary(const SelectionContext &selectionContext)
|
||||
{
|
||||
ModelNode node = selectionContext.currentSingleSelectedNode();
|
||||
selectionContext.view()->emitCustomNotification("add_3d_to_content_lib", {node});
|
||||
}
|
||||
|
||||
void importComponent(const SelectionContext &selectionContext)
|
||||
{
|
||||
selectionContext.view()->emitCustomNotification("import_bundle_to_project");
|
||||
}
|
||||
|
||||
void exportComponent(const SelectionContext &selectionContext)
|
||||
{
|
||||
ModelNode node = selectionContext.currentSingleSelectedNode();
|
||||
selectionContext.view()->emitCustomNotification("export_item_as_bundle", {node});
|
||||
}
|
||||
|
||||
void goImplementation(const SelectionContext &selectionState)
|
||||
{
|
||||
addSignalHandlerOrGotoImplementation(selectionState, false);
|
||||
@@ -1622,7 +1639,7 @@ void addMouseAreaFill(const SelectionContext &selectionContext)
|
||||
QmlDesigner::ModelNode mouseAreaNode = selectionContext.view()->createModelNode(
|
||||
"QtQuick.MouseArea", itemMetaInfo.majorVersion(), itemMetaInfo.minorVersion());
|
||||
#endif
|
||||
mouseAreaNode.validId();
|
||||
mouseAreaNode.ensureIdExists();
|
||||
|
||||
modelNode.defaultNodeListProperty().reparentHere(mouseAreaNode);
|
||||
QmlItemNode mouseAreaItemNode(mouseAreaNode);
|
||||
|
||||
@@ -96,6 +96,9 @@ void addSignalHandlerOrGotoImplementation(const SelectionContext &selectionState
|
||||
void removeLayout(const SelectionContext &selectionContext);
|
||||
void removePositioner(const SelectionContext &selectionContext);
|
||||
void moveToComponent(const SelectionContext &selectionContext);
|
||||
void add3DAssetToContentLibrary(const SelectionContext &selectionContext);
|
||||
void importComponent(const SelectionContext &selectionContext);
|
||||
void exportComponent(const SelectionContext &selectionContext);
|
||||
PropertyName getIndexPropertyName(const ModelNode &modelNode);
|
||||
void addItemToStackedContainer(const SelectionContext &selectionContext);
|
||||
void increaseIndexOfStackedContainer(const SelectionContext &selectionContext);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <qmlprojectmanager/buildsystem/qmlbuildsystem.h>
|
||||
#include <qmlprojectmanager/qmlprojectconstants.h>
|
||||
#include <qmlprojectmanager/cmakegen/filetypes.h>
|
||||
|
||||
#include <qtsupport/qtkitaspect.h>
|
||||
|
||||
@@ -143,41 +144,17 @@ void generateMenuEntry(QObject *parent)
|
||||
exportMenu->addAction(cmd2, QmlProjectManager::Constants::G_EXPORT_GENERATE);
|
||||
}
|
||||
|
||||
bool skipSuffix(const QString &fileName)
|
||||
{
|
||||
const QStringList suffixes = {".pri",
|
||||
".pro",
|
||||
".user",
|
||||
".qrc",
|
||||
".qds",
|
||||
"CMakeLists.txt",
|
||||
".db",
|
||||
".tmp",
|
||||
".TMP",
|
||||
".metainfo",
|
||||
".qtds",
|
||||
".db-shm",
|
||||
".db-wal"};
|
||||
|
||||
for (const auto &suffix : suffixes)
|
||||
if (fileName.endsWith(suffix))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList getProjectFileList()
|
||||
{
|
||||
const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
||||
const FilePaths paths = project->files(ProjectExplorer::Project::AllFiles);
|
||||
|
||||
const QDir dir(project->projectFilePath().parentDir().toString());
|
||||
QStringList selectedFileList;
|
||||
|
||||
const Utils::FilePath dir(project->projectFilePath().parentDir());
|
||||
for (const FilePath &path : paths) {
|
||||
QString relativePath = dir.relativeFilePath(path.toString());
|
||||
if (!skipSuffix(relativePath))
|
||||
selectedFileList.append(relativePath);
|
||||
const Utils::FilePath relativePath = path.relativePathFrom(dir);
|
||||
if (QmlProjectManager::isResource(relativePath))
|
||||
selectedFileList.append(relativePath.path());
|
||||
}
|
||||
|
||||
return selectedFileList;
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace QmlDesigner::ResourceGenerator {
|
||||
|
||||
QMLDESIGNERCOMPONENTS_EXPORT void generateMenuEntry(QObject *parent);
|
||||
QMLDESIGNERCOMPONENTS_EXPORT QStringList getProjectFileList();
|
||||
QMLDESIGNERCOMPONENTS_EXPORT bool skipSuffix(const QString &fileName);
|
||||
QMLDESIGNERCOMPONENTS_EXPORT bool createQrcFile(const Utils::FilePath &qrcFilePath);
|
||||
QMLDESIGNERCOMPONENTS_EXPORT bool createQmlrcFile(const Utils::FilePath &qmlrcFilePath);
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@ Theme::Theme(Utils::Theme *originTheme, QObject *parent)
|
||||
"qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml")
|
||||
.toString();
|
||||
|
||||
QQmlEngine* engine = new QQmlEngine(this);
|
||||
QQmlEngine *engine = new QQmlEngine(this);
|
||||
setupTheme(engine);
|
||||
QQmlComponent component(engine, QUrl::fromLocalFile(constantsPath));
|
||||
|
||||
if (component.status() == QQmlComponent::Ready) {
|
||||
@@ -153,8 +154,7 @@ QPixmap Theme::getPixmap(const QString &id)
|
||||
|
||||
QString Theme::getIconUnicode(Theme::Icon i)
|
||||
{
|
||||
if (!instance()->m_constants)
|
||||
return QString();
|
||||
QTC_ASSERT(instance()->m_constants, return {});
|
||||
|
||||
const QMetaObject *m = instance()->metaObject();
|
||||
const char *enumName = "Icon";
|
||||
@@ -172,6 +172,7 @@ QString Theme::getIconUnicode(Theme::Icon i)
|
||||
|
||||
QString Theme::getIconUnicode(const QString &name)
|
||||
{
|
||||
QTC_ASSERT(instance()->m_constants, return {});
|
||||
return instance()->m_constants->property(name.toStdString().data()).toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,19 @@
|
||||
#include <itemlibraryview.h>
|
||||
#include <materialbrowserview.h>
|
||||
#include <materialeditorview.h>
|
||||
#include <model/auxiliarypropertystorageview.h>
|
||||
#include <navigatorview.h>
|
||||
#include <nodeinstanceview.h>
|
||||
#include <propertyeditorview.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <rewriterview.h>
|
||||
#include <stateseditorview.h>
|
||||
#include <texteditorview.h>
|
||||
#include <textureeditorview.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <sqlitedatabase.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <advanceddockingsystem/dockwidget.h>
|
||||
@@ -49,6 +51,7 @@ public:
|
||||
ViewManagerData(AsynchronousImageCache &imageCache,
|
||||
ExternalDependenciesInterface &externalDependencies)
|
||||
: debugView{externalDependencies}
|
||||
, auxiliaryDataKeyView{auxiliaryDataDatabase, externalDependencies}
|
||||
, designerActionManagerView{externalDependencies}
|
||||
, nodeInstanceView(QCoreApplication::arguments().contains("-capture-puppet-stream")
|
||||
? capturingConnectionManager
|
||||
@@ -78,6 +81,11 @@ public:
|
||||
CapturingConnectionManager capturingConnectionManager;
|
||||
QmlModelState savedState;
|
||||
Internal::DebugView debugView;
|
||||
Sqlite::Database auxiliaryDataDatabase{
|
||||
Utils::PathString{Core::ICore::userResourcePath("auxiliary_data.db").toString()},
|
||||
Sqlite::JournalMode::Wal,
|
||||
Sqlite::LockingMode::Normal};
|
||||
AuxiliaryPropertyStorageView auxiliaryDataKeyView;
|
||||
DesignerActionManagerView designerActionManagerView;
|
||||
NodeInstanceView nodeInstanceView;
|
||||
ContentLibraryView contentLibraryView;
|
||||
@@ -161,7 +169,7 @@ void ViewManager::attachRewriterView()
|
||||
});
|
||||
|
||||
currentModel()->setRewriterView(view);
|
||||
view->reactivateTextMofifierChangeSignals();
|
||||
view->reactivateTextModifierChangeSignals();
|
||||
view->restoreAuxiliaryData();
|
||||
}
|
||||
|
||||
@@ -171,7 +179,7 @@ void ViewManager::attachRewriterView()
|
||||
void ViewManager::detachRewriterView()
|
||||
{
|
||||
if (RewriterView *view = currentDesignDocument()->rewriterView()) {
|
||||
view->deactivateTextMofifierChangeSignals();
|
||||
view->deactivateTextModifierChangeSignals();
|
||||
currentModel()->setRewriterView(nullptr);
|
||||
}
|
||||
}
|
||||
@@ -201,7 +209,8 @@ QList<AbstractView *> ViewManager::views() const
|
||||
QList<AbstractView *> ViewManager::standardViews() const
|
||||
{
|
||||
#ifndef QTC_USE_QML_DESIGNER_LITE
|
||||
QList<AbstractView *> list = {&d->edit3DView,
|
||||
QList<AbstractView *> list = {&d->auxiliaryDataKeyView,
|
||||
&d->edit3DView,
|
||||
&d->formEditorView,
|
||||
&d->textEditorView,
|
||||
&d->assetsLibraryView,
|
||||
@@ -416,23 +425,9 @@ QList<WidgetInfo> ViewManager::widgetInfos() const
|
||||
widgetInfoList.append(view->widgetInfo());
|
||||
}
|
||||
|
||||
Utils::sort(widgetInfoList, [](const WidgetInfo &firstWidgetInfo, const WidgetInfo &secondWidgetInfo) {
|
||||
return firstWidgetInfo.placementPriority < secondWidgetInfo.placementPriority;
|
||||
});
|
||||
|
||||
return widgetInfoList;
|
||||
}
|
||||
|
||||
QWidget *ViewManager::widget(const QString &uniqueId) const
|
||||
{
|
||||
const QList<WidgetInfo> widgetInfoList = widgetInfos();
|
||||
for (const WidgetInfo &widgetInfo : widgetInfoList) {
|
||||
if (widgetInfo.uniqueId == uniqueId)
|
||||
return widgetInfo.widget;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ViewManager::disableWidgets()
|
||||
{
|
||||
for (const auto &view : views())
|
||||
|
||||
@@ -62,7 +62,6 @@ public:
|
||||
}
|
||||
|
||||
QList<WidgetInfo> widgetInfos() const;
|
||||
QWidget *widget(const QString & uniqueId) const;
|
||||
|
||||
void disableWidgets();
|
||||
void enableWidgets();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "backendmodel.h"
|
||||
|
||||
#include "bindingproperty.h"
|
||||
#include "connectioneditorutils.h"
|
||||
#include "connectionview.h"
|
||||
#include "exception.h"
|
||||
#include "nodemetainfo.h"
|
||||
@@ -203,7 +204,7 @@ void BackendModel::addNewBackend()
|
||||
if (dialog.applied()) {
|
||||
QStringList importSplit = dialog.importString().split(" ");
|
||||
if (importSplit.size() != 2) {
|
||||
qWarning() << Q_FUNC_INFO << "invalid import" << importSplit;
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "invalid import" << importSplit;
|
||||
QTC_ASSERT(false, return);
|
||||
}
|
||||
|
||||
@@ -278,7 +279,7 @@ void BackendModel::updatePropertyName(int rowNumber)
|
||||
rootModelNode.removeProperty(oldName);
|
||||
rootModelNode.bindingProperty(newName).setDynamicTypeNameAndExpression(typeName, expression);
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << oldName << newName << "failed...";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << oldName << newName << "failed...";
|
||||
QTC_ASSERT(false, return);
|
||||
}
|
||||
});
|
||||
@@ -290,7 +291,7 @@ void BackendModel::handleDataChanged(const QModelIndex &topLeft, const QModelInd
|
||||
return;
|
||||
|
||||
if (topLeft != bottomRight) {
|
||||
qWarning() << "BackendModel::handleDataChanged multi edit?";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "multi edit?";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -307,7 +308,8 @@ void BackendModel::handleDataChanged(const QModelIndex &topLeft, const QModelInd
|
||||
updatePropertyName(currentRow);
|
||||
} break;
|
||||
|
||||
default: qWarning() << "BindingModel::handleDataChanged column" << currentColumn;
|
||||
default:
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "column" << currentColumn;
|
||||
}
|
||||
|
||||
m_lock = false;
|
||||
|
||||
@@ -89,7 +89,7 @@ void BindingModel::add()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << __FUNCTION__ << " Requires exactly one selected node";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "Requires exactly one selected node";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ QHash<int, QByteArray> BindingModel::roleNames() const
|
||||
|
||||
std::optional<int> BindingModel::rowForProperty(const AbstractProperty &property) const
|
||||
{
|
||||
PropertyName name = property.name();
|
||||
PropertyNameView name = property.name();
|
||||
int internalId = property.parentModelNode().internalId();
|
||||
|
||||
for (int i = 0; i < rowCount(); ++i) {
|
||||
|
||||
@@ -42,7 +42,7 @@ void BindingModelItem::updateProperty(const BindingProperty &property)
|
||||
{
|
||||
setData(property.parentModelNode().internalId(), InternalIdRole);
|
||||
setData(idOrTypeName(property.parentModelNode()), TargetNameRole);
|
||||
setData(property.name(), TargetPropertyNameRole);
|
||||
setData(property.name().toByteArray(), TargetPropertyNameRole);
|
||||
|
||||
// TODO: Make this safe when the new codemodel allows it.
|
||||
if (auto expression = property.expression(); !expression.isEmpty()) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "connectioneditorevaluator.h"
|
||||
#include "connectioneditorutils.h"
|
||||
#include "qmljs/parser/qmljsast_p.h"
|
||||
#include "qmljs/qmljsdocument.h"
|
||||
|
||||
@@ -254,7 +255,7 @@ protected:
|
||||
void throwRecursionDepthError() override
|
||||
{
|
||||
checkValidityAndReturn(false, "Recursion depth problem");
|
||||
qDebug() << Q_FUNC_INFO << this;
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "Recursion depth error";
|
||||
}
|
||||
|
||||
void checkAndResetVariable()
|
||||
@@ -477,7 +478,7 @@ protected:
|
||||
void throwRecursionDepthError() override
|
||||
{
|
||||
setFailed();
|
||||
qDebug() << Q_FUNC_INFO << this;
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "Recursion depth error";
|
||||
}
|
||||
|
||||
void checkAndResetCal()
|
||||
@@ -617,7 +618,7 @@ protected:
|
||||
void throwRecursionDepthError() override
|
||||
{
|
||||
m_failed = true;
|
||||
qDebug() << Q_FUNC_INFO << this;
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "Recursion depth error";
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1082,7 +1083,7 @@ void ConnectionEditorEvaluator::endVisit(QmlJS::AST::StatementList * /*statement
|
||||
void ConnectionEditorEvaluator::throwRecursionDepthError()
|
||||
{
|
||||
d->checkValidityAndReturn(false, "Recursion depth problem");
|
||||
qDebug() << Q_FUNC_INFO << this;
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "Recursion depth error";
|
||||
}
|
||||
|
||||
bool ConnectionEditorEvaluatorPrivate::checkValidityAndReturn(bool valid, const QString &parseError)
|
||||
@@ -1091,7 +1092,7 @@ bool ConnectionEditorEvaluatorPrivate::checkValidityAndReturn(bool valid, const
|
||||
if (m_checkStatus != Status::Failed) {
|
||||
setStatus(Status::Failed);
|
||||
m_errorString = parseError;
|
||||
qDebug() << Q_FUNC_INFO << "Error: " << parseError;
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "Parse error" << parseError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
Q_LOGGING_CATEGORY(ConnectionEditorLog, "qtc.qtquickdesigner.connectioneditor", QtWarningMsg)
|
||||
|
||||
void callLater(const std::function<void()> &fun)
|
||||
{
|
||||
QTimer::singleShot(0, fun);
|
||||
@@ -78,7 +80,7 @@ NodeMetaInfo dynamicTypeNameToNodeMetaInfo(const TypeName &typeName, Model *mode
|
||||
else if (typeName == "var" || typeName == "variant")
|
||||
return model->metaInfo("QML.variant");
|
||||
else
|
||||
qWarning() << __FUNCTION__ << " type " << typeName << "not found";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "type" << typeName << "not found";
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -173,7 +175,7 @@ void convertPropertyType(const T &property, const QVariant &value)
|
||||
if (!node.isValid())
|
||||
return;
|
||||
|
||||
PropertyName name = property.name();
|
||||
PropertyNameView name = property.name();
|
||||
TypeName type = property.dynamicTypeName();
|
||||
node.removeProperty(name);
|
||||
|
||||
@@ -203,7 +205,8 @@ bool isBindingExpression(const QVariant &value)
|
||||
if (value.metaType().id() != QMetaType::QString)
|
||||
return false;
|
||||
|
||||
QRegularExpression regexp("^[a-z_]\\w*|^[A-Z]\\w*\\.{1}([a-z_]\\w*\\.?)+");
|
||||
QRegularExpression regexp("^[a-zA-Z_]\\w*\\.{1}([a-z_]\\w*\\.?)+");
|
||||
// QRegularExpression regexp("^[a-z_]\\w*|^[A-Z]\\w*\\.{1}([a-z_]\\w*\\.?)+");
|
||||
QRegularExpressionMatch match = regexp.match(value.toString());
|
||||
return match.hasMatch();
|
||||
}
|
||||
@@ -301,13 +304,16 @@ std::vector<PropertyMetaInfo> propertiesFromSingleton(const QString &name, Abstr
|
||||
|
||||
QList<AbstractProperty> dynamicPropertiesFromNode(const ModelNode &node)
|
||||
{
|
||||
auto isDynamic = [](const AbstractProperty &p) { return p.isDynamic(); };
|
||||
auto isDynamic = [](const AbstractProperty &p) {
|
||||
return p.isDynamic() || p.isSignalDeclarationProperty();
|
||||
};
|
||||
auto byName = [](const AbstractProperty &a, const AbstractProperty &b) {
|
||||
return a.name() < b.name();
|
||||
};
|
||||
|
||||
QList<AbstractProperty> dynamicProperties = Utils::filtered(node.properties(), isDynamic);
|
||||
Utils::sort(dynamicProperties, byName);
|
||||
|
||||
return dynamicProperties;
|
||||
}
|
||||
|
||||
@@ -326,7 +332,7 @@ QStringList availableTargetProperties(const BindingProperty &bindingProperty)
|
||||
{
|
||||
const ModelNode modelNode = bindingProperty.parentModelNode();
|
||||
if (!modelNode.isValid()) {
|
||||
qWarning() << __FUNCTION__ << " invalid model node";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "invalid model node";
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -368,7 +374,7 @@ QStringList availableSourceProperties(const QString &id,
|
||||
} else if (auto metaInfo = targetProperty.parentModelNode().metaInfo(); metaInfo.isValid()) {
|
||||
targetType = metaInfo.property(targetProperty.name()).propertyType();
|
||||
} else
|
||||
qWarning() << __FUNCTION__ << " no meta info for target node";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "no meta info for target node";
|
||||
|
||||
QStringList possibleProperties;
|
||||
if (!modelNode.isValid()) {
|
||||
@@ -380,7 +386,7 @@ QStringList availableSourceProperties(const QString &id,
|
||||
}
|
||||
return possibleProperties;
|
||||
}
|
||||
qWarning() << __FUNCTION__ << " invalid model node: " << id;
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "invalid model node:" << id;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -406,7 +412,7 @@ QStringList availableSourceProperties(const QString &id,
|
||||
possibleProperties.push_back(QString::fromUtf8(property.name()));
|
||||
}
|
||||
} else {
|
||||
qWarning() << __FUNCTION__ << " no meta info for source node";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "no meta info for source node";
|
||||
}
|
||||
|
||||
return possibleProperties;
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
#include "propertymetainfo.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(ConnectionEditorLog)
|
||||
|
||||
class AbstractView;
|
||||
class AbstractProperty;
|
||||
class BindingProperty;
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "connectionmodel.h"
|
||||
#include "connectioneditorutils.h"
|
||||
#include "connectionview.h"
|
||||
#include "utils/algorithm.h"
|
||||
|
||||
#include <bindingproperty.h>
|
||||
#include <connectioneditorevaluator.h>
|
||||
#include <exception.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <modelnodeoperations.h>
|
||||
#include <nodeabstractproperty.h>
|
||||
#include <nodelistproperty.h>
|
||||
@@ -201,7 +202,7 @@ void ConnectionModel::updateSignalName(int rowNumber)
|
||||
SignalHandlerProperty newSignalHandlerProperty = connectionNode.signalHandlerProperty(newName);
|
||||
updateCustomData(idItem, newSignalHandlerProperty);
|
||||
} else {
|
||||
qWarning() << "BindingModel::updatePropertyName invalid property name";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "invalid property name";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,14 +252,14 @@ void ConnectionModel::updateTargetNode(int rowNumber)
|
||||
});
|
||||
|
||||
} else {
|
||||
qWarning() << "BindingModel::updatePropertyName invalid target id";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "invalid target id";
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionModel::updateCustomData(QStandardItem *item, const SignalHandlerProperty &signalHandlerProperty)
|
||||
{
|
||||
item->setData(signalHandlerProperty.parentModelNode().internalId(), UserRoles::InternalIdRole);
|
||||
item->setData(signalHandlerProperty.name(), UserRoles::TargetPropertyNameRole);
|
||||
item->setData(signalHandlerProperty.name().toByteArray(), UserRoles::TargetPropertyNameRole);
|
||||
item->setData(signalHandlerProperty.parentModelNode()
|
||||
.bindingProperty("target")
|
||||
.resolveToModelNode()
|
||||
@@ -532,7 +533,7 @@ ConnectionModelBackendDelegate *ConnectionModel::delegate()
|
||||
void ConnectionModel::handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
|
||||
{
|
||||
if (topLeft != bottomRight) {
|
||||
qWarning() << "ConnectionModel::handleDataChanged multi edit?";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "multi edit?";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -551,8 +552,8 @@ void ConnectionModel::handleDataChanged(const QModelIndex &topLeft, const QModel
|
||||
case SourceRow: {
|
||||
updateSource(currentRow);
|
||||
} break;
|
||||
|
||||
default: qWarning() << "ConnectionModel::handleDataChanged column" << currentColumn;
|
||||
default:
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "column" << currentColumn;
|
||||
}
|
||||
|
||||
m_lock = false;
|
||||
@@ -1694,9 +1695,9 @@ QVariant ConditionListModel::data(const QModelIndex &index, int role) const
|
||||
return m_tokens.at(index.row()).value;
|
||||
}
|
||||
|
||||
qWarning() << Q_FUNC_INFO << "invalid role";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "invalid role";
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "invalid index";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "invalid index";
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
|
||||
@@ -303,7 +303,7 @@ WidgetInfo ConnectionView::widgetInfo()
|
||||
return createWidgetInfo(d->connectionViewQuickWidget.get(),
|
||||
QLatin1String("ConnectionView"),
|
||||
WidgetInfo::LeftPane,
|
||||
0,
|
||||
|
||||
tr("Connections"));
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ void DynamicPropertiesItem::updateProperty(const AbstractProperty &property)
|
||||
{
|
||||
setData(property.parentModelNode().internalId(), InternalIdRole);
|
||||
setData(idOrTypeName(property.parentModelNode()), TargetNameRole);
|
||||
setData(property.name(), PropertyNameRole);
|
||||
setData(property.name().toByteArray(), PropertyNameRole);
|
||||
setData(property.dynamicTypeName(), PropertyTypeRole);
|
||||
|
||||
if (property.isVariantProperty()) {
|
||||
|
||||
@@ -68,7 +68,7 @@ void DynamicPropertiesModel::add()
|
||||
showErrorMessage(e.description());
|
||||
}
|
||||
} else {
|
||||
qWarning() << "DynamicPropertiesModel::add not one node selected";
|
||||
qCWarning(ConnectionEditorLog) << __FUNCTION__ << "not one node selected";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ void DynamicPropertiesModel::setCurrentProperty(const AbstractProperty &property
|
||||
setCurrentIndex(*index);
|
||||
}
|
||||
|
||||
void DynamicPropertiesModel::setCurrent(int internalId, const PropertyName &name)
|
||||
void DynamicPropertiesModel::setCurrent(int internalId, PropertyNameView name)
|
||||
{
|
||||
if (internalId < 0)
|
||||
return;
|
||||
@@ -195,7 +195,7 @@ AbstractProperty DynamicPropertiesModel::propertyForRow(int row) const
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<int> DynamicPropertiesModel::findRow(int nodeId, const PropertyName &name) const
|
||||
std::optional<int> DynamicPropertiesModel::findRow(int nodeId, PropertyNameView name) const
|
||||
{
|
||||
for (int i = 0; i < rowCount(); ++i) {
|
||||
if (auto *item = itemForRow(i)) {
|
||||
@@ -243,7 +243,7 @@ void DynamicPropertiesModel::addModelNode(const ModelNode &node)
|
||||
|
||||
void DynamicPropertiesModel::addProperty(const AbstractProperty &property)
|
||||
{
|
||||
const PropertyName name = property.name();
|
||||
const PropertyNameView name = property.name();
|
||||
for (int i = 0; i < rowCount(); ++i) {
|
||||
if (auto *item = itemForRow(i)) {
|
||||
if (item->propertyName() > name) {
|
||||
@@ -282,7 +282,7 @@ void DynamicPropertiesModel::commitPropertyType(int row, const TypeName &type)
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicPropertiesModel::commitPropertyName(int row, const PropertyName &name)
|
||||
void DynamicPropertiesModel::commitPropertyName(int row, PropertyNameView name)
|
||||
{
|
||||
AbstractProperty property = propertyForRow(row);
|
||||
if (!property.isValid())
|
||||
@@ -346,7 +346,7 @@ void DynamicPropertiesModel::dispatchPropertyChanges(const AbstractProperty &abs
|
||||
QmlPropertyChanges changes(abstractProperty.parentModelNode());
|
||||
if (changes.target().isValid()) {
|
||||
const ModelNode target = changes.target();
|
||||
const PropertyName propertyName = abstractProperty.name();
|
||||
const PropertyNameView propertyName = abstractProperty.name();
|
||||
const AbstractProperty targetProperty = target.variantProperty(propertyName);
|
||||
if (target.hasProperty(propertyName) && targetProperty.isDynamic())
|
||||
updateItem(targetProperty);
|
||||
|
||||
@@ -46,13 +46,13 @@ public:
|
||||
void reset(const QList<ModelNode> &modelNodes = {});
|
||||
void setCurrentIndex(int i);
|
||||
void setCurrentProperty(const AbstractProperty &property);
|
||||
void setCurrent(int internalId, const PropertyName &name);
|
||||
void setCurrent(int internalId, PropertyNameView name);
|
||||
|
||||
void updateItem(const AbstractProperty &property);
|
||||
void removeItem(const AbstractProperty &property);
|
||||
|
||||
void commitPropertyType(int row, const TypeName &type);
|
||||
void commitPropertyName(int row, const PropertyName &name);
|
||||
void commitPropertyName(int row, PropertyNameView name);
|
||||
void commitPropertyValue(int row, const QVariant &value);
|
||||
|
||||
void dispatchPropertyChanges(const AbstractProperty &abstractProperty);
|
||||
@@ -61,7 +61,7 @@ protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
std::optional<int> findRow(int nodeId, const PropertyName &name) const;
|
||||
std::optional<int> findRow(int nodeId, PropertyNameView name) const;
|
||||
DynamicPropertiesItem *itemForRow(int row) const;
|
||||
DynamicPropertiesItem *itemForProperty(const AbstractProperty &property) const;
|
||||
ModelNode modelNodeForItem(DynamicPropertiesItem *item);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <bindingproperty.h>
|
||||
#include <designeralgorithm.h>
|
||||
#include <exception.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <nodeabstractproperty.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <nodemetainfo.h>
|
||||
@@ -519,47 +519,51 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredPropertyName
|
||||
const std::vector<PropertyName> PropertyTreeModel::getDynamicProperties(
|
||||
const ModelNode &modelNode) const
|
||||
{
|
||||
QList<PropertyName> list = Utils::transform(modelNode.dynamicProperties(),
|
||||
[](const AbstractProperty &property) {
|
||||
return property.name();
|
||||
});
|
||||
auto dynamicProperties = modelNode.dynamicProperties();
|
||||
auto dynamicPropertyNames = Utils::transform<PropertyNameViews>(
|
||||
dynamicProperties, [](const AbstractProperty &property) { return property.name(); });
|
||||
|
||||
QList<PropertyName> filtered
|
||||
= Utils::filtered(list, [this, modelNode](const PropertyName &propertyName) {
|
||||
PropertyName propertyType = modelNode.property(propertyName).dynamicTypeName();
|
||||
switch (m_type) {
|
||||
case AllTypes:
|
||||
return true;
|
||||
case NumberType:
|
||||
return propertyType == "float" || propertyType == "double"
|
||||
|| propertyType == "int";
|
||||
case StringType:
|
||||
return propertyType == "string";
|
||||
case UrlType:
|
||||
return propertyType == "url";
|
||||
case ColorType:
|
||||
return propertyType == "color";
|
||||
case BoolType:
|
||||
return propertyType == "bool";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
auto filtered = Utils::filtered(dynamicPropertyNames, [this, modelNode](PropertyNameView propertyName) {
|
||||
TypeName propertyType = modelNode.property(propertyName).dynamicTypeName();
|
||||
switch (m_type) {
|
||||
case AllTypes:
|
||||
return true;
|
||||
case NumberType:
|
||||
return propertyType == "float" || propertyType == "double" || propertyType == "int";
|
||||
case StringType:
|
||||
return propertyType == "string";
|
||||
case UrlType:
|
||||
return propertyType == "url";
|
||||
case ColorType:
|
||||
return propertyType == "color";
|
||||
case BoolType:
|
||||
return propertyType == "bool";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return Utils::sorted(std::vector<PropertyName>(filtered.begin(), filtered.end()));
|
||||
auto sorted = Utils::sorted(filtered);
|
||||
|
||||
return Utils::transform<std::vector<PropertyName>>(sorted, [](PropertyNameView propertyName) {
|
||||
return propertyName.toByteArray();
|
||||
});
|
||||
}
|
||||
|
||||
const std::vector<PropertyName> PropertyTreeModel::getDynamicSignals(const ModelNode &modelNode) const
|
||||
{
|
||||
QList<PropertyName> list = Utils::transform(modelNode.dynamicProperties(),
|
||||
[](const AbstractProperty &property) {
|
||||
if (property.isSignalDeclarationProperty())
|
||||
return property.name();
|
||||
auto list = Utils::transform<std::vector<PropertyName>>(
|
||||
modelNode.dynamicProperties(), [](const AbstractProperty &property) -> PropertyName {
|
||||
if (property.isSignalDeclarationProperty())
|
||||
return property.name().toByteArray();
|
||||
|
||||
return PropertyName(property.name() + "Changed");
|
||||
});
|
||||
return Utils::sorted(std::vector<PropertyName>(list.begin(), list.end()));
|
||||
return property.name().toByteArray() + "Changed";
|
||||
});
|
||||
|
||||
std::sort(list.begin(), list.end());
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredPropertyNames(
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <rewritingexception.h>
|
||||
|
||||
#include <modelutils.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <utils/async.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
@@ -21,10 +23,11 @@ using namespace Utils;
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
static constexpr int normalImportDelay = 200;
|
||||
|
||||
ContentLibraryBundleImporter::ContentLibraryBundleImporter(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
m_importTimer.setInterval(200);
|
||||
connect(&m_importTimer, &QTimer::timeout, this, &ContentLibraryBundleImporter::handleImportTimer);
|
||||
}
|
||||
|
||||
@@ -49,19 +52,21 @@ QString ContentLibraryBundleImporter::importComponent(const QString &bundleDir,
|
||||
if (!bundleImportPath.exists() && !bundleImportPath.createDir())
|
||||
return QStringLiteral("Failed to create bundle import folder: '%1'").arg(bundleImportPath.toString());
|
||||
|
||||
bool doScan = false;
|
||||
bool doReset = false;
|
||||
FilePath qmldirPath = bundleImportPath.pathAppended("qmldir");
|
||||
QString qmldirContent = QString::fromUtf8(qmldirPath.fileContents().value_or(QByteArray()));
|
||||
if (qmldirContent.isEmpty()) {
|
||||
qmldirContent.append("module ");
|
||||
qmldirContent.append(module);
|
||||
qmldirContent.append('\n');
|
||||
doScan = true;
|
||||
}
|
||||
|
||||
FilePath qmlSourceFile = bundleImportPath.pathAppended(qmlFile);
|
||||
const bool qmlFileExists = qmlSourceFile.exists();
|
||||
const QString qmlType = qmlSourceFile.baseName();
|
||||
|
||||
if (m_pendingTypes.contains(type) && !m_pendingTypes.value(type))
|
||||
if (m_pendingImports.contains(type) && !m_pendingImports[type].isImport)
|
||||
return QStringLiteral("Unable to import while unimporting the same type: '%1'").arg(QLatin1String(type));
|
||||
|
||||
if (!qmldirContent.contains(qmlFile)) {
|
||||
@@ -70,6 +75,7 @@ QString ContentLibraryBundleImporter::importComponent(const QString &bundleDir,
|
||||
qmldirContent.append(qmlFile);
|
||||
qmldirContent.append('\n');
|
||||
qmldirPath.writeFileContents(qmldirContent.toUtf8());
|
||||
doReset = true;
|
||||
}
|
||||
|
||||
QStringList allFiles;
|
||||
@@ -104,16 +110,22 @@ QString ContentLibraryBundleImporter::importComponent(const QString &bundleDir,
|
||||
if (writeAssetRefs)
|
||||
writeAssetRefMap(bundleImportPath, assetRefMap);
|
||||
|
||||
m_fullReset = !qmlFileExists;
|
||||
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||
Model *model = doc ? doc->currentModel() : nullptr;
|
||||
if (!model)
|
||||
return "Model not available, cannot add import statement or update code model";
|
||||
|
||||
ImportData data;
|
||||
data.isImport = true;
|
||||
data.type = type;
|
||||
if (doScan)
|
||||
data.pathToScan = bundleImportPath;
|
||||
else
|
||||
data.fullReset = doReset;
|
||||
|
||||
Import import = Import::createLibraryImport(module, "1.0");
|
||||
if (!model->hasImport(import)) {
|
||||
if (model->possibleImports().contains(import)) {
|
||||
m_pendingImport.clear();
|
||||
try {
|
||||
model->changeImports({import}, {});
|
||||
} catch (const RewritingException &) {
|
||||
@@ -123,12 +135,12 @@ QString ContentLibraryBundleImporter::importComponent(const QString &bundleDir,
|
||||
} else {
|
||||
// If import is not yet possible, import statement needs to be added asynchronously to
|
||||
// avoid errors, as code model update takes a while.
|
||||
m_pendingImport = module;
|
||||
data.importToAdd = module;
|
||||
}
|
||||
}
|
||||
m_pendingTypes.insert(type, true);
|
||||
m_pendingImports.insert(type, data);
|
||||
m_importTimerCount = 0;
|
||||
m_importTimer.start();
|
||||
m_importTimer.start(normalImportDelay);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -137,21 +149,20 @@ void ContentLibraryBundleImporter::handleImportTimer()
|
||||
{
|
||||
auto handleFailure = [this] {
|
||||
m_importTimer.stop();
|
||||
m_fullReset = false;
|
||||
m_pendingImport.clear();
|
||||
m_importTimerCount = 0;
|
||||
|
||||
disconnect(m_libInfoConnection);
|
||||
|
||||
// Emit dummy finished signals for all pending types
|
||||
const QList<TypeName> pendingTypes = m_pendingTypes.keys();
|
||||
const QList<TypeName> pendingTypes = m_pendingImports.keys();
|
||||
for (const TypeName &pendingType : pendingTypes) {
|
||||
m_pendingTypes.remove(pendingType);
|
||||
if (m_pendingTypes.value(pendingType))
|
||||
ImportData data = m_pendingImports.take(pendingType);
|
||||
if (data.isImport)
|
||||
emit importFinished({}, m_bundleId);
|
||||
else
|
||||
emit unimportFinished({}, m_bundleId);
|
||||
|
||||
m_bundleId.clear();
|
||||
}
|
||||
m_bundleId.clear();
|
||||
};
|
||||
|
||||
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||
@@ -161,55 +172,125 @@ void ContentLibraryBundleImporter::handleImportTimer()
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_fullReset) {
|
||||
// Force code model reset to notice changes to existing module
|
||||
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
if (modelManager)
|
||||
modelManager->resetCodeModel();
|
||||
m_fullReset = false;
|
||||
return;
|
||||
}
|
||||
|
||||
QmlDesignerPlugin::instance()->documentManager().resetPossibleImports();
|
||||
|
||||
if (!m_pendingImport.isEmpty()) {
|
||||
try {
|
||||
Import import = Import::createLibraryImport(m_pendingImport, "1.0");
|
||||
if (model->possibleImports().contains(import)) {
|
||||
model->changeImports({import}, {});
|
||||
m_pendingImport.clear();
|
||||
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
if (modelManager) {
|
||||
const QList<TypeName> keys = m_pendingImports.keys();
|
||||
int scanDone = 0;
|
||||
bool refreshImports = false;
|
||||
for (const TypeName &type : keys) {
|
||||
ImportData &data = m_pendingImports[type];
|
||||
if (data.state == ImportData::Starting) {
|
||||
if (data.pathToScan.isEmpty()) {
|
||||
data.state = ImportData::FullReset;
|
||||
} else {
|
||||
// A new bundle module was added, so we can scan it without doing full code
|
||||
// model reset, which is faster
|
||||
QmlJS::PathsAndLanguages pathToScan;
|
||||
pathToScan.maybeInsert(data.pathToScan);
|
||||
data.future = Utils::asyncRun(&QmlJS::ModelManagerInterface::importScan,
|
||||
modelManager->workingCopy(),
|
||||
pathToScan, modelManager,
|
||||
true, true, true);
|
||||
data.state = ImportData::WaitingForImportScan;
|
||||
}
|
||||
} else if (data.state == ImportData::WaitingForImportScan) {
|
||||
// Import scan is asynchronous, so we need to wait for it to be finished
|
||||
if ((data.future.isCanceled() || data.future.isFinished()))
|
||||
data.state = ImportData::RefreshImports;
|
||||
} else if (data.state >= ImportData::RefreshImports) {
|
||||
// Do not mode to next stage until all pending scans are done
|
||||
++scanDone;
|
||||
if (data.state == ImportData::RefreshImports)
|
||||
refreshImports = true;
|
||||
}
|
||||
} catch (const RewritingException &) {
|
||||
// Import adding is unlikely to succeed later, either, so just bail out
|
||||
handleFailure();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (scanDone != m_pendingImports.size()) {
|
||||
return;
|
||||
} else {
|
||||
if (refreshImports) {
|
||||
// The new import is now available in code model, so reset the possible imports
|
||||
QmlDesignerPlugin::instance()->documentManager().resetPossibleImports();
|
||||
model->rewriterView()->forceAmend();
|
||||
|
||||
// Detect when the code model has the new material(s) fully available
|
||||
const QList<TypeName> pendingTypes = m_pendingTypes.keys();
|
||||
for (const TypeName &pendingType : pendingTypes) {
|
||||
NodeMetaInfo metaInfo = model->metaInfo(pendingType);
|
||||
const bool isImport = m_pendingTypes.value(pendingType);
|
||||
const bool typeComplete = metaInfo.isValid() && !metaInfo.prototypes().empty();
|
||||
if (isImport == typeComplete) {
|
||||
m_pendingTypes.remove(pendingType);
|
||||
if (isImport)
|
||||
for (const TypeName &type : keys) {
|
||||
ImportData &data = m_pendingImports[type];
|
||||
if (data.state == ImportData::RefreshImports) {
|
||||
if (!data.importToAdd.isEmpty()) {
|
||||
try {
|
||||
RewriterTransaction transaction = model->rewriterView()->beginRewriterTransaction(
|
||||
QByteArrayLiteral(__FUNCTION__));
|
||||
bool success = ModelUtils::addImportWithCheck(data.importToAdd, model);
|
||||
if (!success)
|
||||
handleFailure();
|
||||
transaction.commit();
|
||||
} catch (const RewritingException &) {
|
||||
handleFailure();
|
||||
}
|
||||
}
|
||||
}
|
||||
data.state = ImportData::FullReset;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool fullReset = false;
|
||||
for (const TypeName &type : keys) {
|
||||
ImportData &data = m_pendingImports[type];
|
||||
if (data.state == ImportData::FullReset) {
|
||||
if (data.fullReset)
|
||||
fullReset = true;
|
||||
data.state = ImportData::Finalize;
|
||||
}
|
||||
}
|
||||
if (fullReset) {
|
||||
// Force code model reset to notice changes to existing module
|
||||
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
if (modelManager) {
|
||||
modelManager->resetCodeModel();
|
||||
disconnect(m_libInfoConnection);
|
||||
m_libInfoConnection = connect(modelManager, &QmlJS::ModelManagerInterface::libraryInfoUpdated,
|
||||
this, [this]() {
|
||||
// This signal comes for each library in code model, so we need to compress
|
||||
// it until no more notifications come
|
||||
m_importTimer.start(1000);
|
||||
}, Qt::QueuedConnection);
|
||||
// Stop the import timer for a bit to allow full reset to complete
|
||||
m_importTimer.stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (const TypeName &type : keys) {
|
||||
ImportData &data = m_pendingImports[type];
|
||||
if (data.state == ImportData::Finalize) {
|
||||
// Reset delay just in case full reset was done earlier
|
||||
m_importTimer.start(normalImportDelay);
|
||||
disconnect(m_libInfoConnection);
|
||||
model->rewriterView()->forceAmend();
|
||||
// Verify that code model has the new material fully available (or removed for unimport)
|
||||
NodeMetaInfo metaInfo = model->metaInfo(type);
|
||||
const bool typeComplete = metaInfo.isValid() && !metaInfo.prototypes().empty();
|
||||
if (data.isImport == typeComplete) {
|
||||
m_pendingImports.remove(type);
|
||||
if (data.isImport)
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
emit importFinished(pendingType, m_bundleId);
|
||||
emit importFinished(type, m_bundleId);
|
||||
#else
|
||||
emit importFinished(metaInfo, m_bundleId);
|
||||
emit importFinished(metaInfo, m_bundleId);
|
||||
#endif
|
||||
else
|
||||
emit unimportFinished(metaInfo, m_bundleId);
|
||||
|
||||
m_bundleId.clear();
|
||||
else
|
||||
emit unimportFinished(metaInfo, m_bundleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pendingTypes.isEmpty()) {
|
||||
if (m_pendingImports.isEmpty()) {
|
||||
m_bundleId.clear();
|
||||
m_importTimer.stop();
|
||||
m_importTimerCount = 0;
|
||||
disconnect(m_libInfoConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +348,7 @@ QString ContentLibraryBundleImporter::unimportComponent(const TypeName &type, co
|
||||
QByteArray newContent;
|
||||
|
||||
QString qmlType = qmlFilePath.baseName();
|
||||
if (m_pendingTypes.contains(type) && m_pendingTypes.value(type)) {
|
||||
if (m_pendingImports.contains(type) && m_pendingImports[type].isImport) {
|
||||
return QStringLiteral("Unable to unimport while importing the same type: '%1'")
|
||||
.arg(QString::fromLatin1(type));
|
||||
}
|
||||
@@ -286,8 +367,6 @@ QString ContentLibraryBundleImporter::unimportComponent(const TypeName &type, co
|
||||
}
|
||||
}
|
||||
|
||||
m_pendingTypes.insert(type, false);
|
||||
|
||||
QVariantHash assetRefMap = loadAssetRefMap(bundleImportPath);
|
||||
bool writeAssetRefs = false;
|
||||
const auto keys = assetRefMap.keys();
|
||||
@@ -326,9 +405,14 @@ QString ContentLibraryBundleImporter::unimportComponent(const TypeName &type, co
|
||||
}
|
||||
}
|
||||
|
||||
m_fullReset = true;
|
||||
ImportData data;
|
||||
data.isImport = false;
|
||||
data.type = type;
|
||||
data.fullReset = true;
|
||||
m_pendingImports.insert(type, data);
|
||||
|
||||
m_importTimerCount = 0;
|
||||
m_importTimer.start();
|
||||
m_importTimer.start(normalImportDelay);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <utils/filepath.h>
|
||||
|
||||
#include <QFuture>
|
||||
#include <QTimer>
|
||||
#include <QVariantHash>
|
||||
|
||||
@@ -46,10 +47,27 @@ private:
|
||||
|
||||
QTimer m_importTimer;
|
||||
int m_importTimerCount = 0;
|
||||
QString m_pendingImport;
|
||||
QString m_bundleId;
|
||||
bool m_fullReset = false;
|
||||
QHash<TypeName, bool> m_pendingTypes; // <type, isImport>
|
||||
struct ImportData
|
||||
{
|
||||
enum State {
|
||||
Starting,
|
||||
WaitingForImportScan,
|
||||
RefreshImports,
|
||||
FullReset,
|
||||
Finalize
|
||||
};
|
||||
bool isImport = true; // false = unimport
|
||||
TypeName type;
|
||||
Utils::FilePath pathToScan; // If set, do importScan
|
||||
QFuture<void> future;
|
||||
QString importToAdd; // If set, add import to model
|
||||
bool fullReset = false; // If true, reset the entire code model.
|
||||
State state = Starting;
|
||||
};
|
||||
|
||||
QHash<TypeName, ImportData> m_pendingImports;
|
||||
QMetaObject::Connection m_libInfoConnection;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -93,11 +93,9 @@ QHash<int, QByteArray> ContentLibraryEffectsModel::roleNames() const
|
||||
return roles;
|
||||
}
|
||||
|
||||
void ContentLibraryEffectsModel::loadBundle()
|
||||
void ContentLibraryEffectsModel::loadBundle(bool force)
|
||||
{
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
|
||||
if (m_probeBundleDir || (m_bundleExists && m_bundleId == compUtils.effectsBundleId()))
|
||||
if (m_probeBundleDir && !force)
|
||||
return;
|
||||
|
||||
// clean up
|
||||
@@ -148,6 +146,7 @@ void ContentLibraryEffectsModel::loadBundle()
|
||||
|
||||
m_bundleObj = bundleJsonDoc.object();
|
||||
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
QString bundleType = compUtils.effectsBundleType();
|
||||
m_bundleId = compUtils.effectsBundleId();
|
||||
|
||||
@@ -171,17 +170,14 @@ void ContentLibraryEffectsModel::loadBundle()
|
||||
TypeName type = QLatin1String("%1.%2")
|
||||
.arg(bundleType, qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
|
||||
|
||||
auto bundleItem = new ContentLibraryItem(category, itemName, qml, type, icon, files);
|
||||
auto bundleItem = new ContentLibraryItem(category, itemName, qml, type, icon, files, m_bundleId);
|
||||
|
||||
category->addBundleItem(bundleItem);
|
||||
}
|
||||
m_bundleCategories.append(category);
|
||||
}
|
||||
|
||||
m_bundleSharedFiles.clear();
|
||||
const QJsonArray sharedFilesArr = m_bundleObj.value("sharedFiles").toArray();
|
||||
for (const QJsonValueConstRef &file : sharedFilesArr)
|
||||
m_bundleSharedFiles.append(file.toString());
|
||||
m_bundleSharedFiles = m_bundleObj.value("sharedFiles").toVariant().toStringList();
|
||||
|
||||
m_bundlePath = bundleDir.path();
|
||||
m_bundleExists = true;
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
void loadBundle();
|
||||
void loadBundle(bool force = false);
|
||||
void setSearchText(const QString &searchText);
|
||||
void updateImportedState(const QStringList &importedItems);
|
||||
|
||||
|
||||
@@ -7,21 +7,18 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
namespace Internal {
|
||||
|
||||
ContentLibraryIconProvider::ContentLibraryIconProvider()
|
||||
: QQuickImageProvider(Pixmap)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QPixmap ContentLibraryIconProvider::requestPixmap(const QString &id,
|
||||
QSize *size,
|
||||
[[maybe_unused]] const QSize &requestedSize)
|
||||
{
|
||||
QString realPath = Core::ICore::resourcePath("qmldesigner/contentLibraryImages/" + id).toString();
|
||||
QString imagePath = Core::ICore::resourcePath("qmldesigner/contentLibraryImages/" + id).toFSPathString();
|
||||
|
||||
QPixmap pixmap{realPath};
|
||||
QPixmap pixmap{imagePath};
|
||||
|
||||
if (size) {
|
||||
size->setWidth(pixmap.width());
|
||||
@@ -37,6 +34,4 @@ QPixmap ContentLibraryIconProvider::requestPixmap(const QString &id,
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <QQuickImageProvider>
|
||||
|
||||
namespace QmlDesigner::Internal {
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ContentLibraryIconProvider : public QQuickImageProvider
|
||||
{
|
||||
@@ -14,4 +14,4 @@ public:
|
||||
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner::Internal
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -10,11 +10,11 @@ ContentLibraryItem::ContentLibraryItem(QObject *parent,
|
||||
const QString &qml,
|
||||
const TypeName &type,
|
||||
const QUrl &icon,
|
||||
const QStringList &files)
|
||||
: QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files)
|
||||
const QStringList &files,
|
||||
const QString &bundleId)
|
||||
: QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files),
|
||||
m_bundleId(bundleId)
|
||||
{
|
||||
m_allFiles = m_files;
|
||||
m_allFiles.push_back(m_qml);
|
||||
}
|
||||
|
||||
bool ContentLibraryItem::filter(const QString &searchText)
|
||||
@@ -68,9 +68,9 @@ bool ContentLibraryItem::imported() const
|
||||
return m_imported;
|
||||
}
|
||||
|
||||
QStringList ContentLibraryItem::allFiles() const
|
||||
QString ContentLibraryItem::bundleId() const
|
||||
{
|
||||
return m_allFiles;
|
||||
return m_bundleId;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -16,10 +16,9 @@ class ContentLibraryItem : public QObject
|
||||
|
||||
Q_PROPERTY(QString bundleItemName MEMBER m_name CONSTANT)
|
||||
Q_PROPERTY(QUrl bundleItemIcon MEMBER m_icon CONSTANT)
|
||||
Q_PROPERTY(QStringList bundleItemFiles READ allFiles CONSTANT)
|
||||
Q_PROPERTY(bool bundleItemVisible MEMBER m_visible NOTIFY itemVisibleChanged)
|
||||
Q_PROPERTY(bool bundleItemImported READ imported WRITE setImported NOTIFY itemImportedChanged)
|
||||
Q_PROPERTY(QString itemType MEMBER m_itemType CONSTANT)
|
||||
Q_PROPERTY(QString bundleId READ bundleId CONSTANT)
|
||||
|
||||
public:
|
||||
ContentLibraryItem(QObject *parent,
|
||||
@@ -27,7 +26,8 @@ public:
|
||||
const QString &qml,
|
||||
const TypeName &type,
|
||||
const QUrl &icon,
|
||||
const QStringList &files);
|
||||
const QStringList &files,
|
||||
const QString &bundleId);
|
||||
|
||||
bool filter(const QString &searchText);
|
||||
|
||||
@@ -37,9 +37,10 @@ public:
|
||||
QStringList files() const;
|
||||
bool visible() const;
|
||||
|
||||
QString bundleId() const;
|
||||
|
||||
bool setImported(bool imported);
|
||||
bool imported() const;
|
||||
QStringList allFiles() const;
|
||||
|
||||
signals:
|
||||
void itemVisibleChanged();
|
||||
@@ -55,8 +56,7 @@ private:
|
||||
bool m_visible = true;
|
||||
bool m_imported = false;
|
||||
|
||||
QStringList m_allFiles;
|
||||
const QString m_itemType = "item";
|
||||
const QString m_bundleId;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include "contentlibrarymaterial.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
ContentLibraryMaterial::ContentLibraryMaterial(QObject *parent,
|
||||
@@ -13,10 +11,9 @@ ContentLibraryMaterial::ContentLibraryMaterial(QObject *parent,
|
||||
const TypeName &type,
|
||||
const QUrl &icon,
|
||||
const QStringList &files,
|
||||
const QString &downloadPath,
|
||||
const QString &baseWebUrl)
|
||||
const QString &bundleId)
|
||||
: QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files)
|
||||
, m_downloadPath(downloadPath), m_baseWebUrl(baseWebUrl)
|
||||
, m_bundleId(bundleId)
|
||||
{
|
||||
m_allFiles = m_files;
|
||||
m_allFiles.push_back(m_qml);
|
||||
@@ -78,25 +75,14 @@ bool ContentLibraryMaterial::imported() const
|
||||
return m_imported;
|
||||
}
|
||||
|
||||
bool ContentLibraryMaterial::isDownloaded() const
|
||||
{
|
||||
QString fullPath = qmlFilePath();
|
||||
return QFileInfo(fullPath).isFile();
|
||||
}
|
||||
|
||||
QString ContentLibraryMaterial::qmlFilePath() const
|
||||
{
|
||||
return m_downloadPath + "/" + m_qml;
|
||||
}
|
||||
|
||||
QString ContentLibraryMaterial::dirPath() const
|
||||
{
|
||||
return m_downloadPath;
|
||||
}
|
||||
|
||||
QStringList ContentLibraryMaterial::allFiles() const
|
||||
{
|
||||
return m_allFiles;
|
||||
}
|
||||
|
||||
QString ContentLibraryMaterial::bundleId() const
|
||||
{
|
||||
return m_bundleId;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -18,10 +18,8 @@ class ContentLibraryMaterial : public QObject
|
||||
Q_PROPERTY(QUrl bundleMaterialIcon MEMBER m_icon CONSTANT)
|
||||
Q_PROPERTY(bool bundleMaterialVisible MEMBER m_visible NOTIFY materialVisibleChanged)
|
||||
Q_PROPERTY(bool bundleItemImported READ imported WRITE setImported NOTIFY materialImportedChanged)
|
||||
Q_PROPERTY(QString bundleMaterialBaseWebUrl MEMBER m_baseWebUrl CONSTANT)
|
||||
Q_PROPERTY(QString bundleMaterialDirPath READ dirPath CONSTANT)
|
||||
Q_PROPERTY(QStringList bundleMaterialFiles READ allFiles CONSTANT)
|
||||
Q_PROPERTY(QString itemType MEMBER m_itemType CONSTANT)
|
||||
Q_PROPERTY(QString bundleId READ bundleId CONSTANT)
|
||||
|
||||
public:
|
||||
ContentLibraryMaterial(QObject *parent,
|
||||
@@ -30,26 +28,23 @@ public:
|
||||
const TypeName &type,
|
||||
const QUrl &icon,
|
||||
const QStringList &files,
|
||||
const QString &downloadPath,
|
||||
const QString &baseWebUrl = {});
|
||||
const QString &bundleId);
|
||||
|
||||
bool filter(const QString &searchText);
|
||||
|
||||
Q_INVOKABLE bool isDownloaded() const;
|
||||
|
||||
QString name() const;
|
||||
QUrl icon() const;
|
||||
QString qml() const;
|
||||
TypeName type() const;
|
||||
QStringList files() const;
|
||||
bool visible() const;
|
||||
QString qmlFilePath() const;
|
||||
|
||||
bool setImported(bool imported);
|
||||
bool imported() const;
|
||||
QString dirPath() const;
|
||||
QStringList allFiles() const;
|
||||
|
||||
QString bundleId() const;
|
||||
|
||||
signals:
|
||||
void materialVisibleChanged();
|
||||
void materialImportedChanged();
|
||||
@@ -64,10 +59,8 @@ private:
|
||||
bool m_visible = true;
|
||||
bool m_imported = false;
|
||||
|
||||
QString m_downloadPath;
|
||||
QString m_baseWebUrl;
|
||||
QStringList m_allFiles;
|
||||
const QString m_itemType = "material";
|
||||
const QString m_bundleId;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
@@ -33,7 +32,7 @@ ContentLibraryMaterialsModel::ContentLibraryMaterialsModel(ContentLibraryWidget
|
||||
: QAbstractListModel(parent)
|
||||
, m_widget(parent)
|
||||
{
|
||||
m_downloadPath = Paths::bundlesPathSetting() + "/Materials";
|
||||
m_bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/Materials");
|
||||
|
||||
m_baseUrl = QmlDesignerPlugin::settings()
|
||||
.value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL)
|
||||
@@ -45,9 +44,8 @@ ContentLibraryMaterialsModel::ContentLibraryMaterialsModel(ContentLibraryWidget
|
||||
|
||||
void ContentLibraryMaterialsModel::loadBundle()
|
||||
{
|
||||
QDir bundleDir{m_downloadPath};
|
||||
if (fetchBundleMetadata(bundleDir) && fetchBundleIcons(bundleDir))
|
||||
loadMaterialBundle(bundleDir);
|
||||
if (fetchBundleJsonFile() && fetchBundleIcons())
|
||||
loadMaterialBundle();
|
||||
}
|
||||
|
||||
int ContentLibraryMaterialsModel::rowCount(const QModelIndex &) const
|
||||
@@ -114,13 +112,14 @@ QHash<int, QByteArray> ContentLibraryMaterialsModel::roleNames() const
|
||||
return roles;
|
||||
}
|
||||
|
||||
bool ContentLibraryMaterialsModel::fetchBundleIcons(const QDir &bundleDir)
|
||||
bool ContentLibraryMaterialsModel::fetchBundleIcons()
|
||||
{
|
||||
QString iconsPath = bundleDir.filePath("icons");
|
||||
Utils::FilePath iconsFilePath = m_bundlePath.pathAppended("icons");
|
||||
|
||||
QDir iconsDir(iconsPath);
|
||||
if (iconsDir.exists() && iconsDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot).length() > 0)
|
||||
if (iconsFilePath.exists() && iconsFilePath.dirEntries(QDir::Files | QDir::Dirs
|
||||
| QDir::NoDotAndDotDot).length() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QString zipFileUrl = m_baseUrl + "/icons.zip";
|
||||
|
||||
@@ -130,20 +129,20 @@ bool ContentLibraryMaterialsModel::fetchBundleIcons(const QDir &bundleDir)
|
||||
downloader->setDownloadEnabled(true);
|
||||
|
||||
QObject::connect(downloader, &FileDownloader::finishedChanged, this,
|
||||
[this, downloader, bundleDir] {
|
||||
[this, downloader] {
|
||||
FileExtractor *extractor = new FileExtractor(this);
|
||||
extractor->setArchiveName(downloader->completeBaseName());
|
||||
extractor->setSourceFile(downloader->outputFile());
|
||||
extractor->setTargetPath(bundleDir.absolutePath());
|
||||
extractor->setTargetPath(m_bundlePath.toFSPathString());
|
||||
extractor->setAlwaysCreateDir(false);
|
||||
extractor->setClearTargetPathContents(false);
|
||||
|
||||
QObject::connect(extractor, &FileExtractor::finishedChanged, this,
|
||||
[this, downloader, bundleDir, extractor] {
|
||||
[this, downloader, extractor] {
|
||||
downloader->deleteLater();
|
||||
extractor->deleteLater();
|
||||
|
||||
loadMaterialBundle(bundleDir);
|
||||
loadMaterialBundle();
|
||||
});
|
||||
|
||||
extractor->extract();
|
||||
@@ -153,25 +152,25 @@ bool ContentLibraryMaterialsModel::fetchBundleIcons(const QDir &bundleDir)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContentLibraryMaterialsModel::fetchBundleMetadata(const QDir &bundleDir)
|
||||
bool ContentLibraryMaterialsModel::fetchBundleJsonFile()
|
||||
{
|
||||
QString matBundlePath = bundleDir.filePath("material_bundle.json");
|
||||
Utils::FilePath jsonFilePath = m_bundlePath.pathAppended("material_bundle.json");
|
||||
|
||||
QFileInfo fi(matBundlePath);
|
||||
if (fi.exists() && fi.size() > 0)
|
||||
if (jsonFilePath.exists() && jsonFilePath.fileSize() > 0)
|
||||
return true;
|
||||
|
||||
QString metaFileUrl = m_baseUrl + "/material_bundle.json";
|
||||
QString bundleJsonUrl = m_baseUrl + "/material_bundle.json";
|
||||
|
||||
FileDownloader *downloader = new FileDownloader(this);
|
||||
downloader->setUrl(metaFileUrl);
|
||||
downloader->setUrl(bundleJsonUrl);
|
||||
downloader->setProbeUrl(false);
|
||||
downloader->setDownloadEnabled(true);
|
||||
downloader->setTargetFilePath(matBundlePath);
|
||||
downloader->setTargetFilePath(jsonFilePath.toFSPathString());
|
||||
|
||||
QObject::connect(downloader, &FileDownloader::finishedChanged, this,
|
||||
[this, downloader, bundleDir] {
|
||||
if (fetchBundleIcons(bundleDir))
|
||||
loadMaterialBundle(bundleDir);
|
||||
[this, downloader] {
|
||||
if (fetchBundleIcons())
|
||||
loadMaterialBundle();
|
||||
downloader->deleteLater();
|
||||
});
|
||||
|
||||
@@ -179,7 +178,7 @@ bool ContentLibraryMaterialsModel::fetchBundleMetadata(const QDir &bundleDir)
|
||||
return false;
|
||||
}
|
||||
|
||||
void ContentLibraryMaterialsModel::downloadSharedFiles(const QDir &targetDir, const QStringList &)
|
||||
void ContentLibraryMaterialsModel::downloadSharedFiles()
|
||||
{
|
||||
QString metaFileUrl = m_baseUrl + "/shared_files.zip";
|
||||
FileDownloader *downloader = new FileDownloader(this);
|
||||
@@ -188,11 +187,11 @@ void ContentLibraryMaterialsModel::downloadSharedFiles(const QDir &targetDir, co
|
||||
downloader->setDownloadEnabled(true);
|
||||
|
||||
QObject::connect(downloader, &FileDownloader::finishedChanged, this,
|
||||
[this, downloader, targetDir] {
|
||||
[this, downloader] {
|
||||
FileExtractor *extractor = new FileExtractor(this);
|
||||
extractor->setArchiveName(downloader->completeBaseName());
|
||||
extractor->setSourceFile(downloader->outputFile());
|
||||
extractor->setTargetPath(targetDir.absolutePath());
|
||||
extractor->setTargetPath(m_bundlePath.toFSPathString());
|
||||
extractor->setAlwaysCreateDir(false);
|
||||
extractor->setClearTargetPathContents(false);
|
||||
|
||||
@@ -212,11 +211,11 @@ QString ContentLibraryMaterialsModel::bundleId() const
|
||||
return m_bundleId;
|
||||
}
|
||||
|
||||
void ContentLibraryMaterialsModel::loadMaterialBundle(const QDir &bundleDir)
|
||||
void ContentLibraryMaterialsModel::loadMaterialBundle(bool forceReload)
|
||||
{
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
|
||||
if (m_bundleExists && m_bundleId == compUtils.materialsBundleId())
|
||||
if (!forceReload && m_bundleExists && m_bundleId == compUtils.materialsBundleId())
|
||||
return;
|
||||
|
||||
// clean up
|
||||
@@ -227,18 +226,18 @@ void ContentLibraryMaterialsModel::loadMaterialBundle(const QDir &bundleDir)
|
||||
m_bundleObj = {};
|
||||
m_bundleId.clear();
|
||||
|
||||
QString bundlePath = bundleDir.filePath("material_bundle.json");
|
||||
Utils::FilePath jsonFilePath = m_bundlePath.pathAppended("material_bundle.json");
|
||||
|
||||
QFile bundleFile(bundlePath);
|
||||
if (!bundleFile.open(QIODevice::ReadOnly)) {
|
||||
qWarning("Couldn't open material_bundle.json");
|
||||
Utils::expected_str<QByteArray> jsonContents = jsonFilePath.fileContents();
|
||||
if (!jsonContents.has_value()) {
|
||||
qWarning() << __FUNCTION__ << jsonContents.error();
|
||||
resetModel();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(bundleFile.readAll());
|
||||
QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(jsonContents.value());
|
||||
if (bundleJsonDoc.isNull()) {
|
||||
qWarning("Invalid material_bundle.json file");
|
||||
qWarning() << __FUNCTION__ << "Invalid json file" << jsonFilePath;
|
||||
resetModel();
|
||||
return;
|
||||
}
|
||||
@@ -258,38 +257,38 @@ void ContentLibraryMaterialsModel::loadMaterialBundle(const QDir &bundleDir)
|
||||
for (const QString &matName : matsNames) {
|
||||
const QJsonObject matObj = matsObj.value(matName).toObject();
|
||||
|
||||
if (matObj.contains("minQtVersion")) {
|
||||
const Version minQtVersion = Version::fromString(
|
||||
matObj.value("minQtVersion").toString());
|
||||
if (minQtVersion > m_quick3dVersion)
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList files;
|
||||
const QJsonArray assetsArr = matObj.value("files").toArray();
|
||||
for (const QJsonValueConstRef &asset : assetsArr)
|
||||
files.append(asset.toString());
|
||||
|
||||
QUrl icon = QUrl::fromLocalFile(bundleDir.filePath(matObj.value("icon").toString()));
|
||||
QUrl icon = m_bundlePath.pathAppended(matObj.value("icon").toString()).toUrl();
|
||||
QString qml = matObj.value("qml").toString();
|
||||
TypeName type = QLatin1String("%1.%2")
|
||||
.arg(bundleType, qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
|
||||
TypeName type = QLatin1String("%1.%2").arg(bundleType, qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
|
||||
|
||||
auto bundleMat = new ContentLibraryMaterial(category, matName, qml, type, icon, files,
|
||||
m_downloadPath, m_baseUrl);
|
||||
m_bundleId);
|
||||
|
||||
category->addBundleMaterial(bundleMat);
|
||||
}
|
||||
m_bundleCategories.append(category);
|
||||
}
|
||||
|
||||
m_bundleSharedFiles.clear();
|
||||
const QJsonArray sharedFilesArr = m_bundleObj.value("sharedFiles").toArray();
|
||||
for (const QJsonValueConstRef &file : sharedFilesArr)
|
||||
m_bundleSharedFiles.append(file.toString());
|
||||
|
||||
QStringList missingSharedFiles;
|
||||
for (const QString &s : std::as_const(m_bundleSharedFiles)) {
|
||||
if (!QFileInfo::exists(bundleDir.filePath(s)))
|
||||
missingSharedFiles.push_back(s);
|
||||
m_bundleSharedFiles = m_bundleObj.value("sharedFiles").toVariant().toStringList();
|
||||
for (const QString &file : std::as_const(m_bundleSharedFiles)) {
|
||||
if (!m_bundlePath.pathAppended(file).exists()) {
|
||||
downloadSharedFiles();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (missingSharedFiles.length() > 0)
|
||||
downloadSharedFiles(bundleDir, missingSharedFiles);
|
||||
|
||||
m_bundleExists = true;
|
||||
updateIsEmpty();
|
||||
resetModel();
|
||||
@@ -297,7 +296,7 @@ void ContentLibraryMaterialsModel::loadMaterialBundle(const QDir &bundleDir)
|
||||
|
||||
bool ContentLibraryMaterialsModel::hasRequiredQuick3DImport() const
|
||||
{
|
||||
return m_widget->hasQuick3DImport() && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3;
|
||||
return m_widget->hasQuick3DImport() && m_quick3dVersion >= Version{6, 3};
|
||||
}
|
||||
|
||||
bool ContentLibraryMaterialsModel::matBundleExists() const
|
||||
@@ -305,6 +304,11 @@ bool ContentLibraryMaterialsModel::matBundleExists() const
|
||||
return m_bundleExists;
|
||||
}
|
||||
|
||||
QString ContentLibraryMaterialsModel::bundlePath() const
|
||||
{
|
||||
return m_bundlePath.toFSPathString();
|
||||
}
|
||||
|
||||
void ContentLibraryMaterialsModel::setSearchText(const QString &searchText)
|
||||
{
|
||||
QString lowerSearchText = searchText.toLower();
|
||||
@@ -338,8 +342,11 @@ void ContentLibraryMaterialsModel::setQuick3DImportVersion(int major, int minor)
|
||||
{
|
||||
bool oldRequiredImport = hasRequiredQuick3DImport();
|
||||
|
||||
m_quick3dMajorVersion = major;
|
||||
m_quick3dMinorVersion = minor;
|
||||
const Version newVersion{major, minor};
|
||||
if (m_quick3dVersion != newVersion) {
|
||||
m_quick3dVersion = newVersion;
|
||||
loadMaterialBundle(true);
|
||||
}
|
||||
|
||||
bool newRequiredImport = hasRequiredQuick3DImport();
|
||||
|
||||
@@ -364,8 +371,8 @@ void ContentLibraryMaterialsModel::applyToSelected(ContentLibraryMaterial *mat,
|
||||
|
||||
void ContentLibraryMaterialsModel::addToProject(ContentLibraryMaterial *mat)
|
||||
{
|
||||
QString err = m_widget->importer()->importComponent(mat->dirPath(), mat->type(), mat->qml(),
|
||||
mat->files() + m_bundleSharedFiles);
|
||||
QString err = m_widget->importer()->importComponent(m_bundlePath.toFSPathString(), mat->type(),
|
||||
mat->qml(), mat->files() + m_bundleSharedFiles);
|
||||
|
||||
if (err.isEmpty())
|
||||
m_widget->setImporterRunning(true);
|
||||
@@ -383,4 +390,9 @@ void ContentLibraryMaterialsModel::removeFromProject(ContentLibraryMaterial *mat
|
||||
qWarning() << __FUNCTION__ << err;
|
||||
}
|
||||
|
||||
bool ContentLibraryMaterialsModel::isMaterialDownloaded(ContentLibraryMaterial *mat) const
|
||||
{
|
||||
return m_bundlePath.pathAppended(mat->qml()).exists();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/version.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonObject>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QDir)
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ContentLibraryMaterial;
|
||||
@@ -21,6 +22,8 @@ class ContentLibraryMaterialsModel : public QAbstractListModel
|
||||
Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged)
|
||||
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
|
||||
Q_PROPERTY(bool hasRequiredQuick3DImport READ hasRequiredQuick3DImport NOTIFY hasRequiredQuick3DImportChanged)
|
||||
Q_PROPERTY(QString baseWebUrl MEMBER m_baseUrl CONSTANT)
|
||||
Q_PROPERTY(QString bundlePath READ bundlePath CONSTANT)
|
||||
|
||||
public:
|
||||
ContentLibraryMaterialsModel(ContentLibraryWidget *parent = nullptr);
|
||||
@@ -37,6 +40,8 @@ public:
|
||||
bool hasRequiredQuick3DImport() const;
|
||||
bool matBundleExists() const;
|
||||
|
||||
QString bundlePath() const;
|
||||
|
||||
void resetModel();
|
||||
void updateIsEmpty();
|
||||
void loadBundle();
|
||||
@@ -44,6 +49,7 @@ public:
|
||||
Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
|
||||
Q_INVOKABLE void addToProject(QmlDesigner::ContentLibraryMaterial *mat);
|
||||
Q_INVOKABLE void removeFromProject(QmlDesigner::ContentLibraryMaterial *mat);
|
||||
Q_INVOKABLE bool isMaterialDownloaded(QmlDesigner::ContentLibraryMaterial *mat) const;
|
||||
|
||||
QString bundleId() const;
|
||||
|
||||
@@ -55,11 +61,11 @@ signals:
|
||||
void matBundleExistsChanged();
|
||||
|
||||
private:
|
||||
void loadMaterialBundle(const QDir &matBundleDir);
|
||||
bool fetchBundleIcons(const QDir &bundleDir);
|
||||
bool fetchBundleMetadata(const QDir &bundleDir);
|
||||
void loadMaterialBundle(bool forceReload = false);
|
||||
bool fetchBundleIcons();
|
||||
bool fetchBundleJsonFile();
|
||||
bool isValidIndex(int idx) const;
|
||||
void downloadSharedFiles(const QDir &targetDir, const QStringList &files);
|
||||
void downloadSharedFiles();
|
||||
|
||||
ContentLibraryWidget *m_widget = nullptr;
|
||||
QString m_searchText;
|
||||
@@ -71,10 +77,8 @@ private:
|
||||
bool m_isEmpty = true;
|
||||
bool m_bundleExists = false;
|
||||
|
||||
int m_quick3dMajorVersion = -1;
|
||||
int m_quick3dMinorVersion = -1;
|
||||
|
||||
QString m_downloadPath;
|
||||
Version m_quick3dVersion;
|
||||
Utils::FilePath m_bundlePath;
|
||||
QString m_baseUrl;
|
||||
};
|
||||
|
||||
|
||||
@@ -78,17 +78,17 @@ QString ContentLibraryTexture::resolveToolTipText()
|
||||
if (m_suffix.isEmpty())
|
||||
return m_baseName; // empty suffix means we have just the icon and no other data
|
||||
|
||||
QString fileName = m_baseName + m_suffix;
|
||||
QString texFileName = fileName();
|
||||
QString imageInfo;
|
||||
|
||||
if (!m_isDownloaded && m_sizeInBytes > 0 && !m_dimensions.isNull()) {
|
||||
imageInfo = ImageUtils::imageInfoString(m_dimensions, m_sizeInBytes);
|
||||
} else {
|
||||
QString fullDownloadPath = m_dirPath + '/' + fileName;
|
||||
QString fullDownloadPath = m_dirPath + '/' + texFileName;
|
||||
imageInfo = ImageUtils::imageInfoString(fullDownloadPath);
|
||||
}
|
||||
|
||||
return QString("%1\n%2").arg(fileName, imageInfo);
|
||||
return QString("%1\n%2").arg(texFileName, imageInfo);
|
||||
}
|
||||
|
||||
bool ContentLibraryTexture::isDownloaded() const
|
||||
@@ -98,7 +98,7 @@ bool ContentLibraryTexture::isDownloaded() const
|
||||
|
||||
QString ContentLibraryTexture::texturePath() const
|
||||
{
|
||||
return m_dirPath + '/' + m_baseName + m_suffix;
|
||||
return m_dirPath + '/' + fileName();
|
||||
}
|
||||
|
||||
void ContentLibraryTexture::setDownloaded()
|
||||
@@ -135,6 +135,11 @@ QString ContentLibraryTexture::textureKey() const
|
||||
return m_textureKey;
|
||||
}
|
||||
|
||||
QString ContentLibraryTexture::fileName() const
|
||||
{
|
||||
return m_baseName + m_suffix;
|
||||
}
|
||||
|
||||
void ContentLibraryTexture::setHasUpdate(bool value)
|
||||
{
|
||||
if (m_hasUpdate != value) {
|
||||
|
||||
@@ -24,7 +24,7 @@ class ContentLibraryTexture : public QObject
|
||||
Q_PROPERTY(bool textureHasUpdate WRITE setHasUpdate READ hasUpdate NOTIFY hasUpdateChanged)
|
||||
Q_PROPERTY(bool textureIsNew MEMBER m_isNew CONSTANT)
|
||||
Q_PROPERTY(QString textureKey MEMBER m_textureKey CONSTANT)
|
||||
Q_PROPERTY(QString itemType MEMBER m_itemType CONSTANT)
|
||||
Q_PROPERTY(QString bundleId MEMBER m_bundleId CONSTANT)
|
||||
|
||||
public:
|
||||
ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo, const QString &dirPath,
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
QString texturePath() const;
|
||||
QString parentDirPath() const;
|
||||
QString textureKey() const;
|
||||
QString fileName() const;
|
||||
|
||||
void setHasUpdate(bool value);
|
||||
bool hasUpdate() const;
|
||||
@@ -74,7 +75,7 @@ private:
|
||||
bool m_visible = true;
|
||||
bool m_hasUpdate = false;
|
||||
bool m_isNew = false;
|
||||
const QString m_itemType = "texture";
|
||||
const QString m_bundleId = "UserTextures";
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "contentlibraryusermodel.h"
|
||||
#include "useritemcategory.h"
|
||||
#include "usertexturecategory.h"
|
||||
|
||||
#include "contentlibrarybundleimporter.h"
|
||||
#include "contentlibraryitem.h"
|
||||
#include "contentlibrarymaterial.h"
|
||||
#include "contentlibrarymaterialscategory.h"
|
||||
#include "contentlibrarytexture.h"
|
||||
#include "contentlibrarywidget.h"
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <imageutils.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <uniquename.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -30,7 +29,7 @@ ContentLibraryUserModel::ContentLibraryUserModel(ContentLibraryWidget *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_widget(parent)
|
||||
{
|
||||
m_userCategories = {tr("Materials"), tr("Textures"), tr("3D"), /*tr("Effects"), tr("2D components")*/}; // TODO
|
||||
createCategories();
|
||||
}
|
||||
|
||||
int ContentLibraryUserModel::rowCount(const QModelIndex &) const
|
||||
@@ -43,218 +42,147 @@ QVariant ContentLibraryUserModel::data(const QModelIndex &index, int role) const
|
||||
QTC_ASSERT(index.isValid() && index.row() < m_userCategories.size(), return {});
|
||||
QTC_ASSERT(roleNames().contains(role), return {});
|
||||
|
||||
if (role == NameRole)
|
||||
return m_userCategories.at(index.row());
|
||||
UserCategory *currCat = m_userCategories.at(index.row());
|
||||
|
||||
if (role == ItemsRole) {
|
||||
if (index.row() == MaterialsSectionIdx)
|
||||
return QVariant::fromValue(m_userMaterials);
|
||||
if (index.row() == TexturesSectionIdx)
|
||||
return QVariant::fromValue(m_userTextures);
|
||||
if (index.row() == Items3DSectionIdx)
|
||||
return QVariant::fromValue(m_user3DItems);
|
||||
if (index.row() == EffectsSectionIdx)
|
||||
return QVariant::fromValue(m_userEffects);
|
||||
}
|
||||
if (role == TitleRole)
|
||||
return currCat->title();
|
||||
|
||||
if (role == NoMatchRole) {
|
||||
if (index.row() == MaterialsSectionIdx)
|
||||
return m_noMatchMaterials;
|
||||
if (index.row() == TexturesSectionIdx)
|
||||
return m_noMatchTextures;
|
||||
if (index.row() == Items3DSectionIdx)
|
||||
return m_noMatch3D;
|
||||
if (index.row() == EffectsSectionIdx)
|
||||
return m_noMatchEffects;
|
||||
}
|
||||
if (role == ItemsRole)
|
||||
return QVariant::fromValue(currCat->items());
|
||||
|
||||
if (role == VisibleRole) {
|
||||
if (index.row() == MaterialsSectionIdx)
|
||||
return !m_userMaterials.isEmpty();
|
||||
if (index.row() == TexturesSectionIdx)
|
||||
return !m_userTextures.isEmpty();
|
||||
if (index.row() == Items3DSectionIdx)
|
||||
return !m_user3DItems.isEmpty();
|
||||
if (index.row() == EffectsSectionIdx)
|
||||
return !m_userEffects.isEmpty();
|
||||
}
|
||||
if (role == NoMatchRole)
|
||||
return currCat->noMatch();
|
||||
|
||||
if (role == EmptyRole)
|
||||
return currCat->isEmpty();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ContentLibraryUserModel::isValidIndex(int idx) const
|
||||
void ContentLibraryUserModel::createCategories()
|
||||
{
|
||||
return idx > -1 && idx < rowCount();
|
||||
QTC_ASSERT(m_userCategories.isEmpty(), return);
|
||||
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
auto userBundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User");
|
||||
|
||||
auto catMaterial = new UserItemCategory{tr("Materials"),
|
||||
userBundlePath.pathAppended("materials"),
|
||||
compUtils.userMaterialsBundleId()};
|
||||
|
||||
auto catTexture = new UserTextureCategory{tr("Textures"), userBundlePath.pathAppended("textures")};
|
||||
|
||||
auto cat3D = new UserItemCategory{tr("3D"), userBundlePath.pathAppended("3d"),
|
||||
compUtils.user3DBundleId()};
|
||||
|
||||
m_userCategories << catMaterial << catTexture << cat3D;
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::updateNoMatchMaterials()
|
||||
{
|
||||
m_noMatchMaterials = Utils::allOf(m_userMaterials, [&](ContentLibraryMaterial *item) {
|
||||
return !item->visible();
|
||||
});
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::updateNoMatchTextures()
|
||||
{
|
||||
m_noMatchTextures = Utils::allOf(m_userTextures, [&](ContentLibraryTexture *item) {
|
||||
return !item->visible();
|
||||
});
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::updateNoMatch3D()
|
||||
{
|
||||
m_noMatch3D = Utils::allOf(m_user3DItems, [&](ContentLibraryItem *item) {
|
||||
return !item->visible();
|
||||
});
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::addMaterial(const QString &name, const QString &qml,
|
||||
const QUrl &icon, const QStringList &files)
|
||||
void ContentLibraryUserModel::addItem(const QString &bundleId, const QString &name,
|
||||
const QString &qml, const QUrl &icon, const QStringList &files)
|
||||
{
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
|
||||
QString typePrefix = compUtils.userMaterialsBundleType();
|
||||
QString typePrefix = compUtils.userBundleType(bundleId);
|
||||
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
||||
|
||||
auto libMat = new ContentLibraryMaterial(this, name, qml, type, icon, files,
|
||||
Paths::bundlesPathSetting().append("/User/materials"));
|
||||
m_userMaterials.append(libMat);
|
||||
SectionIndex sectionIndex = bundleIdToSectionIndex(bundleId);
|
||||
|
||||
emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
|
||||
UserCategory *cat = m_userCategories[sectionIndex];
|
||||
cat->addItem(new ContentLibraryItem(cat, name, qml, type, icon, files, bundleId));
|
||||
updateIsEmpty();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::add3DItem(const QString &name, const QString &qml,
|
||||
const QUrl &icon, const QStringList &files)
|
||||
void ContentLibraryUserModel::refreshSection(const QString &bundleId)
|
||||
{
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
|
||||
QString typePrefix = compUtils.user3DBundleType();
|
||||
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
||||
|
||||
m_user3DItems.append(new ContentLibraryItem(this, name, qml, type, icon, files));
|
||||
SectionIndex sectionIdx = bundleIdToSectionIndex(bundleId);
|
||||
emit dataChanged(index(sectionIdx), index(sectionIdx), {ItemsRole, EmptyRole});
|
||||
updateIsEmpty();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::refresh3DSection()
|
||||
void ContentLibraryUserModel::addTextures(const Utils::FilePaths &paths)
|
||||
{
|
||||
emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
|
||||
auto texCat = qobject_cast<UserTextureCategory *>(m_userCategories[TexturesSectionIdx]);
|
||||
QTC_ASSERT(texCat, return);
|
||||
|
||||
texCat->addItems(paths);
|
||||
|
||||
emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx), {ItemsRole, EmptyRole});
|
||||
updateIsEmpty();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::addTextures(const QStringList &paths)
|
||||
void ContentLibraryUserModel::removeTextures(const QStringList &fileNames)
|
||||
{
|
||||
QDir bundleDir{Paths::bundlesPathSetting() + "/User/textures"};
|
||||
bundleDir.mkpath(".");
|
||||
bundleDir.mkdir("icons");
|
||||
// note: this method doesn't refresh the model after textures removal
|
||||
|
||||
for (const QString &path : paths) {
|
||||
QFileInfo fileInfo(path);
|
||||
QString suffix = '.' + fileInfo.suffix();
|
||||
auto iconFileInfo = QFileInfo(fileInfo.path().append("/icons/").append(fileInfo.baseName() + ".png"));
|
||||
QPair<QSize, qint64> info = ImageUtils::imageInfo(path);
|
||||
QString dirPath = fileInfo.path();
|
||||
QSize imgDims = info.first;
|
||||
qint64 imgFileSize = info.second;
|
||||
auto texCat = qobject_cast<UserTextureCategory *>(m_userCategories[TexturesSectionIdx]);
|
||||
QTC_ASSERT(texCat, return);
|
||||
|
||||
auto tex = new ContentLibraryTexture(this, iconFileInfo, dirPath, suffix, imgDims, imgFileSize);
|
||||
m_userTextures.append(tex);
|
||||
const QObjectList items = texCat->items();
|
||||
for (QObject *item : items) {
|
||||
ContentLibraryTexture *castedItem = qobject_cast<ContentLibraryTexture *>(item);
|
||||
QTC_ASSERT(castedItem, continue);
|
||||
|
||||
if (fileNames.contains(castedItem->fileName()))
|
||||
removeTexture(castedItem, false);
|
||||
}
|
||||
|
||||
emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx));
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::add3DInstance(ContentLibraryItem *bundleItem)
|
||||
{
|
||||
QString err = m_widget->importer()->importComponent(m_bundlePath3D.path(), bundleItem->type(),
|
||||
bundleItem->qml(),
|
||||
bundleItem->files() + m_bundle3DSharedFiles);
|
||||
|
||||
if (err.isEmpty())
|
||||
m_widget->setImporterRunning(true);
|
||||
else
|
||||
qWarning() << __FUNCTION__ << err;
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::removeTexture(ContentLibraryTexture *tex)
|
||||
void ContentLibraryUserModel::removeTexture(ContentLibraryTexture *tex, bool refresh)
|
||||
{
|
||||
// remove resources
|
||||
Utils::FilePath::fromString(tex->texturePath()).removeFile();
|
||||
Utils::FilePath::fromString(tex->iconPath()).removeFile();
|
||||
|
||||
// remove from model
|
||||
m_userTextures.removeOne(tex);
|
||||
tex->deleteLater();
|
||||
m_userCategories[TexturesSectionIdx]->removeItem(tex);
|
||||
|
||||
// update model
|
||||
emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx));
|
||||
if (refresh) {
|
||||
emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx));
|
||||
updateIsEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::removeFromContentLib(QObject *item)
|
||||
{
|
||||
if (auto mat = qobject_cast<ContentLibraryMaterial *>(item))
|
||||
removeMaterialFromContentLib(mat);
|
||||
else if (auto itm = qobject_cast<ContentLibraryItem *>(item))
|
||||
remove3DFromContentLib(itm);
|
||||
auto castedItem = qobject_cast<ContentLibraryItem *>(item);
|
||||
QTC_ASSERT(castedItem, return);
|
||||
|
||||
removeItem(castedItem);
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::removeMaterialFromContentLib(ContentLibraryMaterial *item)
|
||||
void ContentLibraryUserModel::removeItemByName(const QString &qmlFileName, const QString &bundleId)
|
||||
{
|
||||
auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/materials/");
|
||||
ContentLibraryItem *itemToRemove = nullptr;
|
||||
const QObjectList items = m_userCategories[bundleIdToSectionIndex(bundleId)]->items();
|
||||
|
||||
QJsonArray itemsArr = m_bundleObjMaterial.value("items").toArray();
|
||||
for (QObject *item : items) {
|
||||
ContentLibraryItem *castedItem = qobject_cast<ContentLibraryItem *>(item);
|
||||
QTC_ASSERT(castedItem, return);
|
||||
|
||||
// remove qml and icon files
|
||||
Utils::FilePath::fromString(item->qmlFilePath()).removeFile();
|
||||
Utils::FilePath::fromUrl(item->icon()).removeFile();
|
||||
|
||||
// remove from the bundle json file
|
||||
for (int i = 0; i < itemsArr.size(); ++i) {
|
||||
if (itemsArr.at(i).toObject().value("qml") == item->qml()) {
|
||||
itemsArr.removeAt(i);
|
||||
if (castedItem->qml() == qmlFileName) {
|
||||
itemToRemove = castedItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_bundleObjMaterial.insert("items", itemsArr);
|
||||
|
||||
auto result = bundlePath.pathAppended(Constants::BUNDLE_JSON_FILENAME)
|
||||
.writeFileContents(QJsonDocument(m_bundleObjMaterial).toJson());
|
||||
if (!result)
|
||||
qWarning() << __FUNCTION__ << result.error();
|
||||
|
||||
// delete dependency files if they are only used by the deleted material
|
||||
QStringList allFiles;
|
||||
for (const QJsonValueConstRef &itemRef : std::as_const(itemsArr))
|
||||
allFiles.append(itemRef.toObject().value("files").toVariant().toStringList());
|
||||
|
||||
const QStringList itemFiles = item->files();
|
||||
for (const QString &file : itemFiles) {
|
||||
if (allFiles.count(file) == 0) // only used by the deleted item
|
||||
bundlePath.pathAppended(file).removeFile();
|
||||
}
|
||||
|
||||
// remove from model
|
||||
m_userMaterials.removeOne(item);
|
||||
item->deleteLater();
|
||||
|
||||
// update model
|
||||
emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::remove3DFromContentLibByName(const QString &qmlFileName)
|
||||
{
|
||||
ContentLibraryItem *itemToRemove = Utils::findOr(m_user3DItems, nullptr,
|
||||
[&qmlFileName](ContentLibraryItem *item) {
|
||||
return item->qml() == qmlFileName;
|
||||
});
|
||||
|
||||
if (itemToRemove)
|
||||
remove3DFromContentLib(itemToRemove);
|
||||
removeItem(itemToRemove);
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::remove3DFromContentLib(ContentLibraryItem *item)
|
||||
void ContentLibraryUserModel::removeItem(ContentLibraryItem *item)
|
||||
{
|
||||
QJsonArray itemsArr = m_bundleObj3D.value("items").toArray();
|
||||
UserItemCategory *itemCat = qobject_cast<UserItemCategory *>(item->parent());
|
||||
QTC_ASSERT(itemCat, return);
|
||||
|
||||
Utils::FilePath bundlePath = itemCat->bundlePath();
|
||||
QJsonObject &bundleObj = itemCat->bundleObjRef();
|
||||
|
||||
QJsonArray itemsArr = bundleObj.value("items").toArray();
|
||||
|
||||
// remove qml and icon files
|
||||
m_bundlePath3D.pathAppended(item->qml()).removeFile();
|
||||
bundlePath.pathAppended(item->qml()).removeFile();
|
||||
Utils::FilePath::fromUrl(item->icon()).removeFile();
|
||||
|
||||
// remove from the bundle json file
|
||||
@@ -264,10 +192,10 @@ void ContentLibraryUserModel::remove3DFromContentLib(ContentLibraryItem *item)
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_bundleObj3D.insert("items", itemsArr);
|
||||
bundleObj.insert("items", itemsArr);
|
||||
|
||||
auto result = m_bundlePath3D.pathAppended(Constants::BUNDLE_JSON_FILENAME)
|
||||
.writeFileContents(QJsonDocument(m_bundleObj3D).toJson());
|
||||
auto result = bundlePath.pathAppended(Constants::BUNDLE_JSON_FILENAME)
|
||||
.writeFileContents(QJsonDocument(bundleObj).toJson());
|
||||
if (!result)
|
||||
qWarning() << __FUNCTION__ << result.error();
|
||||
|
||||
@@ -279,276 +207,60 @@ void ContentLibraryUserModel::remove3DFromContentLib(ContentLibraryItem *item)
|
||||
const QStringList itemFiles = item->files();
|
||||
for (const QString &file : itemFiles) {
|
||||
if (allFiles.count(file) == 0) // only used by the deleted item
|
||||
m_bundlePath3D.pathAppended(file).removeFile();
|
||||
bundlePath.pathAppended(file).removeFile();
|
||||
}
|
||||
|
||||
// remove from model
|
||||
m_user3DItems.removeOne(item);
|
||||
item->deleteLater();
|
||||
itemCat->removeItem(item);
|
||||
|
||||
// update model
|
||||
emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
|
||||
SectionIndex sectionIdx = bundleIdToSectionIndex(item->bundleId());
|
||||
emit dataChanged(index(sectionIdx), index(sectionIdx), {ItemsRole, EmptyRole});
|
||||
updateIsEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets unique Qml component and icon file material names from a given name
|
||||
* @param defaultName input name
|
||||
* @return <Qml, icon> file names
|
||||
*/
|
||||
QPair<QString, QString> ContentLibraryUserModel::getUniqueLibMaterialNames(const QString &defaultName) const
|
||||
ContentLibraryUserModel::SectionIndex ContentLibraryUserModel::bundleIdToSectionIndex(
|
||||
const QString &bundleId) const
|
||||
{
|
||||
return getUniqueLibItemNames(defaultName, m_bundleObjMaterial);
|
||||
}
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
|
||||
/**
|
||||
* @brief Gets unique Qml component and icon file 3d item names from a given name
|
||||
* @param defaultName input name
|
||||
* @return <Qml, icon> file names
|
||||
*/
|
||||
QPair<QString, QString> ContentLibraryUserModel::getUniqueLib3DNames(const QString &defaultName) const
|
||||
{
|
||||
return getUniqueLibItemNames(defaultName, m_bundleObj3D);
|
||||
}
|
||||
if (bundleId == compUtils.userMaterialsBundleId())
|
||||
return MaterialsSectionIdx;
|
||||
|
||||
QPair<QString, QString> ContentLibraryUserModel::getUniqueLibItemNames(const QString &defaultName,
|
||||
const QJsonObject &bundleObj) const
|
||||
{
|
||||
QTC_ASSERT(!bundleObj.isEmpty(), return {});
|
||||
if (bundleId == compUtils.user3DBundleId())
|
||||
return Items3DSectionIdx;
|
||||
|
||||
const QJsonArray itemsArr = bundleObj.value("items").toArray();
|
||||
if (bundleId == compUtils.userEffectsBundleId())
|
||||
return EffectsSectionIdx;
|
||||
|
||||
QStringList itemQmls, itemIcons;
|
||||
for (const QJsonValueConstRef &itemRef : itemsArr) {
|
||||
const QJsonObject &obj = itemRef.toObject();
|
||||
itemQmls.append(obj.value("qml").toString().chopped(4)); // remove .qml
|
||||
itemIcons.append(QFileInfo(obj.value("icon").toString()).baseName());
|
||||
}
|
||||
|
||||
QString baseQml = UniqueName::generateId(defaultName);
|
||||
baseQml[0] = baseQml.at(0).toUpper();
|
||||
baseQml.prepend("My");
|
||||
|
||||
QString uniqueQml = UniqueName::generate(baseQml, [&] (const QString &name) {
|
||||
return itemQmls.contains(name);
|
||||
});
|
||||
|
||||
QString uniqueIcon = UniqueName::generate(defaultName, [&] (const QString &name) {
|
||||
return itemIcons.contains(name);
|
||||
});
|
||||
|
||||
return {uniqueQml + ".qml", uniqueIcon + ".png"};
|
||||
qWarning() << __FUNCTION__ << "Invalid section index for bundleId:" << bundleId;
|
||||
return {};
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ContentLibraryUserModel::roleNames() const
|
||||
{
|
||||
static const QHash<int, QByteArray> roles {
|
||||
{NameRole, "categoryName"},
|
||||
{VisibleRole, "categoryVisible"},
|
||||
{TitleRole, "categoryTitle"},
|
||||
{EmptyRole, "categoryEmpty"},
|
||||
{ItemsRole, "categoryItems"},
|
||||
{NoMatchRole, "categoryNoMatch"}
|
||||
};
|
||||
return roles;
|
||||
}
|
||||
|
||||
QJsonObject &ContentLibraryUserModel::bundleJsonMaterialObjectRef()
|
||||
QJsonObject &ContentLibraryUserModel::bundleObjectRef(const QString &bundleId)
|
||||
{
|
||||
return m_bundleObjMaterial;
|
||||
auto secIdx = bundleIdToSectionIndex(bundleId);
|
||||
return qobject_cast<UserItemCategory *>(m_userCategories[secIdx])->bundleObjRef();
|
||||
}
|
||||
|
||||
QJsonObject &ContentLibraryUserModel::bundleJson3DObjectRef()
|
||||
void ContentLibraryUserModel::loadBundles(bool force)
|
||||
{
|
||||
return m_bundleObj3D;
|
||||
}
|
||||
for (UserCategory *cat : std::as_const(m_userCategories))
|
||||
cat->loadBundle(force);
|
||||
|
||||
void ContentLibraryUserModel::loadBundles()
|
||||
{
|
||||
loadMaterialBundle();
|
||||
load3DBundle();
|
||||
loadTextureBundle();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::loadMaterialBundle()
|
||||
{
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
if (m_matBundleExists && m_bundleIdMaterial == compUtils.userMaterialsBundleId())
|
||||
return;
|
||||
|
||||
// clean up
|
||||
qDeleteAll(m_userMaterials);
|
||||
m_userMaterials.clear();
|
||||
m_matBundleExists = false;
|
||||
m_noMatchMaterials = true;
|
||||
m_bundleObjMaterial = {};
|
||||
m_bundleIdMaterial.clear();
|
||||
|
||||
m_bundlePathMaterial = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/materials");
|
||||
m_bundlePathMaterial.ensureWritableDir();
|
||||
m_bundlePathMaterial.pathAppended("icons").ensureWritableDir();
|
||||
|
||||
auto jsonFilePath = m_bundlePathMaterial.pathAppended(Constants::BUNDLE_JSON_FILENAME);
|
||||
if (!jsonFilePath.exists()) {
|
||||
QString jsonContent = "{\n";
|
||||
jsonContent += " \"id\": \"UserMaterials\",\n";
|
||||
jsonContent += " \"items\": []\n";
|
||||
jsonContent += "}";
|
||||
Utils::expected_str<qint64> res = jsonFilePath.writeFileContents(jsonContent.toLatin1());
|
||||
if (!res.has_value()) {
|
||||
qWarning() << __FUNCTION__ << res.error();
|
||||
emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Utils::expected_str<QByteArray> jsonContents = jsonFilePath.fileContents();
|
||||
if (!jsonContents.has_value()) {
|
||||
qWarning() << __FUNCTION__ << jsonContents.error();
|
||||
emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(jsonContents.value());
|
||||
if (bundleJsonDoc.isNull()) {
|
||||
qWarning() << __FUNCTION__ << "Invalid json file" << jsonFilePath;
|
||||
emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
|
||||
return;
|
||||
}
|
||||
|
||||
m_bundleIdMaterial = compUtils.userMaterialsBundleId();
|
||||
m_bundleObjMaterial = bundleJsonDoc.object();
|
||||
m_bundleObjMaterial["id"] = m_bundleIdMaterial;
|
||||
|
||||
// parse items
|
||||
QString typePrefix = compUtils.userMaterialsBundleType();
|
||||
const QJsonArray itemsArr = m_bundleObjMaterial.value("items").toArray();
|
||||
for (const QJsonValueConstRef &itemRef : itemsArr) {
|
||||
const QJsonObject itemObj = itemRef.toObject();
|
||||
|
||||
QString name = itemObj.value("name").toString();
|
||||
QString qml = itemObj.value("qml").toString();
|
||||
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
||||
QUrl icon = m_bundlePathMaterial.pathAppended(itemObj.value("icon").toString()).toUrl();
|
||||
QStringList files;
|
||||
const QJsonArray assetsArr = itemObj.value("files").toArray();
|
||||
for (const QJsonValueConstRef &asset : assetsArr)
|
||||
files.append(asset.toString());
|
||||
|
||||
m_userMaterials.append(new ContentLibraryMaterial(this, name, qml, type, icon, files,
|
||||
m_bundlePathMaterial.path(), ""));
|
||||
}
|
||||
|
||||
m_bundleMaterialSharedFiles.clear();
|
||||
const QJsonArray sharedFilesArr = m_bundleObjMaterial.value("sharedFiles").toArray();
|
||||
for (const QJsonValueConstRef &file : sharedFilesArr)
|
||||
m_bundleMaterialSharedFiles.append(file.toString());
|
||||
|
||||
m_matBundleExists = true;
|
||||
updateNoMatchMaterials();
|
||||
emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::load3DBundle()
|
||||
{
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
|
||||
if (m_bundle3DExists && m_bundleId3D == compUtils.user3DBundleId())
|
||||
return;
|
||||
|
||||
// clean up
|
||||
qDeleteAll(m_user3DItems);
|
||||
m_user3DItems.clear();
|
||||
m_bundle3DExists = false;
|
||||
m_noMatch3D = true;
|
||||
m_bundleObj3D = {};
|
||||
m_bundleId3D.clear();
|
||||
|
||||
m_bundlePath3D = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d");
|
||||
m_bundlePath3D.ensureWritableDir();
|
||||
m_bundlePath3D.pathAppended("icons").ensureWritableDir();
|
||||
|
||||
auto jsonFilePath = m_bundlePath3D.pathAppended(Constants::BUNDLE_JSON_FILENAME);
|
||||
if (!jsonFilePath.exists()) {
|
||||
QByteArray jsonContent = "{\n";
|
||||
jsonContent += " \"id\": \"User3D\",\n";
|
||||
jsonContent += " \"items\": []\n";
|
||||
jsonContent += "}";
|
||||
Utils::expected_str<qint64> res = jsonFilePath.writeFileContents(jsonContent);
|
||||
if (!res.has_value()) {
|
||||
qWarning() << __FUNCTION__ << res.error();
|
||||
emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Utils::expected_str<QByteArray> jsonContents = jsonFilePath.fileContents();
|
||||
if (!jsonContents.has_value()) {
|
||||
qWarning() << __FUNCTION__ << jsonContents.error();
|
||||
emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(jsonContents.value());
|
||||
if (bundleJsonDoc.isNull()) {
|
||||
qWarning() << __FUNCTION__ << "Invalid json file" << jsonFilePath;
|
||||
emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
|
||||
return;
|
||||
}
|
||||
|
||||
m_bundleId3D = compUtils.user3DBundleId();
|
||||
m_bundleObj3D = bundleJsonDoc.object();
|
||||
m_bundleObj3D["id"] = m_bundleId3D;
|
||||
|
||||
// parse items
|
||||
QString typePrefix = compUtils.user3DBundleType();
|
||||
const QJsonArray itemsArr = m_bundleObj3D.value("items").toArray();
|
||||
for (const QJsonValueConstRef &itemRef : itemsArr) {
|
||||
const QJsonObject itemObj = itemRef.toObject();
|
||||
|
||||
QString name = itemObj.value("name").toString();
|
||||
QString qml = itemObj.value("qml").toString();
|
||||
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
||||
QUrl icon = m_bundlePath3D.pathAppended(itemObj.value("icon").toString()).toUrl();
|
||||
QStringList files;
|
||||
const QJsonArray assetsArr = itemObj.value("files").toArray();
|
||||
for (const QJsonValueConstRef &asset : assetsArr)
|
||||
files.append(asset.toString());
|
||||
|
||||
m_user3DItems.append(new ContentLibraryItem(nullptr, name, qml, type, icon, files));
|
||||
}
|
||||
|
||||
m_bundle3DSharedFiles.clear();
|
||||
const QJsonArray sharedFilesArr = m_bundleObj3D.value("sharedFiles").toArray();
|
||||
for (const QJsonValueConstRef &file : sharedFilesArr)
|
||||
m_bundle3DSharedFiles.append(file.toString());
|
||||
|
||||
m_bundle3DExists = true;
|
||||
updateNoMatch3D();
|
||||
emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::loadTextureBundle()
|
||||
{
|
||||
if (!m_userTextures.isEmpty())
|
||||
return;
|
||||
|
||||
QDir bundleDir{Paths::bundlesPathSetting() + "/User/textures"};
|
||||
bundleDir.mkpath(".");
|
||||
bundleDir.mkdir("icons");
|
||||
|
||||
const QFileInfoList fileInfos = bundleDir.entryInfoList(QDir::Files);
|
||||
for (const QFileInfo &fileInfo : fileInfos) {
|
||||
QString suffix = '.' + fileInfo.suffix();
|
||||
auto iconFileInfo = QFileInfo(fileInfo.path().append("/icons/").append(fileInfo.baseName() + ".png"));
|
||||
QPair<QSize, qint64> info = ImageUtils::imageInfo(fileInfo.path());
|
||||
QString dirPath = fileInfo.path();
|
||||
QSize imgDims = info.first;
|
||||
qint64 imgFileSize = info.second;
|
||||
|
||||
auto tex = new ContentLibraryTexture(this, iconFileInfo, dirPath, suffix, imgDims, imgFileSize);
|
||||
m_userTextures.append(tex);
|
||||
}
|
||||
|
||||
updateNoMatchTextures();
|
||||
emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx));
|
||||
resetModel();
|
||||
updateIsEmpty();
|
||||
}
|
||||
|
||||
bool ContentLibraryUserModel::hasRequiredQuick3DImport() const
|
||||
@@ -556,9 +268,17 @@ bool ContentLibraryUserModel::hasRequiredQuick3DImport() const
|
||||
return m_widget->hasQuick3DImport() && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3;
|
||||
}
|
||||
|
||||
bool ContentLibraryUserModel::matBundleExists() const
|
||||
{
|
||||
return m_matBundleExists;
|
||||
void ContentLibraryUserModel::updateIsEmpty() {
|
||||
|
||||
bool newIsEmpty = Utils::allOf(std::as_const(m_userCategories), [](UserCategory *cat) {
|
||||
return cat->isEmpty();
|
||||
});
|
||||
|
||||
if (m_isEmpty == newIsEmpty)
|
||||
return;
|
||||
|
||||
m_isEmpty = newIsEmpty;
|
||||
emit isEmptyChanged();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::setSearchText(const QString &searchText)
|
||||
@@ -570,39 +290,46 @@ void ContentLibraryUserModel::setSearchText(const QString &searchText)
|
||||
|
||||
m_searchText = lowerSearchText;
|
||||
|
||||
for (ContentLibraryMaterial *item : std::as_const(m_userMaterials))
|
||||
item->filter(m_searchText);
|
||||
for (UserCategory *cat : std::as_const(m_userCategories))
|
||||
cat->filter(m_searchText);
|
||||
|
||||
for (ContentLibraryTexture *item : std::as_const(m_userTextures))
|
||||
item->filter(m_searchText);
|
||||
|
||||
for (ContentLibraryItem *item : std::as_const(m_user3DItems))
|
||||
item->filter(m_searchText);
|
||||
|
||||
updateNoMatchMaterials();
|
||||
updateNoMatchTextures();
|
||||
updateNoMatch3D();
|
||||
resetModel();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::updateMaterialsImportedState(const QStringList &importedItems)
|
||||
void ContentLibraryUserModel::updateImportedState(const QStringList &importedItems,
|
||||
const QString &bundleId)
|
||||
{
|
||||
SectionIndex secIdx = bundleIdToSectionIndex(bundleId);
|
||||
UserItemCategory *cat = qobject_cast<UserItemCategory *>(m_userCategories.at(secIdx));
|
||||
const QObjectList items = cat->items();
|
||||
|
||||
bool changed = false;
|
||||
for (ContentLibraryMaterial *mat : std::as_const(m_userMaterials))
|
||||
changed |= mat->setImported(importedItems.contains(mat->qml().chopped(4)));
|
||||
for (QObject *item : items) {
|
||||
ContentLibraryItem *castedItem = qobject_cast<ContentLibraryItem *>(item);
|
||||
changed |= castedItem->setImported(importedItems.contains(castedItem->qml().chopped(4)));
|
||||
}
|
||||
|
||||
if (changed)
|
||||
emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
|
||||
emit dataChanged(index(secIdx), index(secIdx), {ItemsRole});
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::update3DImportedState(const QStringList &importedItems)
|
||||
bool ContentLibraryUserModel::jsonPropertyExists(const QString &propName, const QString &propValue,
|
||||
const QString &bundleId) const
|
||||
{
|
||||
bool changed = false;
|
||||
for (ContentLibraryItem *item : std::as_const(m_user3DItems))
|
||||
changed |= item->setImported(importedItems.contains(item->qml().chopped(4)));
|
||||
SectionIndex secIdx = bundleIdToSectionIndex(bundleId);
|
||||
UserItemCategory *cat = qobject_cast<UserItemCategory *>(m_userCategories.at(secIdx));
|
||||
QTC_ASSERT(cat, return false);
|
||||
|
||||
if (changed)
|
||||
emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
|
||||
QJsonObject &bundleObj = cat->bundleObjRef();
|
||||
const QJsonArray itemsArr = bundleObj.value("items").toArray();
|
||||
|
||||
for (const QJsonValueConstRef &itemRef : itemsArr) {
|
||||
const QJsonObject &obj = itemRef.toObject();
|
||||
if (obj.value(propName).toString() == propValue)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::setQuick3DImportVersion(int major, int minor)
|
||||
@@ -626,33 +353,22 @@ void ContentLibraryUserModel::resetModel()
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::applyToSelected(ContentLibraryMaterial *mat, bool add)
|
||||
void ContentLibraryUserModel::applyToSelected(ContentLibraryItem *mat, bool add)
|
||||
{
|
||||
emit applyToSelectedTriggered(mat, add);
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::addToProject(QObject *item)
|
||||
void ContentLibraryUserModel::addToProject(ContentLibraryItem *item)
|
||||
{
|
||||
QString bundleDir;
|
||||
TypeName type;
|
||||
QString qmlFile;
|
||||
QStringList files;
|
||||
if (auto mat = qobject_cast<ContentLibraryMaterial *>(item)) {
|
||||
bundleDir = mat->dirPath();
|
||||
type = mat->type();
|
||||
qmlFile = mat->qml();
|
||||
files = mat->files() + m_bundleMaterialSharedFiles;
|
||||
} else if (auto itm = qobject_cast<ContentLibraryItem *>(item)) {
|
||||
bundleDir = m_bundlePath3D.toString();
|
||||
type = itm->type();
|
||||
qmlFile = itm->qml();
|
||||
files = itm->files() + m_bundle3DSharedFiles;
|
||||
} else {
|
||||
qWarning() << __FUNCTION__ << "Unsupported Item";
|
||||
return;
|
||||
}
|
||||
UserItemCategory *itemCat = qobject_cast<UserItemCategory *>(item->parent());
|
||||
QTC_ASSERT(itemCat, return);
|
||||
|
||||
QString err = m_widget->importer()->importComponent(bundleDir, type, qmlFile, files);
|
||||
QString bundlePath = itemCat->bundlePath().toFSPathString();
|
||||
TypeName type = item->type();
|
||||
QString qmlFile = item->qml();
|
||||
QStringList files = item->files() + itemCat->sharedFiles();
|
||||
|
||||
QString err = m_widget->importer()->importComponent(bundlePath, type, qmlFile, files);
|
||||
|
||||
if (err.isEmpty())
|
||||
m_widget->setImporterRunning(true);
|
||||
@@ -662,20 +378,8 @@ void ContentLibraryUserModel::addToProject(QObject *item)
|
||||
|
||||
void ContentLibraryUserModel::removeFromProject(QObject *item)
|
||||
{
|
||||
TypeName type;
|
||||
QString qml;
|
||||
if (auto mat = qobject_cast<ContentLibraryMaterial *>(item)) {
|
||||
type = mat->type();
|
||||
qml = mat->qml();
|
||||
} else if (auto itm = qobject_cast<ContentLibraryItem *>(item)) {
|
||||
type = itm->type();
|
||||
qml = itm->qml();
|
||||
} else {
|
||||
qWarning() << __FUNCTION__ << "Unsupported Item";
|
||||
return;
|
||||
}
|
||||
|
||||
QString err = m_widget->importer()->unimportComponent(type, qml);
|
||||
auto castedItem = qobject_cast<ContentLibraryItem *>(item);
|
||||
QString err = m_widget->importer()->unimportComponent(castedItem->type(), castedItem->qml());
|
||||
|
||||
if (err.isEmpty())
|
||||
m_widget->setImporterRunning(true);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "usercategory.h"
|
||||
|
||||
#include <utils/filepath.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
@@ -13,7 +15,6 @@ QT_FORWARD_DECLARE_CLASS(QUrl)
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ContentLibraryItem;
|
||||
class ContentLibraryMaterial;
|
||||
class ContentLibraryTexture;
|
||||
class ContentLibraryWidget;
|
||||
class NodeMetaInfo;
|
||||
@@ -22,13 +23,8 @@ class ContentLibraryUserModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged)
|
||||
Q_PROPERTY(bool bundle3DExists MEMBER m_bundle3DExists NOTIFY bundle3DExistsChanged)
|
||||
Q_PROPERTY(bool hasRequiredQuick3DImport READ hasRequiredQuick3DImport NOTIFY hasRequiredQuick3DImportChanged)
|
||||
Q_PROPERTY(QList<ContentLibraryMaterial *> userMaterials MEMBER m_userMaterials NOTIFY userMaterialsChanged)
|
||||
Q_PROPERTY(QList<ContentLibraryTexture *> userTextures MEMBER m_userTextures NOTIFY userTexturesChanged)
|
||||
Q_PROPERTY(QList<ContentLibraryItem *> user3DItems MEMBER m_user3DItems NOTIFY user3DItemsChanged)
|
||||
Q_PROPERTY(QList<ContentLibraryItem *> userEffects MEMBER m_userEffects NOTIFY userEffectsChanged)
|
||||
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
|
||||
|
||||
public:
|
||||
ContentLibraryUserModel(ContentLibraryWidget *parent = nullptr);
|
||||
@@ -38,98 +34,68 @@ public:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
void setSearchText(const QString &searchText);
|
||||
void updateMaterialsImportedState(const QStringList &importedItems);
|
||||
void update3DImportedState(const QStringList &importedItems);
|
||||
void updateImportedState(const QStringList &importedItems, const QString &bundleId);
|
||||
|
||||
QPair<QString, QString> getUniqueLibMaterialNames(const QString &defaultName = "Material") const;
|
||||
QPair<QString, QString> getUniqueLib3DNames(const QString &defaultName = "Item") const;
|
||||
bool jsonPropertyExists(const QString &propName, const QString &propValue,
|
||||
const QString &bundleId) const;
|
||||
|
||||
void setQuick3DImportVersion(int major, int minor);
|
||||
|
||||
bool hasRequiredQuick3DImport() const;
|
||||
|
||||
bool matBundleExists() const;
|
||||
void updateIsEmpty();
|
||||
|
||||
void resetModel();
|
||||
void updateNoMatchMaterials();
|
||||
void updateNoMatchTextures();
|
||||
void updateNoMatch3D();
|
||||
|
||||
void addMaterial(const QString &name, const QString &qml, const QUrl &icon, const QStringList &files);
|
||||
void add3DItem(const QString &name, const QString &qml, const QUrl &icon, const QStringList &files);
|
||||
void refresh3DSection();
|
||||
void addTextures(const QStringList &paths);
|
||||
void addItem(const QString &bundleId, const QString &name, const QString &qml,const QUrl &icon,
|
||||
const QStringList &files);
|
||||
void refreshSection(const QString &bundleId);
|
||||
void addTextures(const Utils::FilePaths &paths);
|
||||
void removeTextures(const QStringList &fileNames);
|
||||
|
||||
void add3DInstance(ContentLibraryItem *bundleItem);
|
||||
|
||||
void remove3DFromContentLibByName(const QString &qmlFileName);
|
||||
void removeItemByName(const QString &qmlFileName, const QString &bundleId);
|
||||
|
||||
void setBundleObj(const QJsonObject &newBundleObj);
|
||||
QJsonObject &bundleJsonMaterialObjectRef();
|
||||
QJsonObject &bundleJson3DObjectRef();
|
||||
QJsonObject &bundleObjectRef(const QString &bundleId);
|
||||
|
||||
void loadBundles();
|
||||
void loadBundles(bool force = false);
|
||||
|
||||
Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
|
||||
Q_INVOKABLE void addToProject(QObject *item);
|
||||
Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryItem *mat, bool add = false);
|
||||
Q_INVOKABLE void addToProject(ContentLibraryItem *item);
|
||||
Q_INVOKABLE void removeFromProject(QObject *item);
|
||||
Q_INVOKABLE void removeTexture(QmlDesigner::ContentLibraryTexture *tex);
|
||||
Q_INVOKABLE void removeTexture(QmlDesigner::ContentLibraryTexture *tex, bool refresh = true);
|
||||
Q_INVOKABLE void removeFromContentLib(QObject *item);
|
||||
|
||||
signals:
|
||||
void hasRequiredQuick3DImportChanged();
|
||||
void userMaterialsChanged();
|
||||
void userTexturesChanged();
|
||||
void user3DItemsChanged();
|
||||
void userEffectsChanged();
|
||||
void applyToSelectedTriggered(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
|
||||
void matBundleExistsChanged();
|
||||
void bundle3DExistsChanged();
|
||||
void isEmptyChanged();
|
||||
void applyToSelectedTriggered(QmlDesigner::ContentLibraryItem *mat, bool add = false);
|
||||
|
||||
private:
|
||||
// section indices must match the order in initModel()
|
||||
enum SectionIndex { MaterialsSectionIdx = 0,
|
||||
TexturesSectionIdx,
|
||||
Items3DSectionIdx,
|
||||
EffectsSectionIdx };
|
||||
|
||||
void createCategories();
|
||||
void loadMaterialBundle();
|
||||
void load3DBundle();
|
||||
void loadTextureBundle();
|
||||
bool isValidIndex(int idx) const;
|
||||
void removeMaterialFromContentLib(ContentLibraryMaterial *mat);
|
||||
void remove3DFromContentLib(ContentLibraryItem *item);
|
||||
QPair<QString, QString> getUniqueLibItemNames(const QString &defaultName,
|
||||
const QJsonObject &bundleObj) const;
|
||||
void removeItem(ContentLibraryItem *item);
|
||||
SectionIndex bundleIdToSectionIndex(const QString &bundleId) const;
|
||||
|
||||
ContentLibraryWidget *m_widget = nullptr;
|
||||
QString m_searchText;
|
||||
QString m_bundleIdMaterial;
|
||||
QString m_bundleId3D;
|
||||
QStringList m_bundleMaterialSharedFiles;
|
||||
QStringList m_bundle3DSharedFiles;
|
||||
Utils::FilePath m_bundlePathMaterial;
|
||||
Utils::FilePath m_bundlePath3D;
|
||||
|
||||
QList<ContentLibraryMaterial *> m_userMaterials;
|
||||
QList<ContentLibraryTexture *> m_userTextures;
|
||||
QList<ContentLibraryItem *> m_userEffects;
|
||||
QList<ContentLibraryItem *> m_user3DItems;
|
||||
QStringList m_userCategories;
|
||||
QList<UserCategory *> m_userCategories;
|
||||
|
||||
QJsonObject m_bundleObjMaterial;
|
||||
QJsonObject m_bundleObj3D;
|
||||
|
||||
bool m_noMatchMaterials = true;
|
||||
bool m_noMatchTextures = true;
|
||||
bool m_noMatch3D = true;
|
||||
bool m_noMatchEffects = true;
|
||||
bool m_matBundleExists = false;
|
||||
bool m_bundle3DExists = false;
|
||||
bool m_isEmpty = true;
|
||||
|
||||
int m_quick3dMajorVersion = -1;
|
||||
int m_quick3dMinorVersion = -1;
|
||||
|
||||
enum Roles { NameRole = Qt::UserRole + 1, VisibleRole, ItemsRole, NoMatchRole };
|
||||
enum Roles { TitleRole = Qt::UserRole + 1, ItemsRole, EmptyRole, NoMatchRole };
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,10 +8,16 @@
|
||||
#include <createtexture.h>
|
||||
#include <nodemetainfo.h>
|
||||
|
||||
#include <utils/filepath.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
class ZipWriter;
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QImage)
|
||||
QT_FORWARD_DECLARE_CLASS(QPixmap)
|
||||
QT_FORWARD_DECLARE_CLASS(QTemporaryDir)
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
@@ -21,6 +27,27 @@ class ContentLibraryTexture;
|
||||
class ContentLibraryWidget;
|
||||
class Model;
|
||||
|
||||
struct AssetPath
|
||||
{
|
||||
QString basePath;
|
||||
QString relativePath;
|
||||
|
||||
Utils::FilePath absFilPath() const
|
||||
{
|
||||
return Utils::FilePath::fromString(basePath).pathAppended(relativePath);
|
||||
}
|
||||
|
||||
bool operator==(const AssetPath &other) const
|
||||
{
|
||||
return basePath == other.basePath && relativePath == other.relativePath;
|
||||
}
|
||||
|
||||
friend size_t qHash(const AssetPath &asset)
|
||||
{
|
||||
return ::qHash(asset.relativePath);
|
||||
}
|
||||
};
|
||||
|
||||
class ContentLibraryView : public AbstractView
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -48,6 +75,9 @@ public:
|
||||
void auxiliaryDataChanged(const ModelNode &node,
|
||||
AuxiliaryDataKeyView type,
|
||||
const QVariant &data) override;
|
||||
void modelNodePreviewPixmapChanged(const ModelNode &node,
|
||||
const QPixmap &pixmap,
|
||||
const QByteArray &requestId) override;
|
||||
|
||||
private:
|
||||
void connectImporter();
|
||||
@@ -55,14 +85,22 @@ private:
|
||||
bool isItemBundle(const QString &bundleId) const;
|
||||
void active3DSceneChanged(qint32 sceneId);
|
||||
void updateBundlesQuick3DVersion();
|
||||
void addLibMaterial(const ModelNode &node, const QPixmap &iconPixmap);
|
||||
void addLibAssets(const QStringList &paths);
|
||||
void addLib3DComponent(const ModelNode &node);
|
||||
void addLib3DItem(const ModelNode &node);
|
||||
void genAndSaveIcon(const QString &qmlPath, const QString &iconPath);
|
||||
QStringList writeLibItemQml(const ModelNode &node, const QString &qml);
|
||||
QPair<QString, QSet<QString>> modelNodeToQmlString(const ModelNode &node, QStringList &depListIds,
|
||||
int depth = 0);
|
||||
void exportLib3DComponent(const ModelNode &node);
|
||||
void addLibItem(const ModelNode &node, const QPixmap &iconPixmap = {});
|
||||
void exportLibItem(const ModelNode &node, const QPixmap &iconPixmap = {});
|
||||
void importBundleToContentLib();
|
||||
void importBundleToProject();
|
||||
void getImageFromCache(const QString &qmlPath,
|
||||
std::function<void(const QImage &image)> successCallback);
|
||||
QSet<AssetPath> getBundleComponentDependencies(const ModelNode &node) const;
|
||||
QString getExportPath(const ModelNode &node) const;
|
||||
QString getImportPath() const;
|
||||
QString nodeNameToComponentFileName(const QString &name) const;
|
||||
QPair<QString, QSet<AssetPath>> modelNodeToQmlString(const ModelNode &node, int depth = 0);
|
||||
void addIconAndCloseZip(const auto &image);
|
||||
void saveIconToBundle(const auto &image);
|
||||
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const TypeName &typeName = {});
|
||||
@@ -89,6 +127,15 @@ private:
|
||||
bool m_hasQuick3DImport = false;
|
||||
qint32 m_sceneId = -1;
|
||||
CreateTexture m_createTexture;
|
||||
Utils::FilePath m_iconSavePath;
|
||||
QString m_generatedFolderName;
|
||||
QString m_bundleId;
|
||||
std::unique_ptr<ZipWriter> m_zipWriter;
|
||||
std::unique_ptr<QTemporaryDir> m_tempDir;
|
||||
|
||||
static constexpr char BUNDLE_VERSION[] = "1.0";
|
||||
static constexpr char ADD_ITEM_REQ_ID[] = "AddItemReqId";
|
||||
static constexpr char EXPORT_ITEM_REQ_ID[] = "ExportItemReqId";
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
#include "contentlibrarybundleimporter.h"
|
||||
#include "contentlibraryeffectsmodel.h"
|
||||
#include "contentlibraryiconprovider.h"
|
||||
#include "contentlibraryitem.h"
|
||||
#include "contentlibrarymaterial.h"
|
||||
#include "contentlibrarymaterialsmodel.h"
|
||||
#include "contentlibrarytexture.h"
|
||||
#include "contentlibrarytexturesmodel.h"
|
||||
#include "contentlibraryiconprovider.h"
|
||||
#include "contentlibraryusermodel.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -84,7 +84,7 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
} else if (m_materialToDrag) {
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
||||
if ((me->globalPosition().toPoint() - m_dragStartPoint).manhattanLength() > 20
|
||||
&& m_materialToDrag->isDownloaded()) {
|
||||
&& m_materialsModel->isMaterialDownloaded(m_materialToDrag)) {
|
||||
QByteArray data;
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
@@ -123,7 +123,8 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
}
|
||||
|
||||
ContentLibraryWidget::ContentLibraryWidget()
|
||||
: m_quickWidget(Utils::makeUniqueObjectPtr<StudioQuickWidget>(this))
|
||||
: m_iconProvider(Utils::makeUniqueObjectPtr<ContentLibraryIconProvider>())
|
||||
, m_quickWidget(Utils::makeUniqueObjectPtr<StudioQuickWidget>(this))
|
||||
, m_materialsModel(new ContentLibraryMaterialsModel(this))
|
||||
, m_texturesModel(new ContentLibraryTexturesModel("Textures", this))
|
||||
, m_environmentsModel(new ContentLibraryTexturesModel("Environments", this))
|
||||
@@ -138,8 +139,7 @@ ContentLibraryWidget::ContentLibraryWidget()
|
||||
|
||||
m_quickWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_CONTENT_LIBRARY);
|
||||
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||
m_quickWidget->engine()->addImageProvider(QStringLiteral("contentlibrary"),
|
||||
new Internal::ContentLibraryIconProvider);
|
||||
m_quickWidget->engine()->addImageProvider("contentlibrary", m_iconProvider.get());
|
||||
m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
|
||||
m_quickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground));
|
||||
|
||||
@@ -181,6 +181,10 @@ ContentLibraryWidget::ContentLibraryWidget()
|
||||
createImporter();
|
||||
}
|
||||
|
||||
ContentLibraryWidget::~ContentLibraryWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void ContentLibraryWidget::createImporter()
|
||||
{
|
||||
m_importer = new ContentLibraryBundleImporter();
|
||||
@@ -212,6 +216,11 @@ void ContentLibraryWidget::createImporter()
|
||||
});
|
||||
}
|
||||
|
||||
ContentLibraryIconProvider *ContentLibraryWidget::iconProvider() const
|
||||
{
|
||||
return m_iconProvider.get();
|
||||
}
|
||||
|
||||
void ContentLibraryWidget::updateImportedState(const QString &bundleId)
|
||||
{
|
||||
if (!m_importer)
|
||||
@@ -230,10 +239,8 @@ void ContentLibraryWidget::updateImportedState(const QString &bundleId)
|
||||
m_materialsModel->updateImportedState(importedItems);
|
||||
else if (bundleId == compUtils.effectsBundleId())
|
||||
m_effectsModel->updateImportedState(importedItems);
|
||||
else if (bundleId == compUtils.userMaterialsBundleId())
|
||||
m_userModel->updateMaterialsImportedState(importedItems);
|
||||
else if (bundleId == compUtils.user3DBundleId())
|
||||
m_userModel->update3DImportedState(importedItems);
|
||||
else
|
||||
m_userModel->updateImportedState(importedItems, bundleId);
|
||||
}
|
||||
|
||||
ContentLibraryBundleImporter *ContentLibraryWidget::importer() const
|
||||
|
||||
@@ -24,13 +24,13 @@ namespace QmlDesigner {
|
||||
|
||||
class ContentLibraryBundleImporter;
|
||||
class ContentLibraryEffectsModel;
|
||||
class ContentLibraryIconProvider;
|
||||
class ContentLibraryItem;
|
||||
class ContentLibraryMaterial;
|
||||
class ContentLibraryMaterialsModel;
|
||||
class ContentLibraryTexture;
|
||||
class ContentLibraryTexturesModel;
|
||||
class ContentLibraryUserModel;
|
||||
class NodeMetaInfo;
|
||||
|
||||
class ContentLibraryWidget : public QFrame
|
||||
{
|
||||
@@ -48,6 +48,7 @@ class ContentLibraryWidget : public QFrame
|
||||
|
||||
public:
|
||||
ContentLibraryWidget();
|
||||
~ContentLibraryWidget();
|
||||
|
||||
QList<QToolButton *> createToolBarWidgets();
|
||||
|
||||
@@ -94,6 +95,7 @@ public:
|
||||
QSize sizeHint() const override;
|
||||
|
||||
ContentLibraryBundleImporter *importer() const;
|
||||
ContentLibraryIconProvider *iconProvider() const;
|
||||
|
||||
signals:
|
||||
void bundleItemDragStarted(QmlDesigner::ContentLibraryItem *item);
|
||||
@@ -108,6 +110,7 @@ signals:
|
||||
void isQt6ProjectChanged();
|
||||
void importerRunningChanged();
|
||||
void hasModelSelectionChanged();
|
||||
void importBundle();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
@@ -128,6 +131,7 @@ private:
|
||||
void populateTextureBundleModels();
|
||||
void createImporter();
|
||||
|
||||
Utils::UniqueObjectPtr<ContentLibraryIconProvider> m_iconProvider;
|
||||
Utils::UniqueObjectPtr<StudioQuickWidget> m_quickWidget;
|
||||
QPointer<ContentLibraryMaterialsModel> m_materialsModel;
|
||||
QPointer<ContentLibraryTexturesModel> m_texturesModel;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "usercategory.h"
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
UserCategory::UserCategory(const QString &title, const Utils::FilePath &bundlePath)
|
||||
: m_title(title)
|
||||
, m_bundlePath(bundlePath)
|
||||
{
|
||||
}
|
||||
|
||||
QString UserCategory::title() const
|
||||
{
|
||||
return m_title;
|
||||
}
|
||||
|
||||
bool UserCategory::isEmpty() const
|
||||
{
|
||||
return m_isEmpty;
|
||||
}
|
||||
|
||||
void UserCategory::setIsEmpty(bool val)
|
||||
{
|
||||
if (m_isEmpty == val)
|
||||
return;
|
||||
|
||||
m_isEmpty = val;
|
||||
emit isEmptyChanged();
|
||||
}
|
||||
|
||||
bool UserCategory::noMatch() const
|
||||
{
|
||||
return m_noMatch;
|
||||
}
|
||||
|
||||
void UserCategory::setNoMatch(bool val)
|
||||
{
|
||||
if (m_noMatch == val)
|
||||
return;
|
||||
|
||||
m_noMatch = val;
|
||||
emit noMatchChanged();
|
||||
}
|
||||
|
||||
void UserCategory::addItem(QObject *item)
|
||||
{
|
||||
m_items.append(item);
|
||||
emit itemsChanged();
|
||||
|
||||
setIsEmpty(false);
|
||||
}
|
||||
|
||||
void UserCategory::removeItem(QObject *item)
|
||||
{
|
||||
m_items.removeOne(item);
|
||||
item->deleteLater();
|
||||
emit itemsChanged();
|
||||
|
||||
setIsEmpty(m_items.isEmpty());
|
||||
}
|
||||
|
||||
Utils::FilePath UserCategory::bundlePath() const
|
||||
{
|
||||
return m_bundlePath;
|
||||
}
|
||||
|
||||
QObjectList UserCategory::items() const
|
||||
{
|
||||
return m_items;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/filepath.h>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class UserCategory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UserCategory(const QString &title, const Utils::FilePath &bundlePath);
|
||||
|
||||
QString title() const;
|
||||
QObjectList items() const;
|
||||
|
||||
bool isEmpty() const;
|
||||
void setIsEmpty(bool val);
|
||||
|
||||
bool noMatch() const;
|
||||
void setNoMatch(bool val);
|
||||
|
||||
virtual void loadBundle(bool force = false) = 0;
|
||||
virtual void filter(const QString &searchText) = 0;
|
||||
|
||||
void addItem(QObject *item);
|
||||
void removeItem(QObject *item);
|
||||
|
||||
Utils::FilePath bundlePath() const;
|
||||
|
||||
signals:
|
||||
void itemsChanged();
|
||||
void isEmptyChanged();
|
||||
void noMatchChanged();
|
||||
|
||||
protected:
|
||||
QString m_title;
|
||||
Utils::FilePath m_bundlePath;
|
||||
QObjectList m_items;
|
||||
bool m_isEmpty = true;
|
||||
bool m_noMatch = true;
|
||||
bool m_bundleLoaded = false;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "useritemcategory.h"
|
||||
|
||||
#include "contentlibraryitem.h"
|
||||
|
||||
#include <qmldesignerconstants.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
UserItemCategory::UserItemCategory(const QString &title, const Utils::FilePath &bundlePath,
|
||||
const QString &bundleId)
|
||||
: UserCategory(title, bundlePath)
|
||||
, m_bundleId(bundleId)
|
||||
{
|
||||
}
|
||||
|
||||
void UserItemCategory::loadBundle(bool force)
|
||||
{
|
||||
if (m_bundleLoaded && !force)
|
||||
return;
|
||||
|
||||
// clean up
|
||||
qDeleteAll(m_items);
|
||||
m_items.clear();
|
||||
m_bundleLoaded = false;
|
||||
m_noMatch = false;
|
||||
m_bundleObj = {};
|
||||
|
||||
m_bundlePath.ensureWritableDir();
|
||||
m_bundlePath.pathAppended("icons").ensureWritableDir();
|
||||
|
||||
auto jsonFilePath = m_bundlePath.pathAppended(Constants::BUNDLE_JSON_FILENAME);
|
||||
if (!jsonFilePath.exists()) {
|
||||
QString jsonContent = "{\n";
|
||||
jsonContent += " \"id\": \"" + m_bundleId + "\",\n";
|
||||
jsonContent += " \"items\": []\n";
|
||||
jsonContent += "}";
|
||||
Utils::expected_str<qint64> res = jsonFilePath.writeFileContents(jsonContent.toLatin1());
|
||||
if (!res.has_value()) {
|
||||
qWarning() << __FUNCTION__ << res.error();
|
||||
setIsEmpty(true);
|
||||
emit itemsChanged();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Utils::expected_str<QByteArray> jsonContents = jsonFilePath.fileContents();
|
||||
if (!jsonContents.has_value()) {
|
||||
qWarning() << __FUNCTION__ << jsonContents.error();
|
||||
setIsEmpty(true);
|
||||
emit itemsChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(jsonContents.value());
|
||||
if (bundleJsonDoc.isNull()) {
|
||||
qWarning() << __FUNCTION__ << "Invalid json file" << jsonFilePath;
|
||||
setIsEmpty(true);
|
||||
emit itemsChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
m_bundleObj = bundleJsonDoc.object();
|
||||
m_bundleObj["id"] = m_bundleId;
|
||||
|
||||
// parse items
|
||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||
QString typePrefix = compUtils.userBundleType(m_bundleId);
|
||||
const QJsonArray itemsArr = m_bundleObj.value("items").toArray();
|
||||
for (const QJsonValueConstRef &itemRef : itemsArr) {
|
||||
const QJsonObject itemObj = itemRef.toObject();
|
||||
|
||||
QString name = itemObj.value("name").toString();
|
||||
QString qml = itemObj.value("qml").toString();
|
||||
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
||||
QUrl icon = m_bundlePath.pathAppended(itemObj.value("icon").toString()).toUrl();
|
||||
QStringList files = itemObj.value("files").toVariant().toStringList();
|
||||
|
||||
m_items.append(new ContentLibraryItem(this, name, qml, type, icon, files, m_bundleId));
|
||||
}
|
||||
|
||||
m_sharedFiles.clear();
|
||||
const QJsonArray sharedFilesArr = m_bundleObj.value("sharedFiles").toArray();
|
||||
for (const QJsonValueConstRef &file : sharedFilesArr)
|
||||
m_sharedFiles.append(file.toString());
|
||||
|
||||
m_bundleLoaded = true;
|
||||
setIsEmpty(m_items.isEmpty());
|
||||
emit itemsChanged();
|
||||
}
|
||||
|
||||
void UserItemCategory::filter(const QString &searchText)
|
||||
{
|
||||
bool noMatch = true;
|
||||
for (QObject *item : std::as_const(m_items)) {
|
||||
ContentLibraryItem *castedItem = qobject_cast<ContentLibraryItem *>(item);
|
||||
bool itemVisible = castedItem->filter(searchText);
|
||||
if (itemVisible)
|
||||
noMatch = false;
|
||||
}
|
||||
setNoMatch(noMatch);
|
||||
}
|
||||
|
||||
QStringList UserItemCategory::sharedFiles() const
|
||||
{
|
||||
return m_sharedFiles;
|
||||
}
|
||||
|
||||
QJsonObject &UserItemCategory::bundleObjRef()
|
||||
{
|
||||
return m_bundleObj;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "usercategory.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ContentLibraryItem;
|
||||
|
||||
class UserItemCategory : public UserCategory
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UserItemCategory(const QString &title, const Utils::FilePath &bundlePath, const QString &bundleId);
|
||||
|
||||
void loadBundle(bool force) override;
|
||||
void filter(const QString &searchText) override;
|
||||
|
||||
QStringList sharedFiles() const;
|
||||
|
||||
QJsonObject &bundleObjRef();
|
||||
|
||||
private:
|
||||
QString m_bundleId;
|
||||
QJsonObject m_bundleObj;
|
||||
QStringList m_sharedFiles;
|
||||
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "usertexturecategory.h"
|
||||
|
||||
#include "contentlibrarytexture.h"
|
||||
|
||||
#include <designerpaths.h>
|
||||
#include <imageutils.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
UserTextureCategory::UserTextureCategory(const QString &title, const Utils::FilePath &bundlePath)
|
||||
: UserCategory(title, bundlePath)
|
||||
{
|
||||
}
|
||||
|
||||
void UserTextureCategory::loadBundle(bool force)
|
||||
{
|
||||
if (m_bundleLoaded && !force)
|
||||
return;
|
||||
|
||||
// clean up
|
||||
qDeleteAll(m_items);
|
||||
m_items.clear();
|
||||
|
||||
m_bundlePath.ensureWritableDir();
|
||||
m_bundlePath.pathAppended("icons").ensureWritableDir();
|
||||
|
||||
addItems(m_bundlePath.dirEntries(QDir::Files));
|
||||
|
||||
m_bundleLoaded = true;
|
||||
}
|
||||
|
||||
void UserTextureCategory::filter(const QString &searchText)
|
||||
{
|
||||
bool noMatch = true;
|
||||
for (QObject *item : std::as_const(m_items)) {
|
||||
ContentLibraryTexture *castedItem = qobject_cast<ContentLibraryTexture *>(item);
|
||||
bool itemVisible = castedItem->filter(searchText);
|
||||
if (itemVisible)
|
||||
noMatch = false;
|
||||
}
|
||||
setNoMatch(noMatch);
|
||||
}
|
||||
|
||||
void UserTextureCategory::addItems(const Utils::FilePaths &paths)
|
||||
{
|
||||
for (const Utils::FilePath &filePath : paths) {
|
||||
QString suffix = '.' + filePath.suffix();
|
||||
auto iconFileInfo = filePath.parentDir().pathAppended("icons/" + filePath.baseName() + ".png")
|
||||
.toFileInfo();
|
||||
QPair<QSize, qint64> info = ImageUtils::imageInfo(filePath.path());
|
||||
QString dirPath = filePath.parentDir().toFSPathString();
|
||||
QSize imgDims = info.first;
|
||||
qint64 imgFileSize = info.second;
|
||||
|
||||
auto tex = new ContentLibraryTexture(this, iconFileInfo, dirPath, suffix, imgDims, imgFileSize);
|
||||
m_items.append(tex);
|
||||
}
|
||||
|
||||
setIsEmpty(m_items.isEmpty());
|
||||
emit itemsChanged();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "usercategory.h"
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ContentLibraryTexture;
|
||||
|
||||
class UserTextureCategory : public UserCategory
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UserTextureCategory(const QString &title, const Utils::FilePath &bundlePath);
|
||||
|
||||
void loadBundle(bool force) override;
|
||||
void filter(const QString &searchText) override;
|
||||
|
||||
void addItems(const Utils::FilePaths &paths);
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -16,15 +16,75 @@
|
||||
|
||||
#include <coreplugin/messagebox.h>
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QStack>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
static QString nameFromId(const QString &id, const QString &defaultName)
|
||||
{
|
||||
if (id.isEmpty())
|
||||
return defaultName;
|
||||
|
||||
QString newName = id;
|
||||
static const QRegularExpression sideUnderscores{R"((?:^_+)|(?:_+$))"};
|
||||
static const QRegularExpression underscores{R"((?:_+))"};
|
||||
static const QRegularExpression camelCases{R"((?:[A-Z](?=[a-z]))|(?:(?<=[a-z])[A-Z]))"};
|
||||
|
||||
newName.remove(sideUnderscores);
|
||||
|
||||
// Insert underscore to camel case edges
|
||||
QRegularExpressionMatchIterator caseMatch = camelCases.globalMatch(newName);
|
||||
QStack<int> camelCaseIndexes;
|
||||
while (caseMatch.hasNext())
|
||||
camelCaseIndexes.push(caseMatch.next().capturedStart());
|
||||
while (!camelCaseIndexes.isEmpty())
|
||||
newName.insert(camelCaseIndexes.pop(), '_');
|
||||
|
||||
// Replace underscored joints with space
|
||||
newName.replace(underscores, " ");
|
||||
newName = newName.trimmed();
|
||||
|
||||
if (newName.isEmpty())
|
||||
return defaultName;
|
||||
|
||||
newName[0] = newName[0].toUpper();
|
||||
return newName;
|
||||
}
|
||||
|
||||
CreateTexture::CreateTexture(AbstractView *view)
|
||||
: m_view{view}
|
||||
{}
|
||||
|
||||
ModelNode CreateTexture::execute()
|
||||
{
|
||||
ModelNode matLib = Utils3D::materialLibraryNode(m_view);
|
||||
if (!matLib.isValid())
|
||||
return {};
|
||||
|
||||
ModelNode newTextureNode;
|
||||
m_view->executeInTransaction(__FUNCTION__, [&]() {
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
newTextureNode = m_view->createModelNode("Texture");
|
||||
#else
|
||||
NodeMetaInfo metaInfo = m_view->model()->qtQuick3DTextureMetaInfo();
|
||||
newTextureNode = m_view->createModelNode("QtQuick3D.Texture",
|
||||
metaInfo.majorVersion(),
|
||||
metaInfo.minorVersion());
|
||||
#endif
|
||||
newTextureNode.ensureIdExists();
|
||||
VariantProperty textureName = newTextureNode.variantProperty("objectName");
|
||||
textureName.setValue(nameFromId(newTextureNode.id(), "Texture"_L1));
|
||||
matLib.defaultNodeListProperty().reparentHere(newTextureNode);
|
||||
});
|
||||
|
||||
return newTextureNode;
|
||||
}
|
||||
|
||||
ModelNode CreateTexture::execute(const QString &filePath, AddTextureMode mode, int sceneId)
|
||||
{
|
||||
Asset asset(filePath);
|
||||
@@ -94,8 +154,12 @@ ModelNode CreateTexture::createTextureFromImage(const Utils::FilePath &assetPat
|
||||
#endif
|
||||
newTexNode.setIdWithoutRefactoring(m_view->model()->generateNewId(assetPath.baseName()));
|
||||
|
||||
VariantProperty textureName = newTexNode.variantProperty("objectName");
|
||||
textureName.setValue(nameFromId(newTexNode.id(), "Texture"_L1));
|
||||
|
||||
VariantProperty sourceProp = newTexNode.variantProperty("source");
|
||||
sourceProp.setValue(QUrl(textureSource));
|
||||
|
||||
matLib.defaultNodeListProperty().reparentHere(newTexNode);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,10 @@ class CreateTexture : public QObject
|
||||
public:
|
||||
CreateTexture(AbstractView *view);
|
||||
|
||||
ModelNode execute(const QString &filePath, AddTextureMode mode = AddTextureMode::Texture, int sceneId = -1);
|
||||
ModelNode execute();
|
||||
ModelNode execute(const QString &filePath,
|
||||
AddTextureMode mode = AddTextureMode::Texture,
|
||||
int sceneId = -1);
|
||||
ModelNode resolveSceneEnv(int sceneId);
|
||||
void assignTextureAsLightProbe(const ModelNode &texture, int sceneId);
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ bool CurveEditorView::hasWidget() const
|
||||
|
||||
WidgetInfo CurveEditorView::widgetInfo()
|
||||
{
|
||||
return createWidgetInfo(m_editor, "CurveEditorId", WidgetInfo::BottomPane, 0, tr("Curves"));
|
||||
return createWidgetInfo(m_editor, "CurveEditorId", WidgetInfo::BottomPane, tr("Curves"));
|
||||
}
|
||||
|
||||
void CurveEditorView::modelAttached(Model *model)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
#include <bindingproperty.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <nodeabstractproperty.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <nodemetainfo.h>
|
||||
@@ -244,6 +244,9 @@ QTextStream &operator<<(QTextStream &stream, AuxiliaryDataType type)
|
||||
case AuxiliaryDataType::Temporary:
|
||||
stream << "Temporary";
|
||||
break;
|
||||
case AuxiliaryDataType::Persistent:
|
||||
stream << "Persistent";
|
||||
break;
|
||||
}
|
||||
|
||||
return stream;
|
||||
@@ -436,7 +439,6 @@ WidgetInfo DebugView::widgetInfo()
|
||||
return createWidgetInfo(m_debugViewWidget.data(),
|
||||
QStringLiteral("DebugView"),
|
||||
WidgetInfo::LeftPane,
|
||||
0,
|
||||
tr("Debug View"));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nodeinstanceglobal.h"
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
namespace QmlDesigner
|
||||
{
|
||||
|
||||
using ThemeId = ushort;
|
||||
|
||||
enum class GroupType { Colors, Flags, Numbers, Strings };
|
||||
|
||||
class ThemeProperty
|
||||
{
|
||||
public:
|
||||
bool isValid() const { return !name.trimmed().isEmpty() && value.isValid(); }
|
||||
|
||||
PropertyName name;
|
||||
QVariant value;
|
||||
bool isBinding = false;
|
||||
};
|
||||
|
||||
constexpr const char *GroupId(const GroupType type) {
|
||||
if (type == GroupType::Colors) return "colors";
|
||||
if (type == GroupType::Flags) return "flags";
|
||||
if (type == GroupType::Numbers) return "numbers";
|
||||
if (type == GroupType::Strings) return "strings";
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
}
|
||||
187
src/plugins/qmldesigner/components/designsystem/dsthemegroup.cpp
Normal file
187
src/plugins/qmldesigner/components/designsystem/dsthemegroup.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "dsthemegroup.h"
|
||||
|
||||
#include <model.h>
|
||||
#include <nodeproperty.h>
|
||||
#include <variantproperty.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QVariant>
|
||||
|
||||
namespace QmlDesigner {
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
Q_LOGGING_CATEGORY(dsLog, "qtc.designer.designSystem", QtInfoMsg)
|
||||
|
||||
std::optional<TypeName> groupTypeName(GroupType type)
|
||||
{
|
||||
switch (type) {
|
||||
case QmlDesigner::GroupType::Colors: return "color"; break;
|
||||
case QmlDesigner::GroupType::Flags: return "bool"; break;
|
||||
case QmlDesigner::GroupType::Numbers: return "real"; break;
|
||||
case QmlDesigner::GroupType::Strings: return "string"; break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QDebug &operator<<(QDebug &s, const ThemeProperty &p)
|
||||
{
|
||||
s << "{Name:" << p.name << ", Value:" << p.value << ", isBinding:" << p.isBinding << "}";
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
DSThemeGroup::DSThemeGroup(GroupType type):
|
||||
m_type(type)
|
||||
{}
|
||||
|
||||
DSThemeGroup::~DSThemeGroup() {}
|
||||
|
||||
bool DSThemeGroup::addProperty(ThemeId theme, const ThemeProperty &prop)
|
||||
{
|
||||
if (!prop.isValid()) {
|
||||
qCDebug(dsLog) << "Add property failed. Invalid property." << prop;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_values.contains(prop.name))
|
||||
m_values[prop.name] = {};
|
||||
|
||||
auto &tValues = m_values.at(prop.name);
|
||||
if (tValues.contains(theme)) {
|
||||
qCDebug(dsLog) << "Add property failed. Duplicate property name." << prop;
|
||||
return false;
|
||||
}
|
||||
|
||||
tValues.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(theme),
|
||||
std::forward_as_tuple(prop.value, prop.isBinding));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<ThemeProperty> DSThemeGroup::propertyValue(ThemeId theme, const PropertyName &name) const
|
||||
{
|
||||
if (!m_values.contains(name))
|
||||
return {};
|
||||
|
||||
const auto &tValues = m_values.at(name);
|
||||
const auto itr = tValues.find(theme);
|
||||
if (itr != tValues.end()) {
|
||||
auto &[value, isBindind] = itr->second;
|
||||
return ThemeProperty{name, value, isBindind};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void DSThemeGroup::updateProperty(ThemeId theme, PropertyName newName, const ThemeProperty &prop)
|
||||
{
|
||||
if (!m_values.contains(prop.name)) {
|
||||
qCDebug(dsLog) << "Property update failure. Can't find property" << prop;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ThemeProperty{newName, prop.value, prop.isBinding}.isValid()) {
|
||||
qCDebug(dsLog) << "Property update failure. Invalid property" << prop << newName;
|
||||
return;
|
||||
}
|
||||
|
||||
if (newName != prop.name && m_values.contains(newName)) {
|
||||
qCDebug(dsLog) << "Property update failure. Property name update already exists" << newName
|
||||
<< prop;
|
||||
return;
|
||||
}
|
||||
|
||||
auto &tValues = m_values.at(prop.name);
|
||||
const auto itr = tValues.find(theme);
|
||||
if (itr == tValues.end()) {
|
||||
qCDebug(dsLog) << "Property update failure. No property for the theme" << theme << prop;
|
||||
return;
|
||||
}
|
||||
|
||||
auto &entry = tValues.at(theme);
|
||||
entry.value = prop.value;
|
||||
entry.isBinding = prop.isBinding;
|
||||
if (newName != prop.name) {
|
||||
m_values[newName] = std::move(tValues);
|
||||
m_values.erase(prop.name);
|
||||
}
|
||||
}
|
||||
|
||||
void DSThemeGroup::removeProperty(const PropertyName &name)
|
||||
{
|
||||
m_values.erase(name);
|
||||
}
|
||||
|
||||
size_t DSThemeGroup::count(ThemeId theme) const
|
||||
{
|
||||
return std::accumulate(m_values.cbegin(),
|
||||
m_values.cend(),
|
||||
0ull,
|
||||
[theme](size_t c, const GroupProperties::value_type &p) {
|
||||
return c + (p.second.contains(theme) ? 1 : 0);
|
||||
});
|
||||
}
|
||||
|
||||
size_t DSThemeGroup::count() const
|
||||
{
|
||||
return m_values.size();
|
||||
}
|
||||
|
||||
void DSThemeGroup::removeTheme(ThemeId theme)
|
||||
{
|
||||
for (auto itr = m_values.begin(); itr != m_values.end();) {
|
||||
itr->second.erase(theme);
|
||||
itr = itr->second.size() == 0 ? m_values.erase(itr) : std::next(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void DSThemeGroup::duplicateValues(ThemeId from, ThemeId to)
|
||||
{
|
||||
for (auto itr = m_values.begin(); itr != m_values.end(); ++itr) {
|
||||
auto &[propName, values] = *itr;
|
||||
auto fromValueItr = values.find(from);
|
||||
if (fromValueItr != values.end())
|
||||
values[to] = fromValueItr->second;
|
||||
}
|
||||
}
|
||||
|
||||
void DSThemeGroup::decorate(ThemeId theme, ModelNode themeNode)
|
||||
{
|
||||
if (!count(theme))
|
||||
return; // No props for this theme in this group.
|
||||
|
||||
const auto groupName = GroupId(m_type);
|
||||
const auto typeName = groupTypeName(m_type);
|
||||
auto groupNode = themeNode.model()->createModelNode("QtObject");
|
||||
auto groupProperty = themeNode.nodeProperty(groupName);
|
||||
|
||||
if (!groupProperty || !typeName || !groupNode) {
|
||||
qCDebug(dsLog) << "Adding group node failed." << groupName << theme;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto itr = m_values.begin(); itr != m_values.end(); ++itr) {
|
||||
auto &[propName, values] = *itr;
|
||||
auto themeValue = values.find(theme);
|
||||
if (themeValue != values.end()) {
|
||||
auto &propData = themeValue->second;
|
||||
if (propData.isBinding) {
|
||||
auto bindingProp = groupNode.bindingProperty(propName);
|
||||
if (bindingProp)
|
||||
bindingProp.setDynamicTypeNameAndExpression(*typeName, propData.value.toString());
|
||||
} else {
|
||||
auto nodeProp = groupNode.variantProperty(propName);
|
||||
if (nodeProp)
|
||||
nodeProp.setDynamicTypeNameAndValue(*typeName, propData.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
groupProperty.setDynamicTypeNameAndsetModelNode("QtObject", groupNode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
#include "qmldesignercomponents_global.h"
|
||||
#include "dsconstants.h"
|
||||
#include "nodeinstanceglobal.h"
|
||||
|
||||
#include <modelnode.h>
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class QMLDESIGNERCOMPONENTS_EXPORT DSThemeGroup
|
||||
{
|
||||
struct PropertyData
|
||||
{
|
||||
PropertyData() = default;
|
||||
template<typename Variant>
|
||||
PropertyData(Variant &&value, bool isBinding)
|
||||
: value{std::forward<Variant>(value)}
|
||||
, isBinding{isBinding}
|
||||
{}
|
||||
|
||||
QVariant value;
|
||||
bool isBinding = false;
|
||||
};
|
||||
|
||||
using ThemeValues = std::map<ThemeId, PropertyData>;
|
||||
using GroupProperties = std::map<PropertyName, ThemeValues>;
|
||||
|
||||
public:
|
||||
DSThemeGroup(GroupType type);
|
||||
~DSThemeGroup();
|
||||
|
||||
bool addProperty(ThemeId, const ThemeProperty &prop);
|
||||
std::optional<ThemeProperty> propertyValue(ThemeId theme, const PropertyName &name) const;
|
||||
|
||||
void updateProperty(ThemeId theme, PropertyName newName, const ThemeProperty &prop);
|
||||
void removeProperty(const PropertyName &name);
|
||||
|
||||
GroupType type() const { return m_type; }
|
||||
|
||||
size_t count(ThemeId theme) const;
|
||||
size_t count() const;
|
||||
bool isEmpty() const;
|
||||
|
||||
void removeTheme(ThemeId theme);
|
||||
|
||||
void duplicateValues(ThemeId from, ThemeId to);
|
||||
void decorate(ThemeId theme, ModelNode themeNode);
|
||||
|
||||
private:
|
||||
const GroupType m_type;
|
||||
GroupProperties m_values;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "dsthememanager.h"
|
||||
|
||||
#include "dsconstants.h"
|
||||
#include "dsthemegroup.h"
|
||||
|
||||
#include <nodeproperty.h>
|
||||
#include <model.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QVariant>
|
||||
|
||||
namespace {
|
||||
Q_LOGGING_CATEGORY(dsLog, "qtc.designer.designSystem", QtInfoMsg)
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
DSThemeManager::DSThemeManager() {}
|
||||
|
||||
DSThemeManager::~DSThemeManager() {}
|
||||
|
||||
std::optional<ThemeId> DSThemeManager::addTheme(const ThemeName &themeName)
|
||||
{
|
||||
if (themeName.trimmed().isEmpty() || themeId(themeName)) {
|
||||
qCDebug(dsLog) << "Can not add new Theme. Duplicate theme name";
|
||||
return {};
|
||||
}
|
||||
|
||||
const ThemeId newThemeId = m_themes.empty() ? 1 : m_themes.rbegin()->first + 1;
|
||||
m_themes.insert({newThemeId, themeName});
|
||||
|
||||
// Copy the new theme properties from an old theme(first one).
|
||||
if (m_themes.size() > 1)
|
||||
duplicateTheme(m_themes.begin()->first, newThemeId);
|
||||
|
||||
return newThemeId;
|
||||
}
|
||||
|
||||
std::optional<ThemeId> DSThemeManager::themeId(const ThemeName &themeName) const
|
||||
{
|
||||
for (auto &[id, name] : m_themes) {
|
||||
if (themeName == name)
|
||||
return id;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t DSThemeManager::themeCount() const
|
||||
{
|
||||
return m_themes.size();
|
||||
}
|
||||
|
||||
void DSThemeManager::removeTheme(ThemeId id)
|
||||
{
|
||||
if (!m_themes.contains(id))
|
||||
return;
|
||||
|
||||
for (auto groupItr = m_groups.begin(); groupItr != m_groups.end(); ++groupItr)
|
||||
groupItr->second->removeTheme(id);
|
||||
|
||||
m_themes.erase(id);
|
||||
}
|
||||
|
||||
void DSThemeManager::duplicateTheme(ThemeId from, ThemeId to)
|
||||
{
|
||||
for (auto groupItr = m_groups.begin(); groupItr != m_groups.end(); ++groupItr)
|
||||
groupItr->second->duplicateValues(from, to);
|
||||
}
|
||||
|
||||
std::optional<ThemeProperty> DSThemeManager::property(ThemeId themeId,
|
||||
GroupType gType,
|
||||
const PropertyName &name) const
|
||||
{
|
||||
if (m_themes.contains(themeId)) {
|
||||
auto groupItr = m_groups.find(gType);
|
||||
if (groupItr != m_groups.end())
|
||||
return groupItr->second->propertyValue(themeId, name);
|
||||
}
|
||||
|
||||
qCDebug(dsLog) << "Error fetching property: {" << themeId << GroupId(gType) << name << "}";
|
||||
return {};
|
||||
}
|
||||
|
||||
bool DSThemeManager::addProperty(GroupType gType, const ThemeProperty &p)
|
||||
{
|
||||
if (!m_themes.size()) {
|
||||
qCDebug(dsLog) << "Can not add proprty. Themes empty";
|
||||
return false;
|
||||
}
|
||||
|
||||
// A property is added to all themes.
|
||||
DSThemeGroup *dsGroup = propertyGroup(gType);
|
||||
QTC_ASSERT(dsGroup, return false);
|
||||
|
||||
bool success = true;
|
||||
for (auto itr = m_themes.begin(); itr != m_themes.end(); ++itr)
|
||||
success &= dsGroup->addProperty(itr->first, p);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void DSThemeManager::removeProperty(GroupType gType, const PropertyName &name)
|
||||
{
|
||||
// A property is removed from all themes.
|
||||
DSThemeGroup *dsGroup = propertyGroup(gType);
|
||||
QTC_ASSERT(dsGroup, return);
|
||||
dsGroup->removeProperty(name);
|
||||
}
|
||||
|
||||
void DSThemeManager::updateProperty(ThemeId id, GroupType gType, const ThemeProperty &p)
|
||||
{
|
||||
updateProperty(id, gType, p, p.name);
|
||||
}
|
||||
|
||||
void DSThemeManager::updateProperty(ThemeId id,
|
||||
GroupType gType,
|
||||
const ThemeProperty &p,
|
||||
const PropertyName &newName)
|
||||
{
|
||||
if (!m_themes.contains(id))
|
||||
return;
|
||||
|
||||
DSThemeGroup *dsGroup = propertyGroup(gType);
|
||||
QTC_ASSERT(dsGroup, return);
|
||||
|
||||
dsGroup->updateProperty(id, newName, p);
|
||||
}
|
||||
|
||||
void DSThemeManager::decorate(ModelNode rootNode) const
|
||||
{
|
||||
if (!m_themes.size())
|
||||
return;
|
||||
|
||||
auto p = rootNode.bindingProperty("currentTheme");
|
||||
p.setDynamicTypeNameAndExpression("QtObject", QString::fromLatin1(m_themes.begin()->second));
|
||||
addGroupAliases(rootNode);
|
||||
|
||||
auto model = rootNode.model();
|
||||
for (auto itr = m_themes.begin(); itr != m_themes.end(); ++itr) {
|
||||
auto themeNode = model->createModelNode("QtObject");
|
||||
auto themeProperty = model->rootModelNode().nodeProperty(itr->second);
|
||||
themeProperty.setDynamicTypeNameAndsetModelNode("QtObject", themeNode);
|
||||
|
||||
// Add property groups
|
||||
for (auto groupItr = m_groups.begin(); groupItr != m_groups.end(); ++groupItr)
|
||||
groupItr->second->decorate(itr->first, themeNode);
|
||||
}
|
||||
}
|
||||
|
||||
DSThemeGroup *DSThemeManager::propertyGroup(GroupType type)
|
||||
{
|
||||
auto itr = m_groups.find(type);
|
||||
if (itr == m_groups.end())
|
||||
itr = m_groups.insert({type, std::make_unique<DSThemeGroup>(type)}).first;
|
||||
|
||||
return itr->second.get();
|
||||
}
|
||||
|
||||
void DSThemeManager::addGroupAliases(ModelNode rootNode) const
|
||||
{
|
||||
QSet<PropertyName> groupNames;
|
||||
for (auto groupItr = m_groups.begin(); groupItr != m_groups.end(); ++groupItr) {
|
||||
DSThemeGroup *group = groupItr->second.get();
|
||||
const PropertyName groupName = GroupId(group->type());
|
||||
if (group->count())
|
||||
groupNames.insert(groupName);
|
||||
}
|
||||
|
||||
for (const auto &name : groupNames) {
|
||||
auto p = rootNode.bindingProperty(name);
|
||||
auto binding = QString("currentTheme.%1").arg(QString::fromLatin1(name));
|
||||
p.setDynamicTypeNameAndExpression("QtObject", binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "qmldesignercomponents_global.h"
|
||||
|
||||
#include "dsconstants.h"
|
||||
#include "dsthemegroup.h"
|
||||
|
||||
#include <modelnode.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
using ThemeName = PropertyName;
|
||||
|
||||
class DSTheme;
|
||||
class QMLDESIGNERCOMPONENTS_EXPORT DSThemeManager
|
||||
{
|
||||
|
||||
public:
|
||||
DSThemeManager();
|
||||
~DSThemeManager();
|
||||
|
||||
DSThemeManager(const DSThemeManager&) = delete;
|
||||
DSThemeManager& operator=(const DSThemeManager&) = delete;
|
||||
|
||||
DSThemeManager(DSThemeManager&&) = default;
|
||||
DSThemeManager& operator=(DSThemeManager&&) = default;
|
||||
|
||||
std::optional<ThemeId> addTheme(const ThemeName &themeName);
|
||||
std::optional<ThemeId> themeId(const ThemeName &themeName) const;
|
||||
void removeTheme(ThemeId id);
|
||||
size_t themeCount() const;
|
||||
|
||||
void duplicateTheme(ThemeId from, ThemeId to);
|
||||
|
||||
bool addProperty(GroupType gType, const ThemeProperty &p);
|
||||
std::optional<ThemeProperty> property(ThemeId themeId,
|
||||
GroupType gType,
|
||||
const PropertyName &name) const;
|
||||
void removeProperty(GroupType gType, const PropertyName &p);
|
||||
void updateProperty(ThemeId id, GroupType gType, const ThemeProperty &p);
|
||||
void updateProperty(ThemeId id, GroupType gType, const ThemeProperty &p, const PropertyName &newName);
|
||||
|
||||
void decorate(ModelNode rootNode) const;
|
||||
|
||||
private:
|
||||
DSThemeGroup *propertyGroup(GroupType type);
|
||||
void addGroupAliases(ModelNode rootNode) const;
|
||||
|
||||
private:
|
||||
std::map<ThemeId, ThemeName> m_themes;
|
||||
std::map<GroupType, std::unique_ptr<DSThemeGroup>> m_groups;
|
||||
};
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <bakelightsdatamodel.h>
|
||||
#include <bindingproperty.h>
|
||||
#include <documentmanager.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <modelnode.h>
|
||||
#include <nodeabstractproperty.h>
|
||||
#include <nodeinstanceview.h>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "qmlobjectnode.h"
|
||||
#include "variantproperty.h"
|
||||
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
|
||||
#include <utils3d.h>
|
||||
|
||||
@@ -234,7 +234,7 @@ bool BakeLightsDataModel::reset()
|
||||
PropertyName dotName = mi.name() + '.';
|
||||
for (const AbstractProperty &prop : props) {
|
||||
if (prop.name().startsWith(dotName)) {
|
||||
PropertyName subName = prop.name().mid(dotName.size());
|
||||
PropertyNameView subName = prop.name().mid(dotName.size());
|
||||
if (subName == "bakedLightmap") {
|
||||
ModelNode blm = prop.toBindingProperty().resolveToModelNode();
|
||||
if (blm.isValid()) {
|
||||
@@ -269,7 +269,7 @@ bool BakeLightsDataModel::reset()
|
||||
PropertyName dotName = mi.name() + '.';
|
||||
for (const AbstractProperty &prop : props) {
|
||||
if (prop.name().startsWith(dotName)) {
|
||||
PropertyName subName = prop.name().mid(dotName.size());
|
||||
PropertyNameView subName = prop.name().mid(dotName.size());
|
||||
if (subName == "bakeMode") {
|
||||
if (prop.isVariantProperty()) {
|
||||
QString bakeModeStr = prop.toVariantProperty().value()
|
||||
|
||||
@@ -2,13 +2,9 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cameraspeedconfiguration.h"
|
||||
|
||||
#include "designersettings.h"
|
||||
#include "edit3dview.h"
|
||||
#include "edit3dviewconfig.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <utils/environment.h>
|
||||
|
||||
#include <QCursor>
|
||||
@@ -193,4 +189,9 @@ bool CameraSpeedConfiguration::eventFilter(QObject *obj, QEvent *event)
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
bool CameraSpeedConfiguration::isQDSTrusted() const
|
||||
{
|
||||
return Edit3DView::isQDSTrusted();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
Q_INVOKABLE void restoreCursor();
|
||||
Q_INVOKABLE void holdCursorInPlace();
|
||||
Q_INVOKABLE int devicePixelRatio();
|
||||
Q_INVOKABLE bool isQDSTrusted() const;
|
||||
|
||||
void cancel();
|
||||
void apply();
|
||||
@@ -58,6 +59,7 @@ signals:
|
||||
void speedChanged();
|
||||
void multiplierChanged();
|
||||
void totalSpeedChanged();
|
||||
void accessibilityOpened();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
|
||||
#include "edit3dactions.h"
|
||||
|
||||
#include "bakelights.h"
|
||||
#include "edit3dview.h"
|
||||
#include "nodemetainfo.h"
|
||||
#include "indicatoractionwidget.h"
|
||||
#include "qmldesignerconstants.h"
|
||||
#include "seekerslider.h"
|
||||
|
||||
@@ -34,10 +33,25 @@ void Edit3DActionTemplate::actionTriggered(bool b)
|
||||
m_action(m_selectionContext);
|
||||
}
|
||||
|
||||
Edit3DWidgetActionTemplate::Edit3DWidgetActionTemplate(QWidgetAction *widget)
|
||||
Edit3DWidgetActionTemplate::Edit3DWidgetActionTemplate(QWidgetAction *widget,
|
||||
SelectionContextOperation action)
|
||||
: PureActionInterface(widget)
|
||||
, m_action(action)
|
||||
{
|
||||
QObject::connect(widget, &QAction::triggered, widget, [this](bool value) {
|
||||
actionTriggered(value);
|
||||
});
|
||||
}
|
||||
|
||||
void Edit3DWidgetActionTemplate::setSelectionContext(const SelectionContext &selectionContext)
|
||||
{
|
||||
m_selectionContext = selectionContext;
|
||||
}
|
||||
|
||||
void Edit3DWidgetActionTemplate::actionTriggered([[maybe_unused]] bool b)
|
||||
{
|
||||
if (m_action)
|
||||
m_action(m_selectionContext);
|
||||
}
|
||||
|
||||
Edit3DAction::Edit3DAction(const QByteArray &menuId,
|
||||
@@ -154,4 +168,34 @@ bool Edit3DBakeLightsAction::isEnabled(const SelectionContext &) const
|
||||
&& !Utils3D::activeView3dId(m_view).isEmpty();
|
||||
}
|
||||
|
||||
Edit3DIndicatorButtonAction::Edit3DIndicatorButtonAction(const QByteArray &menuId,
|
||||
View3DActionType type,
|
||||
const QString &description,
|
||||
const QIcon &icon,
|
||||
SelectionContextOperation customAction,
|
||||
Edit3DView *view)
|
||||
: Edit3DAction(menuId,
|
||||
type,
|
||||
view,
|
||||
new Edit3DWidgetActionTemplate(new IndicatorButtonAction(description, icon),
|
||||
customAction))
|
||||
{
|
||||
m_buttonAction = qobject_cast<IndicatorButtonAction *>(action());
|
||||
}
|
||||
|
||||
void Edit3DIndicatorButtonAction::setIndicator(bool indicator)
|
||||
{
|
||||
m_buttonAction->setIndicator(indicator);
|
||||
}
|
||||
|
||||
bool Edit3DIndicatorButtonAction::isVisible(const SelectionContext &) const
|
||||
{
|
||||
return m_buttonAction->isVisible();
|
||||
}
|
||||
|
||||
bool Edit3DIndicatorButtonAction::isEnabled(const SelectionContext &) const
|
||||
{
|
||||
return m_buttonAction->isEnabled();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace QmlDesigner {
|
||||
using SelectionContextOperation = std::function<void(const SelectionContext &)>;
|
||||
class Edit3DView;
|
||||
class SeekerSliderAction;
|
||||
class IndicatorButtonAction;
|
||||
|
||||
class Edit3DActionTemplate : public DefaultAction
|
||||
{
|
||||
@@ -40,8 +41,13 @@ class Edit3DWidgetActionTemplate : public PureActionInterface
|
||||
Q_DISABLE_COPY(Edit3DWidgetActionTemplate)
|
||||
|
||||
public:
|
||||
explicit Edit3DWidgetActionTemplate(QWidgetAction *widget);
|
||||
virtual void setSelectionContext(const SelectionContext &) {}
|
||||
explicit Edit3DWidgetActionTemplate(QWidgetAction *widget, SelectionContextOperation action = {});
|
||||
|
||||
void setSelectionContext(const SelectionContext &selectionContext) override;
|
||||
virtual void actionTriggered(bool b);
|
||||
|
||||
SelectionContextOperation m_action;
|
||||
SelectionContext m_selectionContext;
|
||||
};
|
||||
|
||||
class Edit3DAction : public AbstractAction
|
||||
@@ -108,6 +114,27 @@ private:
|
||||
SeekerSliderAction *m_seeker = nullptr;
|
||||
};
|
||||
|
||||
class Edit3DIndicatorButtonAction : public Edit3DAction
|
||||
{
|
||||
public:
|
||||
Edit3DIndicatorButtonAction(const QByteArray &menuId,
|
||||
View3DActionType type,
|
||||
const QString &description,
|
||||
const QIcon &icon,
|
||||
SelectionContextOperation customAction,
|
||||
Edit3DView *view);
|
||||
|
||||
IndicatorButtonAction *buttonAction();
|
||||
void setIndicator(bool indicator);
|
||||
|
||||
protected:
|
||||
bool isVisible(const SelectionContext &) const override;
|
||||
bool isEnabled(const SelectionContext &) const override;
|
||||
|
||||
private:
|
||||
IndicatorButtonAction *m_buttonAction = nullptr;
|
||||
};
|
||||
|
||||
class Edit3DBakeLightsAction : public Edit3DAction
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -81,21 +81,13 @@ QWidget *Edit3DCanvas::busyIndicator() const
|
||||
return m_busyIndicator;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
extern "C" bool AXIsProcessTrusted();
|
||||
#endif
|
||||
|
||||
void Edit3DCanvas::setFlyMode(bool enabled, const QPoint &pos)
|
||||
{
|
||||
if (m_flyMode == enabled)
|
||||
return;
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
if (!AXIsProcessTrusted())
|
||||
m_isTrusted = false;
|
||||
#endif
|
||||
|
||||
m_flyMode = enabled;
|
||||
m_isQDSTrusted = Edit3DView::isQDSTrusted();
|
||||
|
||||
if (enabled) {
|
||||
m_flyModeStartTime = QDateTime::currentMSecsSinceEpoch();
|
||||
@@ -199,7 +191,7 @@ void Edit3DCanvas::mouseMoveEvent(QMouseEvent *e)
|
||||
// We notify explicit camera rotation need for puppet rather than rely in mouse events,
|
||||
// as mouse isn't grabbed on puppet side and can't handle fast movements that go out of
|
||||
// edit camera mouse area. This also simplifies split view handling.
|
||||
QPointF diff = m_isTrusted ? (m_hiddenCursorPos - e->globalPos()) : (m_lastCursorPos - e->globalPos());
|
||||
QPointF diff = m_isQDSTrusted ? (m_hiddenCursorPos - e->globalPos()) : (m_lastCursorPos - e->globalPos());
|
||||
|
||||
if (e->buttons() == (Qt::LeftButton | Qt::RightButton)) {
|
||||
m_parent->view()->emitView3DAction(View3DActionType::EditCameraMove,
|
||||
@@ -212,7 +204,7 @@ void Edit3DCanvas::mouseMoveEvent(QMouseEvent *e)
|
||||
m_flyModeFirstUpdate = false;
|
||||
}
|
||||
|
||||
if (m_isTrusted)
|
||||
if (m_isQDSTrusted)
|
||||
QCursor::setPos(m_hiddenCursorPos);
|
||||
else
|
||||
m_lastCursorPos = e->globalPos();
|
||||
|
||||
@@ -53,7 +53,7 @@ private:
|
||||
qint32 m_activeScene = -1;
|
||||
QElapsedTimer m_usageTimer;
|
||||
qreal m_opacity = 1.0;
|
||||
bool m_isTrusted = true;
|
||||
bool m_isQDSTrusted = true;
|
||||
QWidget *m_busyIndicator = nullptr;
|
||||
bool m_flyMode = false;
|
||||
QPoint m_flyModeStartCursorPos;
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "edit3dmaterialsaction.h"
|
||||
|
||||
#include <bindingproperty.h>
|
||||
#include <designmodewidget.h>
|
||||
#include <model.h>
|
||||
#include <modelnode.h>
|
||||
#include <modelutils.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <qmleditormenu.h>
|
||||
#include <variantproperty.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
static QString getMaterialName(const ModelNode &material, bool forceIncludeId = false)
|
||||
{
|
||||
QString materialName = material.variantProperty("objectName").value().toString();
|
||||
if (materialName.isEmpty() || forceIncludeId)
|
||||
materialName.append(QString("[%1]").arg(material.id()));
|
||||
return materialName;
|
||||
}
|
||||
|
||||
struct MaterialNameLessThan
|
||||
{
|
||||
bool operator()(const ModelNode &a, const ModelNode &b)
|
||||
{
|
||||
const QString aName = getMaterialName(a, true);
|
||||
const QString bName = getMaterialName(b, true);
|
||||
return aName.compare(bName, Qt::CaseSensitive) < 0;
|
||||
};
|
||||
};
|
||||
|
||||
static QList<ModelNode> getMaterials(const ModelNode &node)
|
||||
{
|
||||
BindingProperty matsProp = node.bindingProperty("materials");
|
||||
if (!matsProp.exists())
|
||||
return {};
|
||||
|
||||
Model *model = node.model();
|
||||
QList<ModelNode> materials;
|
||||
if (model->hasId(matsProp.expression()))
|
||||
materials.append(model->modelNodeForId(matsProp.expression()));
|
||||
else
|
||||
materials = matsProp.resolveToModelNodeList();
|
||||
|
||||
return materials;
|
||||
}
|
||||
|
||||
static QList<ModelNode> getSortedMaterials(const ModelNode &node)
|
||||
{
|
||||
QList<ModelNode> materials = getMaterials(node);
|
||||
std::sort(materials.begin(), materials.end(), MaterialNameLessThan{});
|
||||
return materials;
|
||||
}
|
||||
|
||||
static void removeMaterialFromNode(const ModelNode &node, const QString &materialId, int nthMaterial)
|
||||
{
|
||||
BindingProperty matsProp = node.bindingProperty("materials");
|
||||
if (!matsProp.exists())
|
||||
return;
|
||||
|
||||
const QString materialsExpression = matsProp.expression();
|
||||
Model *model = node.model();
|
||||
|
||||
if (matsProp.isList()) {
|
||||
matsProp.removeModelNodeFromArray(model->modelNodeForId(materialId));
|
||||
QStringList nodeMaterials = ModelUtils::expressionToList(materialsExpression);
|
||||
|
||||
int indexToBeRemoved = -1;
|
||||
do
|
||||
indexToBeRemoved = nodeMaterials.indexOf(materialId, indexToBeRemoved + 1);
|
||||
while (nthMaterial-- && indexToBeRemoved != -1);
|
||||
|
||||
if (indexToBeRemoved != -1)
|
||||
nodeMaterials.removeAt(indexToBeRemoved);
|
||||
|
||||
if (nodeMaterials.isEmpty())
|
||||
matsProp.parentModelNode().removeProperty(matsProp.name());
|
||||
else if (nodeMaterials.size() == 1)
|
||||
matsProp.setExpression(nodeMaterials.first());
|
||||
else
|
||||
matsProp.setExpression('[' + nodeMaterials.join(',') + ']');
|
||||
} else if (materialsExpression == materialId) {
|
||||
matsProp.parentModelNode().removeProperty(matsProp.name());
|
||||
}
|
||||
}
|
||||
|
||||
static QList<ModelNode> commonMaterialsOfNodes(const QList<ModelNode> &selectedNodes)
|
||||
{
|
||||
if (selectedNodes.isEmpty())
|
||||
return {};
|
||||
|
||||
if (selectedNodes.size() == 1)
|
||||
return getMaterials(selectedNodes.first());
|
||||
|
||||
QList<ModelNode> commonMaterials = getSortedMaterials(selectedNodes.first());
|
||||
for (const ModelNode &node : Utils::span(selectedNodes).subspan(1)) {
|
||||
const QList<ModelNode> materials = getSortedMaterials(node);
|
||||
QList<ModelNode> materialIntersection;
|
||||
std::set_intersection(commonMaterials.begin(),
|
||||
commonMaterials.end(),
|
||||
materials.begin(),
|
||||
materials.end(),
|
||||
std::back_inserter(materialIntersection),
|
||||
MaterialNameLessThan{});
|
||||
std::swap(commonMaterials, materialIntersection);
|
||||
if (commonMaterials.isEmpty())
|
||||
return {};
|
||||
}
|
||||
return commonMaterials;
|
||||
}
|
||||
|
||||
Edit3DMaterialsAction::Edit3DMaterialsAction(const QIcon &icon, QObject *parent)
|
||||
: QAction(icon, tr("Materials"), parent)
|
||||
{
|
||||
this->setMenu(new QmlEditorMenu("Materials"));
|
||||
connect(this, &QObject::destroyed, this->menu(), &QObject::deleteLater);
|
||||
}
|
||||
|
||||
void Edit3DMaterialsAction::updateMenu(const QList<ModelNode> &selecedNodes)
|
||||
{
|
||||
QMenu *menu = this->menu();
|
||||
QTC_ASSERT(menu, return);
|
||||
|
||||
m_selectedNodes = selecedNodes;
|
||||
|
||||
menu->clear();
|
||||
const QList<ModelNode> materials = commonMaterialsOfNodes(m_selectedNodes);
|
||||
QHash<ModelNode, int> nthMaterialMap; // <material, n times repeated>
|
||||
|
||||
for (const ModelNode &material : materials) {
|
||||
int nthMaterialWithTheSameId = nthMaterialMap.value(material, -1) + 1;
|
||||
nthMaterialMap.insert(material, nthMaterialWithTheSameId);
|
||||
QAction *materialAction = createMaterialAction(material, menu, nthMaterialWithTheSameId);
|
||||
if (materialAction)
|
||||
menu->addAction(materialAction);
|
||||
}
|
||||
|
||||
setVisible(!menu->actions().isEmpty());
|
||||
setEnabled(isVisible());
|
||||
}
|
||||
|
||||
void Edit3DMaterialsAction::removeMaterial(const QString &materialId, int nthMaterial)
|
||||
{
|
||||
if (m_selectedNodes.isEmpty())
|
||||
return;
|
||||
|
||||
AbstractView *nodesView = m_selectedNodes.first().view();
|
||||
nodesView->executeInTransaction(__FUNCTION__, [&] {
|
||||
for (ModelNode &node : m_selectedNodes)
|
||||
removeMaterialFromNode(node, materialId, nthMaterial);
|
||||
});
|
||||
}
|
||||
|
||||
QAction *Edit3DMaterialsAction::createMaterialAction(const ModelNode &material,
|
||||
QMenu *parentMenu,
|
||||
int nthMaterial)
|
||||
{
|
||||
const QString materialId = material.id();
|
||||
if (materialId.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
QString materialName = getMaterialName(material);
|
||||
|
||||
QAction *action = new QAction(materialName, parentMenu);
|
||||
QMenu *menu = new QmlEditorMenu(materialName, parentMenu);
|
||||
connect(action, &QObject::destroyed, menu, &QObject::deleteLater);
|
||||
|
||||
QAction *removeMaterialAction = new QAction(tr("Remove"), menu);
|
||||
connect(removeMaterialAction,
|
||||
&QAction::triggered,
|
||||
menu,
|
||||
std::bind(&Edit3DMaterialsAction::removeMaterial, this, materialId, nthMaterial));
|
||||
|
||||
QAction *editMaterialAction = new QAction(tr("Edit"), menu);
|
||||
connect(editMaterialAction, &QAction::triggered, menu, [material] {
|
||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialEditor", true);
|
||||
if (auto materialView = material.view())
|
||||
materialView->emitCustomNotification("select_material", {material});
|
||||
});
|
||||
|
||||
menu->addAction(editMaterialAction);
|
||||
menu->addAction(removeMaterialAction);
|
||||
action->setMenu(menu);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
}; // namespace QmlDesigner
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#pragma once
|
||||
|
||||
#include <selectioncontext.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QList>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ModelNode;
|
||||
|
||||
class Edit3DMaterialsAction : public QAction
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Edit3DMaterialsAction(const QIcon &icon, QObject *parent);
|
||||
|
||||
void updateMenu(const QList<ModelNode> &selecedNodes);
|
||||
|
||||
private slots:
|
||||
void removeMaterial(const QString &materialId, int nthMaterial);
|
||||
|
||||
private:
|
||||
QAction *createMaterialAction(const ModelNode &material, QMenu *parentMenu, int nthMaterial);
|
||||
|
||||
QList<ModelNode> m_selectedNodes;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "variantproperty.h"
|
||||
|
||||
#include <auxiliarydataproperties.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <utils3d.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/stylehelper.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QToolButton>
|
||||
|
||||
namespace QmlDesigner {
|
||||
@@ -86,7 +85,6 @@ WidgetInfo Edit3DView::widgetInfo()
|
||||
return createWidgetInfo(m_edit3DWidget.data(),
|
||||
"Editor3D",
|
||||
WidgetInfo::CentralPane,
|
||||
0,
|
||||
tr("3D"),
|
||||
tr("3D view"),
|
||||
DesignerWidgetFlags::IgnoreErrors);
|
||||
@@ -1306,22 +1304,25 @@ void Edit3DView::createEdit3DActions()
|
||||
this, [this] {
|
||||
setCameraSpeedAuxData(m_cameraSpeedConfiguration->speed(),
|
||||
m_cameraSpeedConfiguration->multiplier());
|
||||
});
|
||||
});
|
||||
connect(m_cameraSpeedConfiguration.data(), &CameraSpeedConfiguration::accessibilityOpened,
|
||||
this, [this] {
|
||||
m_cameraSpeedConfigAction->setIndicator(false);
|
||||
});
|
||||
}
|
||||
m_cameraSpeedConfiguration->showConfigDialog(resolveToolbarPopupPos(m_cameraSpeedConfigAction.get()));
|
||||
};
|
||||
|
||||
m_cameraSpeedConfigAction = std::make_unique<Edit3DAction>(
|
||||
m_cameraSpeedConfigAction = std::make_unique<Edit3DIndicatorButtonAction>(
|
||||
QmlDesigner::Constants::EDIT3D_CAMERA_SPEED_CONFIG,
|
||||
View3DActionType::Empty,
|
||||
QCoreApplication::translate("CameraSpeedConfigAction", "Open camera speed configuration dialog"),
|
||||
QKeySequence(),
|
||||
false,
|
||||
false,
|
||||
QCoreApplication::translate("CameraSpeedConfigAction",
|
||||
"Open camera speed configuration dialog"),
|
||||
toolbarIcon(DesignerIcons::CameraSpeedConfigIcon),
|
||||
this,
|
||||
cameraSpeedConfigTrigger);
|
||||
cameraSpeedConfigTrigger,
|
||||
this);
|
||||
|
||||
m_cameraSpeedConfigAction->setIndicator(!isQDSTrusted());
|
||||
|
||||
m_leftActions << m_selectionModeAction.get();
|
||||
m_leftActions << nullptr; // Null indicates separator
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
#include <QVector>
|
||||
#include <QVector3D>
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
extern "C" bool AXIsProcessTrusted();
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
class QInputEvent;
|
||||
@@ -41,6 +45,15 @@ public:
|
||||
bool showWireframe = false;
|
||||
};
|
||||
|
||||
static bool isQDSTrusted()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
return AXIsProcessTrusted();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Edit3DView(ExternalDependenciesInterface &externalDependencies);
|
||||
|
||||
WidgetInfo widgetInfo() override;
|
||||
@@ -180,7 +193,7 @@ private:
|
||||
std::unique_ptr<Edit3DAction> m_backgroundColorMenuAction;
|
||||
std::unique_ptr<Edit3DAction> m_snapToggleAction;
|
||||
std::unique_ptr<Edit3DAction> m_snapConfigAction;
|
||||
std::unique_ptr<Edit3DAction> m_cameraSpeedConfigAction;
|
||||
std::unique_ptr<Edit3DIndicatorButtonAction> m_cameraSpeedConfigAction;
|
||||
std::unique_ptr<Edit3DBakeLightsAction> m_bakeLightsAction;
|
||||
|
||||
int particlemode;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "edit3dactions.h"
|
||||
#include "edit3dcanvas.h"
|
||||
#include "edit3dmaterialsaction.h"
|
||||
#include "edit3dtoolbarmenu.h"
|
||||
#include "edit3dview.h"
|
||||
|
||||
@@ -35,7 +36,7 @@
|
||||
#include <coreplugin/actionmanager/command.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
|
||||
#include <utils/asset.h>
|
||||
#include <utils/fileutils.h>
|
||||
@@ -205,13 +206,8 @@ void Edit3DWidget::createContextMenu()
|
||||
DocumentManager::goIntoComponent(m_view->singleSelectedModelNode());
|
||||
});
|
||||
|
||||
m_editMaterialAction = m_contextMenu->addAction(
|
||||
contextIcon(DesignerIcons::MaterialIcon),
|
||||
tr("Edit Material"), [&] {
|
||||
SelectionContext selCtx(m_view);
|
||||
selCtx.setTargetNode(m_contextMenuTarget);
|
||||
ModelNodeOperations::editMaterial(selCtx);
|
||||
});
|
||||
m_materialsAction = new Edit3DMaterialsAction(contextIcon(DesignerIcons::MaterialIcon), this);
|
||||
m_contextMenu->addAction(m_materialsAction);
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
|
||||
@@ -374,7 +370,19 @@ void Edit3DWidget::createContextMenu()
|
||||
m_addToContentLibAction = m_contextMenu->addAction(
|
||||
contextIcon(DesignerIcons::CreateIcon), // TODO: placeholder icon
|
||||
tr("Add to Content Library"), [&] {
|
||||
view()->emitCustomNotification("add_3d_to_content_lib", {m_contextMenuTarget});
|
||||
view()->emitCustomNotification("add_3d_to_content_lib", {m_contextMenuTarget}); // To ContentLibrary
|
||||
});
|
||||
|
||||
m_importBundleAction = m_contextMenu->addAction(
|
||||
contextIcon(DesignerIcons::CreateIcon), // TODO: placeholder icon
|
||||
tr("Import Component"), [&] {
|
||||
view()->emitCustomNotification("import_bundle_to_project"); // To ContentLibrary
|
||||
});
|
||||
|
||||
m_exportBundleAction = m_contextMenu->addAction(
|
||||
contextIcon(DesignerIcons::CreateIcon), // TODO: placeholder icon
|
||||
tr("Export Component"), [&] {
|
||||
view()->emitCustomNotification("export_item_as_bundle", {m_contextMenuTarget}); // To ContentLibrary
|
||||
});
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
@@ -644,7 +652,7 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
|
||||
m_createSubMenu->setEnabled(!isSceneLocked());
|
||||
|
||||
m_editComponentAction->setEnabled(isSingleComponent);
|
||||
m_editMaterialAction->setEnabled(isModel);
|
||||
m_materialsAction->setEnabled(isModel);
|
||||
m_duplicateAction->setEnabled(selectionExcludingRoot);
|
||||
m_copyAction->setEnabled(selectionExcludingRoot);
|
||||
m_pasteAction->setEnabled(isPasteAvailable());
|
||||
@@ -657,6 +665,8 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
|
||||
m_bakeLightsAction->setVisible(view()->bakeLightsAction()->action()->isVisible());
|
||||
m_bakeLightsAction->setEnabled(view()->bakeLightsAction()->action()->isEnabled());
|
||||
m_addToContentLibAction->setEnabled(isNode && !isInBundle);
|
||||
m_exportBundleAction->setEnabled(isNode);
|
||||
m_materialsAction->updateMenu(view()->selectedModelNodes());
|
||||
|
||||
if (m_view) {
|
||||
int idx = m_view->activeSplit();
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace QmlDesigner {
|
||||
class Edit3DView;
|
||||
class Edit3DCanvas;
|
||||
class ToolBox;
|
||||
class Edit3DMaterialsAction;
|
||||
|
||||
struct ItemLibraryDetails {
|
||||
QString name;
|
||||
@@ -89,7 +90,6 @@ private:
|
||||
QPointer<QMenu> m_contextMenu;
|
||||
QPointer<QAction> m_bakeLightsAction;
|
||||
QPointer<QAction> m_editComponentAction;
|
||||
QPointer<QAction> m_editMaterialAction;
|
||||
QPointer<QAction> m_duplicateAction;
|
||||
QPointer<QAction> m_copyAction;
|
||||
QPointer<QAction> m_pasteAction;
|
||||
@@ -100,7 +100,10 @@ private:
|
||||
QPointer<QAction> m_selectParentAction;
|
||||
QPointer<QAction> m_toggleGroupAction;
|
||||
QPointer<QAction> m_wireFrameAction;
|
||||
QPointer<QAction> m_importBundleAction;
|
||||
QPointer<QAction> m_exportBundleAction;
|
||||
QPointer<QAction> m_addToContentLibAction;
|
||||
QPointer<Edit3DMaterialsAction> m_materialsAction;
|
||||
QHash<int, QPointer<QAction>> m_matOverrideActions;
|
||||
QPointer<QMenu> m_createSubMenu;
|
||||
ModelNode m_contextMenuTarget;
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "indicatoractionwidget.h"
|
||||
|
||||
#include <theme.h>
|
||||
#include <utils/icon.h>
|
||||
#include <utils/stylehelper.h>
|
||||
|
||||
#include <QActionGroup>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QStyleOption>
|
||||
#include <QStylePainter>
|
||||
#include <QToolBar>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
static void drawIndicator(QPainter *painter, const QPoint &point, int dimension)
|
||||
{
|
||||
painter->save();
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(Theme::getColor(Theme::DSamberLight));
|
||||
painter->drawEllipse(point, dimension, dimension);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
IndicatorButton::IndicatorButton(QWidget *parent)
|
||||
: QToolButton(parent)
|
||||
{
|
||||
Utils::StyleHelper::setPanelWidget(this);
|
||||
Utils::StyleHelper::setPanelWidgetSingleRow(this);
|
||||
}
|
||||
|
||||
bool IndicatorButton::indicator() const
|
||||
{
|
||||
return m_indicator;
|
||||
}
|
||||
|
||||
void IndicatorButton::setIndicator(bool newIndicator)
|
||||
{
|
||||
if (m_indicator != newIndicator) {
|
||||
m_indicator = newIndicator;
|
||||
emit indicatorChanged(m_indicator);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
QSize IndicatorButton::sizeHint() const
|
||||
{
|
||||
if (QMenu *menu = qobject_cast<QMenu *>(parent())) {
|
||||
ensurePolished();
|
||||
QStyleOptionMenuItem opt;
|
||||
initMenuStyleOption(menu, &opt, defaultAction());
|
||||
QSize sz = style()
|
||||
->itemTextRect(fontMetrics(), QRect(), Qt::TextShowMnemonic, false, text())
|
||||
.size();
|
||||
if (!opt.icon.isNull())
|
||||
sz = QSize(sz.width() + opt.maxIconWidth + 4, qMax(sz.height(), opt.maxIconWidth));
|
||||
QSize size = style()->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, this);
|
||||
return size;
|
||||
}
|
||||
return Super::sizeHint();
|
||||
}
|
||||
|
||||
void IndicatorButton::paintEvent([[maybe_unused]] QPaintEvent *event)
|
||||
{
|
||||
QStylePainter p(this);
|
||||
|
||||
if (QMenu *menu = qobject_cast<QMenu *>(parent())) {
|
||||
this->setFixedWidth(menu->width());
|
||||
QStyleOptionMenuItem opt;
|
||||
initMenuStyleOption(menu, &opt, defaultAction());
|
||||
p.drawControl(QStyle::CE_MenuItem, opt);
|
||||
|
||||
if (indicator() && opt.maxIconWidth && !opt.icon.isNull()) {
|
||||
const int indicatorDim = opt.rect.height() / 8;
|
||||
const int indicatorOffset = indicatorDim * 5 / 4;
|
||||
|
||||
drawIndicator(&p,
|
||||
opt.rect.topLeft()
|
||||
+ QPoint{opt.rect.height() - indicatorOffset, indicatorOffset},
|
||||
indicatorDim);
|
||||
}
|
||||
} else {
|
||||
QStyleOptionToolButton option;
|
||||
initStyleOption(&option);
|
||||
p.drawComplexControl(QStyle::CC_ToolButton, option);
|
||||
|
||||
if (indicator() && option.iconSize.isValid() && !option.icon.isNull()) {
|
||||
const int indicatorDim = std::min(option.rect.width(), option.rect.height()) / 8;
|
||||
const int indicatorOffset = indicatorDim * 5 / 4;
|
||||
drawIndicator(&p,
|
||||
option.rect.topRight() + QPoint{-indicatorOffset, indicatorOffset},
|
||||
indicatorDim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IndicatorButton::initMenuStyleOption(QMenu *menu,
|
||||
QStyleOptionMenuItem *option,
|
||||
const QAction *action) const
|
||||
{
|
||||
if (!option || !action)
|
||||
return;
|
||||
|
||||
option->initFrom(menu);
|
||||
option->palette = palette();
|
||||
option->state = QStyle::State_None;
|
||||
|
||||
if (window()->isActiveWindow())
|
||||
option->state |= QStyle::State_Active;
|
||||
if (isEnabled() && action->isEnabled() && (!action->menu() || action->menu()->isEnabled()))
|
||||
option->state |= QStyle::State_Enabled;
|
||||
else
|
||||
option->palette.setCurrentColorGroup(QPalette::Disabled);
|
||||
|
||||
option->font = action->font().resolve(font());
|
||||
option->fontMetrics = QFontMetrics(option->font);
|
||||
|
||||
if (menu->activeAction() && menu->activeAction() == action)
|
||||
option->state |= QStyle::State_Selected;
|
||||
|
||||
option->menuHasCheckableItems = false;
|
||||
if (!action->isCheckable()) {
|
||||
option->checkType = QStyleOptionMenuItem::NotCheckable;
|
||||
} else {
|
||||
option->checkType = (action->actionGroup() && action->actionGroup()->isExclusive())
|
||||
? QStyleOptionMenuItem::Exclusive
|
||||
: QStyleOptionMenuItem::NonExclusive;
|
||||
option->checked = action->isChecked();
|
||||
}
|
||||
if (action->menu())
|
||||
option->menuItemType = QStyleOptionMenuItem::SubMenu;
|
||||
else if (action->isSeparator())
|
||||
option->menuItemType = QStyleOptionMenuItem::Separator;
|
||||
else
|
||||
option->menuItemType = QStyleOptionMenuItem::Normal;
|
||||
if (action->isIconVisibleInMenu())
|
||||
option->icon = action->icon();
|
||||
|
||||
option->text = action->text();
|
||||
option->maxIconWidth = 20;
|
||||
option->rect = rect();
|
||||
}
|
||||
|
||||
IndicatorButtonAction::IndicatorButtonAction(const QString &description,
|
||||
const QIcon &icon,
|
||||
QObject *parent)
|
||||
: QWidgetAction(parent)
|
||||
{
|
||||
setText(description);
|
||||
setToolTip(description);
|
||||
setIcon(icon);
|
||||
}
|
||||
|
||||
IndicatorButtonAction::~IndicatorButtonAction() = default;
|
||||
|
||||
void IndicatorButtonAction::setIndicator(bool indicator)
|
||||
{
|
||||
if (m_indicator != indicator) {
|
||||
m_indicator = indicator;
|
||||
emit indicatorChanged(m_indicator, QPrivateSignal{});
|
||||
}
|
||||
}
|
||||
|
||||
QWidget *IndicatorButtonAction::createWidget(QWidget *parent)
|
||||
{
|
||||
if (qobject_cast<QMenu *>(parent))
|
||||
return nullptr;
|
||||
|
||||
IndicatorButton *button = new IndicatorButton(parent);
|
||||
|
||||
connect(this, &IndicatorButtonAction::indicatorChanged, button, &IndicatorButton::setIndicator);
|
||||
connect(button, &IndicatorButton::indicatorChanged, this, &IndicatorButtonAction::setIndicator);
|
||||
connect(button, &QToolButton::clicked, this, &QAction::trigger);
|
||||
button->setIndicator(m_indicator);
|
||||
button->setDefaultAction(this);
|
||||
|
||||
if (QToolBar *tb = qobject_cast<QToolBar *>(parent)) {
|
||||
button->setAutoRaise(true);
|
||||
button->setFocusPolicy(Qt::NoFocus);
|
||||
button->setIconSize(tb->iconSize());
|
||||
button->setToolButtonStyle(tb->toolButtonStyle());
|
||||
connect(tb, &QToolBar::iconSizeChanged, button, &IndicatorButton::setIconSize);
|
||||
connect(tb, &QToolBar::toolButtonStyleChanged, button, &IndicatorButton::setToolButtonStyle);
|
||||
connect(button, &IndicatorButton::triggered, tb, &QToolBar::actionTriggered);
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#pragma once
|
||||
|
||||
#include <QToolButton>
|
||||
#include <QWidgetAction>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QStyleOptionToolButton;
|
||||
class QPaintEvent;
|
||||
class QStyleOptionMenuItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class IndicatorButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL)
|
||||
public:
|
||||
explicit IndicatorButton(QWidget *parent = nullptr);
|
||||
|
||||
bool indicator() const;
|
||||
void setIndicator(bool newIndicator);
|
||||
|
||||
protected:
|
||||
QSize sizeHint() const override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void initMenuStyleOption(QMenu *menu, QStyleOptionMenuItem *option, const QAction *action) const;
|
||||
|
||||
signals:
|
||||
void indicatorChanged(bool);
|
||||
|
||||
private:
|
||||
bool m_indicator = false;
|
||||
using Super = QToolButton;
|
||||
};
|
||||
|
||||
class IndicatorButtonAction : public QWidgetAction
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit IndicatorButtonAction(const QString &description,
|
||||
const QIcon &icon,
|
||||
QObject *parent = nullptr);
|
||||
virtual ~IndicatorButtonAction();
|
||||
|
||||
public slots:
|
||||
void setIndicator(bool indicator);
|
||||
|
||||
protected:
|
||||
virtual QWidget *createWidget(QWidget *parent) override;
|
||||
|
||||
private:
|
||||
bool m_indicator;
|
||||
|
||||
signals:
|
||||
void indicatorChanged(bool, QPrivateSignal);
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "modelnodecontextmenu.h"
|
||||
#include "qmldesignerconstants.h"
|
||||
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QGraphicsSceneDragDropEvent>
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <QComboBox>
|
||||
#include <QPainter>
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
BackgroundAction::BackgroundAction(QObject *parent) :
|
||||
@@ -21,7 +23,17 @@ void BackgroundAction::setColor(const QColor &color)
|
||||
{
|
||||
if (m_comboBox)
|
||||
m_comboBox->setCurrentIndex(colors().indexOf(color));
|
||||
}
|
||||
|
||||
void BackgroundAction::setColorEnabled(const QColor &color, bool enable)
|
||||
{
|
||||
if (!m_comboBox)
|
||||
return;
|
||||
|
||||
QStandardItemModel *model = qobject_cast<QStandardItemModel *>(m_comboBox->model());
|
||||
if (QStandardItem *item = model->item(colors().indexOf(color)))
|
||||
item->setFlags(enable ? item->flags() | Qt::ItemIsEnabled
|
||||
: item->flags() & ~Qt::ItemIsEnabled);
|
||||
}
|
||||
|
||||
QIcon iconForColor(const QColor &color) {
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
explicit BackgroundAction(QObject *parent);
|
||||
void setColor(const QColor &color);
|
||||
|
||||
void setColorEnabled(const QColor &color, bool enable);
|
||||
signals:
|
||||
void backgroundChanged(const QColor &color);
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ qreal FormEditorItem::selectionWeigth(const QPointF &point, int iteration)
|
||||
return weight;
|
||||
}
|
||||
|
||||
void FormEditorItem::synchronizeOtherProperty(const QByteArray &propertyName)
|
||||
void FormEditorItem::synchronizeOtherProperty(PropertyNameView propertyName)
|
||||
{
|
||||
if (propertyName == "opacity")
|
||||
setOpacity(qmlItemNode().instanceValue("opacity").toDouble());
|
||||
@@ -557,7 +557,7 @@ QmlItemNode FormEditorItem::qmlItemNode() const
|
||||
return m_qmlItemNode;
|
||||
}
|
||||
|
||||
void FormEditorFlowItem::synchronizeOtherProperty(const QByteArray &)
|
||||
void FormEditorFlowItem::synchronizeOtherProperty(PropertyNameView)
|
||||
{
|
||||
setContentVisible(true);
|
||||
}
|
||||
@@ -783,7 +783,7 @@ QTransform FormEditorFlowActionItem::instanceSceneContentItemTransform() const
|
||||
return sceneTransform();
|
||||
}
|
||||
|
||||
void FormEditorTransitionItem::synchronizeOtherProperty(const QByteArray &)
|
||||
void FormEditorTransitionItem::synchronizeOtherProperty(PropertyNameView)
|
||||
{
|
||||
setContentVisible(true);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
QPointF center() const;
|
||||
qreal selectionWeigth(const QPointF &point, int iteration);
|
||||
|
||||
virtual void synchronizeOtherProperty(const QByteArray &propertyName);
|
||||
virtual void synchronizeOtherProperty(PropertyNameView propertyName);
|
||||
virtual void setDataModelPosition(const QPointF &position);
|
||||
virtual void setDataModelPositionInBaseState(const QPointF &position);
|
||||
virtual QPointF instancePosition() const;
|
||||
@@ -141,7 +141,7 @@ class FormEditorFlowItem : public FormEditorItem
|
||||
friend FormEditorScene;
|
||||
|
||||
public:
|
||||
void synchronizeOtherProperty(const QByteArray &propertyName) override;
|
||||
void synchronizeOtherProperty(PropertyNameView propertyName) override;
|
||||
void setDataModelPosition(const QPointF &position) override;
|
||||
void setDataModelPositionInBaseState(const QPointF &position) override;
|
||||
void updateGeometry() override;
|
||||
@@ -198,7 +198,7 @@ class FormEditorTransitionItem : public FormEditorItem
|
||||
friend FormEditorScene;
|
||||
|
||||
public:
|
||||
void synchronizeOtherProperty(const QByteArray &propertyName) override;
|
||||
void synchronizeOtherProperty(PropertyNameView propertyName) override;
|
||||
void setDataModelPosition(const QPointF &position) override;
|
||||
void setDataModelPositionInBaseState(const QPointF &position) override;
|
||||
void updateGeometry() override;
|
||||
|
||||
@@ -142,7 +142,7 @@ void FormEditorScene::synchronizeParent(const QmlItemNode &qmlItemNode)
|
||||
reparentItem(qmlItemNode, parentNode);
|
||||
}
|
||||
|
||||
void FormEditorScene::synchronizeOtherProperty(FormEditorItem *item, const QByteArray &propertyName)
|
||||
void FormEditorScene::synchronizeOtherProperty(FormEditorItem *item, PropertyNameView propertyName)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
|
||||
void synchronizeTransformation(FormEditorItem *item);
|
||||
void synchronizeParent(const QmlItemNode &qmlItemNode);
|
||||
void synchronizeOtherProperty(FormEditorItem *item, const QByteArray &propertyName);
|
||||
void synchronizeOtherProperty(FormEditorItem *item, PropertyNameView propertyName);
|
||||
|
||||
FormEditorItem* calulateNewParent(FormEditorItem *widget);
|
||||
LayerItem* manipulatorLayerItem() const;
|
||||
|
||||
@@ -364,7 +364,6 @@ WidgetInfo FormEditorView::widgetInfo()
|
||||
return createWidgetInfo(m_formEditorWidget.data(),
|
||||
"FormEditor",
|
||||
WidgetInfo::CentralPane,
|
||||
0,
|
||||
tr("2D"),
|
||||
tr("2D view"),
|
||||
DesignerWidgetFlags::IgnoreErrors);
|
||||
@@ -996,10 +995,8 @@ void FormEditorView::setupRootItemSize()
|
||||
formEditorWidget()->setRootItemRect(rootRect);
|
||||
formEditorWidget()->centerScene();
|
||||
|
||||
auto contextImage = rootModelNode().auxiliaryData(contextImageProperty);
|
||||
|
||||
if (contextImage)
|
||||
m_formEditorWidget->setBackgoundImage(contextImage.value().value<QImage>());
|
||||
if (auto contextImage = rootModelNode().auxiliaryData(contextImageProperty))
|
||||
formEditorWidget()->setBackgoundImage(contextImage.value().value<QImage>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -330,24 +330,14 @@ void FormEditorWidget::changeRootItemHeight(const QString &heighText)
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr AuxiliaryDataKeyView formeditorColorProperty{AuxiliaryDataType::Temporary,
|
||||
"formeditorColor"};
|
||||
}
|
||||
|
||||
void FormEditorWidget::changeBackgound(const QColor &color)
|
||||
{
|
||||
if (color.alpha() == 0) {
|
||||
if (color.alpha() == 0)
|
||||
m_graphicsView->activateCheckboardBackground();
|
||||
if (m_formEditorView->rootModelNode().hasAuxiliaryData(formeditorColorProperty)) {
|
||||
m_formEditorView->rootModelNode().setAuxiliaryDataWithoutLock(formeditorColorProperty,
|
||||
{});
|
||||
}
|
||||
} else {
|
||||
else
|
||||
m_graphicsView->activateColoredBackground(color);
|
||||
m_formEditorView->rootModelNode().setAuxiliaryDataWithoutLock(formeditorColorProperty,
|
||||
color);
|
||||
}
|
||||
|
||||
m_formEditorView->rootModelNode().setAuxiliaryDataWithoutLock(formeditorColorProperty, color);
|
||||
}
|
||||
|
||||
void FormEditorWidget::registerActionAsCommand(
|
||||
@@ -408,8 +398,12 @@ void FormEditorWidget::updateActions()
|
||||
m_backgroundAction->setColor(Qt::transparent);
|
||||
}
|
||||
|
||||
if (m_formEditorView->rootModelNode().hasAuxiliaryData(contextImageProperty))
|
||||
if (m_formEditorView->rootModelNode().hasAuxiliaryData(contextImageProperty)) {
|
||||
m_backgroundAction->setColorEnabled(BackgroundAction::ContextImage, true);
|
||||
m_backgroundAction->setColor(BackgroundAction::ContextImage);
|
||||
} else {
|
||||
m_backgroundAction->setColorEnabled(BackgroundAction::ContextImage, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
m_rootWidthAction->clearLineEditText();
|
||||
|
||||
@@ -34,6 +34,12 @@ void Import3dCanvas::updateRenderImage(const QImage &img)
|
||||
update();
|
||||
}
|
||||
|
||||
void Import3dCanvas::displayError(const QString &error)
|
||||
{
|
||||
m_errorMsg = error;
|
||||
update();
|
||||
}
|
||||
|
||||
void Import3dCanvas::paintEvent([[maybe_unused]] QPaintEvent *e)
|
||||
{
|
||||
QWidget::paintEvent(e);
|
||||
@@ -46,6 +52,9 @@ void Import3dCanvas::paintEvent([[maybe_unused]] QPaintEvent *e)
|
||||
} else {
|
||||
painter.drawImage(rect(), m_image, QRect(0, 0, m_image.width(), m_image.height()));
|
||||
}
|
||||
|
||||
if (!m_errorMsg.isEmpty())
|
||||
painter.drawText(QRect(0, 0, width(), height()), Qt::AlignHCenter | Qt::AlignVCenter, m_errorMsg);
|
||||
}
|
||||
|
||||
void Import3dCanvas::resizeEvent(QResizeEvent *)
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
Import3dCanvas(QWidget *parent);
|
||||
|
||||
void updateRenderImage(const QImage &img);
|
||||
void displayError(const QString &error);
|
||||
|
||||
signals:
|
||||
void requestImageUpdate();
|
||||
@@ -32,6 +33,7 @@ protected:
|
||||
private:
|
||||
QImage m_image;
|
||||
QPointF m_dragPos;
|
||||
QString m_errorMsg;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -16,6 +16,11 @@ Import3dConnectionManager::Import3dConnectionManager()
|
||||
connections().emplace_back("Import 3D", "import3dmode");
|
||||
}
|
||||
|
||||
void Import3dConnectionManager::setPreviewIconCallback(IconCallback callback)
|
||||
{
|
||||
m_previewIconCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void Import3dConnectionManager::setPreviewImageCallback(ImageCallback callback)
|
||||
{
|
||||
m_previewImageCallback = std::move(callback);
|
||||
@@ -29,6 +34,15 @@ void Import3dConnectionManager::dispatchCommand(const QVariant &command,
|
||||
if (command.typeId() == commandType) {
|
||||
auto cmd = command.value<PuppetToCreatorCommand>();
|
||||
switch (cmd.type()) {
|
||||
case PuppetToCreatorCommand::Import3DPreviewIcon: {
|
||||
const QVariantList data = cmd.data().toList();
|
||||
const QString assetName = data[0].toString();
|
||||
ImageContainer container = qvariant_cast<ImageContainer>(data[1]);
|
||||
QImage image = container.image();
|
||||
if (!image.isNull())
|
||||
m_previewIconCallback(assetName, image);
|
||||
break;
|
||||
}
|
||||
case PuppetToCreatorCommand::Import3DPreviewImage: {
|
||||
ImageContainer container = qvariant_cast<ImageContainer>(cmd.data());
|
||||
QImage image = container.image();
|
||||
|
||||
@@ -12,16 +12,19 @@ namespace QmlDesigner {
|
||||
class Import3dConnectionManager : public InteractiveConnectionManager
|
||||
{
|
||||
public:
|
||||
using IconCallback = std::function<void(const QString &, const QImage &)>;
|
||||
using ImageCallback = std::function<void(const QImage &)>;
|
||||
|
||||
Import3dConnectionManager();
|
||||
|
||||
void setPreviewIconCallback(IconCallback callback);
|
||||
void setPreviewImageCallback(ImageCallback callback);
|
||||
|
||||
protected:
|
||||
void dispatchCommand(const QVariant &command, Connection &connection) override;
|
||||
|
||||
private:
|
||||
IconCallback m_previewIconCallback;
|
||||
ImageCallback m_previewImageCallback;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <designermcumanager.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <qmldesignerbase/qmldesignerbaseplugin.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QVariant>
|
||||
#include <QMetaProperty>
|
||||
@@ -73,6 +75,9 @@ void ItemLibraryAddImportModel::update(const Imports &possibleImports)
|
||||
const DesignerMcuManager &mcuManager = DesignerMcuManager::instance();
|
||||
const bool isQtForMCUs = mcuManager.isMCUProject();
|
||||
Imports filteredImports;
|
||||
|
||||
const bool isLiteDesigner = QmlDesigner::QmlDesignerBasePlugin::isLiteModeEnabled();
|
||||
|
||||
if (isQtForMCUs) {
|
||||
const QStringList mcuAllowedList = mcuManager.allowedImports();
|
||||
const QStringList mcuBannedList = mcuManager.bannedImports();
|
||||
@@ -82,6 +87,11 @@ void ItemLibraryAddImportModel::update(const Imports &possibleImports)
|
||||
|| !import.url().startsWith("Qt"))
|
||||
&& !mcuBannedList.contains(import.url());
|
||||
});
|
||||
} else if (isLiteDesigner) {
|
||||
const QStringList liteAllowedList = {"QtQuick", "QtQuick.Layouts", "QtQuick.Controls"};
|
||||
filteredImports = Utils::filtered(possibleImports, [&](const Import &import) {
|
||||
return (liteAllowedList.contains(import.url()) || !import.url().startsWith("Qt"));
|
||||
});
|
||||
} else {
|
||||
filteredImports = possibleImports;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#include "import3dcanvas.h"
|
||||
#include "import3dconnectionmanager.h"
|
||||
|
||||
#include <designeractionmanager.h>
|
||||
#include <designericons.h>
|
||||
#include <model.h>
|
||||
#include <model/modelutils.h>
|
||||
#include <modelutils.h>
|
||||
#include <nodeinstanceview.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
@@ -18,6 +20,7 @@
|
||||
|
||||
#include <theme.h>
|
||||
#include <utils/outputformatter.h>
|
||||
#include <utils/stylehelper.h>
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
@@ -25,7 +28,9 @@
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QFontMetrics>
|
||||
#include <QDir>
|
||||
#include <QLocale>
|
||||
#include <QLoggingCategory>
|
||||
#include <QTimer>
|
||||
#include <QJsonArray>
|
||||
@@ -63,6 +68,17 @@ void addFormattedMessage(Utils::OutputFormatter *formatter,
|
||||
formatter->plainTextEdit()->verticalScrollBar()->maximum());
|
||||
}
|
||||
|
||||
QIcon iconFromIconFont(Theme::Icon iconType, const QColor &color)
|
||||
{
|
||||
const QString unicode = Theme::getIconUnicode(iconType);
|
||||
const QString fontName = "qtds_propertyIconFont.ttf";
|
||||
|
||||
const auto helper = Utils::StyleHelper::IconFontHelper(
|
||||
unicode, color, QSize(28, 28), QIcon::Normal);
|
||||
|
||||
return Utils::StyleHelper::getIconFromIconFont(fontName, {helper});
|
||||
}
|
||||
|
||||
const int rowHeight = 32;
|
||||
const int checkBoxColWidth = 18;
|
||||
const int labelMinWidth = 130;
|
||||
@@ -88,6 +104,11 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
||||
setModal(true);
|
||||
ui->setupUi(this);
|
||||
|
||||
m_selectedRemoveIcon = iconFromIconFont(Theme::Icon::delete_small,
|
||||
Theme::getColor(Theme::IconsBaseColor));
|
||||
m_unselectedRemoveIcon = iconFromIconFont(Theme::Icon::delete_small,
|
||||
Theme::getColor(Theme::IconsDisabledColor));
|
||||
|
||||
m_outputFormatter = new Utils::OutputFormatter;
|
||||
m_outputFormatter->setPlainTextEdit(ui->plainTextEdit);
|
||||
|
||||
@@ -239,20 +260,18 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
||||
|
||||
connect(ui->advancedSettingsButton, &QPushButton::clicked,
|
||||
this, &ItemLibraryAssetImportDialog::toggleAdvanced);
|
||||
connect(ui->importList, &QListWidget::currentItemChanged,
|
||||
this, &ItemLibraryAssetImportDialog::onCurrentItemChanged);
|
||||
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::updateUi);
|
||||
|
||||
if (m_quick3DFiles.size() != 1) {
|
||||
addInfo(tr("Select import options and press \"Import\" to import the following files:"));
|
||||
} else {
|
||||
addInfo(tr("Importing:"));
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
|
||||
}
|
||||
addInfo(tr("Importing:"));
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
|
||||
|
||||
for (const auto &file : std::as_const(m_quick3DFiles))
|
||||
addInfo(file);
|
||||
|
||||
updateImportButtonState();
|
||||
m_updatingControlStates = false;
|
||||
}
|
||||
|
||||
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
|
||||
@@ -385,6 +404,15 @@ void ItemLibraryAssetImportDialog::updateImport(AbstractView *view,
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if ((event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete)
|
||||
&& ui->importList->currentItem()) {
|
||||
onRemoveAsset(assetNameForListItem(ui->importList->currentItem()));
|
||||
}
|
||||
return QDialog::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex,
|
||||
const QJsonObject &groups)
|
||||
{
|
||||
@@ -501,7 +529,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||
QJsonValue value(optCheck->isChecked());
|
||||
optObj.insert("value", value);
|
||||
m_importOptions[optionsIndex].insert(optKey, optObj);
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
});
|
||||
} else {
|
||||
// Simple options also exist in advanced, so don't connect simple controls directly
|
||||
@@ -512,13 +540,13 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||
QObject::connect(optCheck, &QCheckBox::toggled, this, [this, optCheck, advCheck]() {
|
||||
if (advCheck->isChecked() != optCheck->isChecked()) {
|
||||
advCheck->setChecked(optCheck->isChecked());
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
}
|
||||
});
|
||||
QObject::connect(advCheck, &QCheckBox::toggled, this, [this, optCheck, advCheck]() {
|
||||
if (advCheck->isChecked() != optCheck->isChecked()) {
|
||||
optCheck->setChecked(advCheck->isChecked());
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -555,7 +583,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||
QJsonValue value(optSpin->value());
|
||||
optObj.insert("value", value);
|
||||
m_importOptions[optionsIndex].insert(optKey, optObj);
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
});
|
||||
} else {
|
||||
auto *advSpin = qobject_cast<QDoubleSpinBox *>(
|
||||
@@ -566,14 +594,14 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||
this, [this, optSpin, advSpin] {
|
||||
if (advSpin->value() != optSpin->value()) {
|
||||
advSpin->setValue(optSpin->value());
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
}
|
||||
});
|
||||
QObject::connect(advSpin, &QDoubleSpinBox::valueChanged,
|
||||
this, [this, optSpin, advSpin] {
|
||||
if (advSpin->value() != optSpin->value()) {
|
||||
optSpin->setValue(advSpin->value());
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -830,6 +858,15 @@ void ItemLibraryAssetImportDialog::updateUi()
|
||||
}
|
||||
}
|
||||
|
||||
QString ItemLibraryAssetImportDialog::assetNameForListItem(QListWidgetItem *item)
|
||||
{
|
||||
for (const ImportData &data : std::as_const(m_importData)) {
|
||||
if (data.listItem == item)
|
||||
return data.previewData.name;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ItemLibraryAssetImportDialog::isSimpleGroup(const QString &id)
|
||||
{
|
||||
static QStringList simpleGroups {
|
||||
@@ -859,6 +896,15 @@ bool ItemLibraryAssetImportDialog::isHiddenOption(const QString &id)
|
||||
return hiddenOptions.contains(id);
|
||||
}
|
||||
|
||||
bool ItemLibraryAssetImportDialog::optionsChanged()
|
||||
{
|
||||
for (const ImportData &data : std::as_const(m_importData)) {
|
||||
if (data.previewData.renderedOptions != data.previewData.currentOptions)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::startPreview()
|
||||
{
|
||||
cleanupPreviewPuppet();
|
||||
@@ -876,8 +922,9 @@ Rectangle {
|
||||
|
||||
property alias sceneNode: sceneNode
|
||||
property alias view3d: view3d
|
||||
property alias iconView3d: iconView3d
|
||||
property string extents
|
||||
property string sceneModelName: "%3"
|
||||
property string sceneModelName
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 1.0; color: "#222222" }
|
||||
@@ -890,30 +937,46 @@ Rectangle {
|
||||
camera: viewCamera
|
||||
|
||||
environment: SceneEnvironment {
|
||||
id: sceneEnvironment
|
||||
lightProbe: probeTexture
|
||||
antialiasingMode: SceneEnvironment.MSAA
|
||||
antialiasingQuality: SceneEnvironment.VeryHigh
|
||||
}
|
||||
|
||||
PerspectiveCamera {
|
||||
id: viewCamera
|
||||
x: 600
|
||||
y: 600
|
||||
z: 600
|
||||
eulerRotation.x: -45
|
||||
eulerRotation.y: -45
|
||||
clipFar: 100000
|
||||
clipNear: 10
|
||||
}
|
||||
|
||||
DirectionalLight {
|
||||
rotation: viewCamera.rotation
|
||||
}
|
||||
|
||||
Node {
|
||||
id: sceneNode
|
||||
PerspectiveCamera {
|
||||
id: viewCamera
|
||||
x: 600
|
||||
y: 600
|
||||
z: 600
|
||||
eulerRotation.x: -45
|
||||
eulerRotation.y: -45
|
||||
clipFar: 100000
|
||||
clipNear: 10
|
||||
}
|
||||
|
||||
DirectionalLight {
|
||||
rotation: viewCamera.rotation
|
||||
}
|
||||
|
||||
Texture {
|
||||
id: probeTexture
|
||||
source: "qrc:/qtquickplugin/mockfiles/images/preview_studio.hdr"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
View3D {
|
||||
id: iconView3d
|
||||
importScene: sceneNode
|
||||
camera: viewCamera
|
||||
environment: sceneEnvironment
|
||||
visible: false
|
||||
width: 48
|
||||
height: 48
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
@@ -925,7 +988,7 @@ Rectangle {
|
||||
)";
|
||||
|
||||
QSize size = canvas()->size();
|
||||
previewQml = previewQml.arg(size.width()).arg(size.height()).arg(m_previewCompName);
|
||||
previewQml = previewQml.arg(size.width()).arg(size.height());
|
||||
|
||||
m_previewFile.writeFileContents(previewQml.toUtf8());
|
||||
|
||||
@@ -957,17 +1020,29 @@ Rectangle {
|
||||
return;
|
||||
}
|
||||
|
||||
m_nodeInstanceView->setTarget(m_view->nodeInstanceView()->target());
|
||||
m_nodeInstanceView->setTarget(ProjectExplorer::ProjectManager::startupTarget());
|
||||
|
||||
auto previewIconCallback = [this](const QString &assetName, const QImage &image) {
|
||||
if (!m_importData.contains(assetName)) {
|
||||
addWarning(tr("Preview icon generated for non-existent asset: %1").arg(assetName));
|
||||
return;
|
||||
}
|
||||
if (m_importData[assetName].iconLabel)
|
||||
m_importData[assetName].iconLabel->setPixmap(QPixmap::fromImage(image));
|
||||
};
|
||||
|
||||
auto previewImageCallback = [this](const QImage &image) {
|
||||
canvas()->updateRenderImage(image);
|
||||
};
|
||||
|
||||
auto crashCallback = [&] {
|
||||
addWarning("Preview process crashed.");
|
||||
cleanupPreviewPuppet();
|
||||
const QString errorMsg(tr("Preview generation process crashed."));
|
||||
addWarning(errorMsg);
|
||||
canvas()->displayError(errorMsg);
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::cleanupPreviewPuppet);
|
||||
};
|
||||
|
||||
m_connectionManager->setPreviewIconCallback(std::move(previewIconCallback));
|
||||
m_connectionManager->setPreviewImageCallback(std::move(previewImageCallback));
|
||||
m_nodeInstanceView->setCrashCallback(std::move(crashCallback));
|
||||
|
||||
@@ -985,8 +1060,10 @@ void ItemLibraryAssetImportDialog::cleanupPreviewPuppet()
|
||||
if (m_nodeInstanceView)
|
||||
m_nodeInstanceView->setCrashCallback({});
|
||||
|
||||
if (m_connectionManager)
|
||||
if (m_connectionManager) {
|
||||
m_connectionManager->setPreviewIconCallback({});
|
||||
m_connectionManager->setPreviewImageCallback({});
|
||||
}
|
||||
|
||||
delete m_rewriterView;
|
||||
delete m_nodeInstanceView;
|
||||
@@ -998,6 +1075,31 @@ Import3dCanvas *ItemLibraryAssetImportDialog::canvas()
|
||||
return ui->import3dcanvas;
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::resetOptionControls()
|
||||
{
|
||||
const QString currentName = assetNameForListItem(ui->importList->currentItem());
|
||||
if (!m_importData.contains(currentName))
|
||||
return;
|
||||
|
||||
m_updatingControlStates = true;
|
||||
|
||||
const ImportData &data = m_importData[currentName];
|
||||
const QJsonObject options = data.previewData.currentOptions;
|
||||
const QStringList optKeys = options.keys();
|
||||
for (const QString &optKey : optKeys) {
|
||||
QWidget *w = m_labelToControlWidgetMaps[data.previewData.optionsIndex].value(optKey);
|
||||
const QJsonObject optObj = options.value(optKey).toObject();
|
||||
const QJsonValue optValue = optObj.value("value");
|
||||
if (auto *cb = qobject_cast<QCheckBox *>(w))
|
||||
cb->setChecked(optValue.toBool());
|
||||
else if (auto *spin = qobject_cast<QDoubleSpinBox *>(w))
|
||||
spin->setValue(optValue.toDouble());
|
||||
}
|
||||
|
||||
m_updatingControlStates = false;
|
||||
updatePreviewOptions();
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
m_dialogHeight = event->size().height();
|
||||
@@ -1010,9 +1112,20 @@ void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
|
||||
ui->closeButton->setText(importing ? tr("Cancel") : tr("Close"));
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::updateImportButtonState()
|
||||
void ItemLibraryAssetImportDialog::updatePreviewOptions()
|
||||
{
|
||||
ui->importButton->setText(m_previewOptions == m_importOptions ? tr("Accept") : tr("Import"));
|
||||
if (m_updatingControlStates)
|
||||
return;
|
||||
|
||||
if (ui->importList->currentRow() >= 0) {
|
||||
const QString assetName = assetNameForListItem(ui->importList->currentItem());
|
||||
if (m_importData.contains(assetName)) {
|
||||
ImportData &data = m_importData[assetName];
|
||||
data.previewData.currentOptions = m_importOptions[data.previewData.optionsIndex];
|
||||
}
|
||||
}
|
||||
|
||||
ui->importButton->setText(optionsChanged() ? tr("Import") : tr("Accept"));
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::addError(const QString &error, const QString &srcPath)
|
||||
@@ -1035,19 +1148,29 @@ void ItemLibraryAssetImportDialog::addInfo(const QString &info, const QString &s
|
||||
void ItemLibraryAssetImportDialog::onImport()
|
||||
{
|
||||
ui->importButton->setEnabled(false);
|
||||
ui->tabWidget->setEnabled(false);
|
||||
ui->importList->setEnabled(false);
|
||||
|
||||
if (!m_previewCompName.isEmpty() && m_previewOptions == m_importOptions) {
|
||||
if (!m_importData.isEmpty() && !optionsChanged()) {
|
||||
cleanupPreviewPuppet();
|
||||
m_importer.finalizeQuick3DImport();
|
||||
return;
|
||||
}
|
||||
|
||||
const QString assetName = assetNameForListItem(ui->importList->currentItem());
|
||||
const ImportData &data = m_importData.value(assetName);
|
||||
|
||||
setCloseButtonState(true);
|
||||
ui->progressBar->setValue(0);
|
||||
|
||||
if (!m_quick3DFiles.isEmpty()) {
|
||||
if (!m_previewCompName.isEmpty()) {
|
||||
m_importer.reImportQuick3D(m_previewCompName, m_importOptions);
|
||||
if (!m_importData.isEmpty()) {
|
||||
QHash<QString , QJsonObject> importOptions;
|
||||
for (const ImportData &data : std::as_const(m_importData)) {
|
||||
if (data.previewData.renderedOptions != data.previewData.currentOptions)
|
||||
importOptions.insert(data.previewData.name, data.previewData.currentOptions);
|
||||
}
|
||||
m_importer.reImportQuick3D(importOptions);
|
||||
} else {
|
||||
m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
|
||||
m_importOptions, m_extToImportOptionsMap,
|
||||
@@ -1066,19 +1189,118 @@ void ItemLibraryAssetImportDialog::setImportProgress(int value, const QString &t
|
||||
ui->progressBar->setValue(value);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onImportReadyForPreview(const QString &path, const QString &compName)
|
||||
void ItemLibraryAssetImportDialog::onImportReadyForPreview(
|
||||
const QString &path, const QList<ItemLibraryAssetImporter::PreviewData> &previewData)
|
||||
{
|
||||
addInfo(tr("Import is ready for preview."));
|
||||
if (m_previewCompName.isEmpty())
|
||||
addInfo(tr("Click \"Accept\" to finish the import or adjust options and click \"Import\" to import again."));
|
||||
if (previewData.isEmpty()) {
|
||||
m_importer.cancelImport();
|
||||
return;
|
||||
}
|
||||
|
||||
m_previewFile = Utils::FilePath::fromString(path).pathAppended(m_importer.previewFileName());
|
||||
m_previewCompName = compName;
|
||||
m_previewOptions = m_importOptions;
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::startPreview);
|
||||
QPixmap placeHolder = QPixmap(":/navigator/icon/tooltip_placeholder.png").scaled(48, 48);
|
||||
|
||||
int maxNameLen = 150;
|
||||
// Used to initially layout infolabel with sufficient height
|
||||
const QString tallStr = "Wj\nWj\nWj";
|
||||
|
||||
QStringList assetNames;
|
||||
for (const ItemLibraryAssetImporter::PreviewData &data : previewData) {
|
||||
const QString assetName = data.name;
|
||||
assetNames.append(assetName);
|
||||
if (!m_importData.contains(assetName)) {
|
||||
ImportData impData;
|
||||
impData.previewData = data;
|
||||
auto lwi = new QListWidgetItem();
|
||||
impData.listItem = lwi;
|
||||
auto w = new QWidget(ui->importList);
|
||||
w->setToolTip(assetName);
|
||||
auto layout = new QHBoxLayout(w);
|
||||
auto iconLabel = new QLabel(w);
|
||||
iconLabel->setPixmap(placeHolder);
|
||||
impData.iconLabel = iconLabel;
|
||||
layout->addWidget(iconLabel);
|
||||
auto infoLabel = new QLabel(w);
|
||||
impData.infoLabel = infoLabel;
|
||||
infoLabel->setText(tallStr);
|
||||
infoLabel->setFixedWidth(maxNameLen);
|
||||
layout->addWidget(infoLabel);
|
||||
layout->addStretch(1);
|
||||
auto removeButton = new QPushButton(m_unselectedRemoveIcon, {}, w);
|
||||
removeButton->setFlat(true);
|
||||
impData.removeButton = removeButton;
|
||||
layout->addWidget(removeButton, 0, Qt::AlignRight);
|
||||
layout->setSizeConstraint(QLayout::SetNoConstraint);
|
||||
w->setLayout(layout);
|
||||
w->resize(w->height(), ui->importList->width());
|
||||
lwi->setSizeHint(w->sizeHint());
|
||||
ui->importList->addItem(lwi);
|
||||
ui->importList->setItemWidget(lwi, w);
|
||||
m_importData[assetName] = impData;
|
||||
QObject::connect(removeButton, &QPushButton::clicked, this, [this, assetName]() {
|
||||
onRemoveAsset(assetName);
|
||||
});
|
||||
} else {
|
||||
m_importData[assetName].previewData = data;
|
||||
}
|
||||
|
||||
if (!m_importData.contains(assetName))
|
||||
return;
|
||||
|
||||
const ImportData &impData = m_importData[assetName];
|
||||
|
||||
if (QLabel *l = impData.infoLabel) {
|
||||
QFontMetrics fm = l->fontMetrics();
|
||||
QString truncNameBase = assetName;
|
||||
QString truncName = assetName;
|
||||
int truncNameLen = fm.boundingRect(truncName).width();
|
||||
while (!truncNameBase.isEmpty() && truncNameLen > maxNameLen) {
|
||||
truncNameBase.chop(1);
|
||||
truncName = truncNameBase + "...";
|
||||
truncNameLen = fm.boundingRect(truncName).width();
|
||||
}
|
||||
|
||||
QString s;
|
||||
s += truncName + '\n';
|
||||
s += tr("Object Type: %1\n").arg(data.type);
|
||||
s += tr("Import Size: %1").arg(QLocale::system().formattedDataSize(
|
||||
data.size, 2, QLocale::DataSizeTraditionalFormat));
|
||||
l->setText(s);
|
||||
}
|
||||
|
||||
addInfo(tr("Import ready for preview: %1").arg(assetName));
|
||||
}
|
||||
|
||||
if (m_firstImport) {
|
||||
addInfo(tr("Click \"Accept\" to finish the import or adjust options and click \"Import\" to import again."));
|
||||
m_firstImport = false;
|
||||
}
|
||||
|
||||
if (m_previewFile.isEmpty()) {
|
||||
m_previewFile = Utils::FilePath::fromString(path).pathAppended(m_importer.previewFileName());
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::startPreview);
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, [this, assetNames]() {
|
||||
if (!m_nodeInstanceView)
|
||||
return;
|
||||
for (const QString &assetName : std::as_const(assetNames)) {
|
||||
const ImportData &data = m_importData.value(assetName);
|
||||
if (!data.previewData.name.isEmpty()) {
|
||||
QVariantHash msgData;
|
||||
msgData.insert("name", data.previewData.name);
|
||||
msgData.insert("qmlName", data.previewData.qmlName);
|
||||
msgData.insert("folder", data.previewData.folderName);
|
||||
m_nodeInstanceView->view3DAction(View3DActionType::Import3dAddPreviewModel, msgData);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui->importButton->setEnabled(true);
|
||||
updateImportButtonState();
|
||||
ui->tabWidget->setEnabled(true);
|
||||
ui->importList->setEnabled(true);
|
||||
updatePreviewOptions();
|
||||
if (ui->importList->currentRow() < 0)
|
||||
ui->importList->setCurrentRow(0);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onRequestImageUpdate()
|
||||
@@ -1119,6 +1341,37 @@ void ItemLibraryAssetImportDialog::onImportFinished()
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onCurrentItemChanged(QListWidgetItem *current, QListWidgetItem *)
|
||||
{
|
||||
if (!current)
|
||||
return;
|
||||
|
||||
for (const ImportData &data : std::as_const(m_importData)) {
|
||||
if (data.removeButton) {
|
||||
if (current == data.listItem)
|
||||
data.removeButton->setIcon(m_selectedRemoveIcon);
|
||||
else
|
||||
data.removeButton->setIcon(m_unselectedRemoveIcon);
|
||||
}
|
||||
}
|
||||
const QString assetName = assetNameForListItem(ui->importList->currentItem());
|
||||
resetOptionControls();
|
||||
|
||||
const ImportData data = m_importData.value(assetName);
|
||||
for (int i = 0; i < ui->tabWidget->count(); ++i)
|
||||
ui->tabWidget->widget(i)->setVisible(i == data.previewData.optionsIndex);
|
||||
ui->tabWidget->setCurrentIndex(data.previewData.optionsIndex);
|
||||
|
||||
QTimer::singleShot(0, this, [this, assetName]() {
|
||||
if (!m_nodeInstanceView)
|
||||
return;
|
||||
if (m_importData.contains(assetName)) {
|
||||
m_nodeInstanceView->view3DAction(View3DActionType::Import3dSetCurrentPreviewModel,
|
||||
assetName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onClose()
|
||||
{
|
||||
ui->importButton->setEnabled(false);
|
||||
@@ -1164,4 +1417,20 @@ void ItemLibraryAssetImportDialog::toggleAdvanced()
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onRemoveAsset(const QString &assetName)
|
||||
{
|
||||
m_importer.removeAssetFromImport(assetName);
|
||||
if (m_importData.contains(assetName)) {
|
||||
ImportData data = m_importData.take(assetName);
|
||||
addInfo(tr("Removed %1 from the import.").arg(assetName));
|
||||
if (data.listItem) {
|
||||
ui->importList->removeItemWidget(data.listItem);
|
||||
delete data.listItem;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_importData.isEmpty())
|
||||
onClose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user