forked from qt-creator/qt-creator
QmlDesigner: Add tooltips to UrlChooser
* Add tooltips with thumbnails to UrlChooser enable preview of image formats and meshes * Add property editor image provider which makes use of the image cache * Add mesh image cache collector in order to create thumbnails for meshes and built-in primitves * Fix typo in explicit image cache image provider * Add return value in time stamp provider if provided file does not exist Change-Id: I2290d2ace87ddd90e9899e343f2ad1ecd2993fdf Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
committed by
Henning Gründl
parent
1c6fa83648
commit
bd51b4fdc2
@@ -44,6 +44,9 @@ Row {
|
||||
// by QtQuick3D to add built-in primitives to the model.
|
||||
property var defaultItems
|
||||
|
||||
// Current item
|
||||
property string absoluteFilePath: ""
|
||||
|
||||
FileResourcesModel {
|
||||
id: fileModel
|
||||
modelNodeBackendProperty: modelNodeBackend
|
||||
@@ -74,16 +77,64 @@ Row {
|
||||
visible: comboBox.hover && toolTip.text !== ""
|
||||
text: root.backendValue.valueToString
|
||||
delay: StudioTheme.Values.toolTipDelay
|
||||
height: StudioTheme.Values.toolTipHeight
|
||||
|
||||
background: Rectangle {
|
||||
color: StudioTheme.Values.themeToolTipBackground
|
||||
border.color: StudioTheme.Values.themeToolTipOutline
|
||||
border.width: StudioTheme.Values.border
|
||||
}
|
||||
contentItem: Text {
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: 10
|
||||
|
||||
Item {
|
||||
visible: thumbnail.status === Image.Ready
|
||||
Layout.preferredWidth: 100
|
||||
Layout.preferredHeight: 100
|
||||
|
||||
Image {
|
||||
id: checker
|
||||
visible: !root.isMesh(root.absoluteFilePath)
|
||||
anchors.fill: parent
|
||||
fillMode: Image.Tile
|
||||
source: "images/checkers.png"
|
||||
}
|
||||
|
||||
Image {
|
||||
id: thumbnail
|
||||
asynchronous: true
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: {
|
||||
if (root.isBuiltInPrimitive(root.absoluteFilePath))
|
||||
return "image://qmldesigner_thumbnails/"
|
||||
+ root.absoluteFilePath.substring(1, root.absoluteFilePath.length)
|
||||
+ ".builtin"
|
||||
|
||||
if (fileModel.isLocal(root.absoluteFilePath))
|
||||
return "image://qmldesigner_thumbnails/" + root.absoluteFilePath
|
||||
|
||||
return root.absoluteFilePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Text {
|
||||
text: root.fileName(toolTip.text)
|
||||
color: StudioTheme.Values.themeToolTipText
|
||||
text: toolTip.text
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font: toolTip.font
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: root.isBuiltInPrimitive(toolTip.text) ? qsTr("Built-in primitive")
|
||||
: toolTip.text
|
||||
font: toolTip.font
|
||||
color: StudioTheme.Values.themeToolTipText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,16 +206,62 @@ Row {
|
||||
visible: delegateRoot.hovered
|
||||
text: delegateRoot.relativeFilePath
|
||||
delay: StudioTheme.Values.toolTipDelay
|
||||
height: StudioTheme.Values.toolTipHeight
|
||||
|
||||
background: Rectangle {
|
||||
color: StudioTheme.Values.themeToolTipBackground
|
||||
border.color: StudioTheme.Values.themeToolTipOutline
|
||||
border.width: StudioTheme.Values.border
|
||||
}
|
||||
contentItem: Text {
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: 10
|
||||
|
||||
Item {
|
||||
visible: delegateThumbnail.status === Image.Ready
|
||||
Layout.preferredWidth: 100
|
||||
Layout.preferredHeight: 100
|
||||
|
||||
Image {
|
||||
id: delegateChecker
|
||||
visible: !root.isMesh(delegateRoot.absoluteFilePath)
|
||||
anchors.fill: parent
|
||||
fillMode: Image.Tile
|
||||
source: "images/checkers.png"
|
||||
}
|
||||
|
||||
Image {
|
||||
id: delegateThumbnail
|
||||
asynchronous: true
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: {
|
||||
if (root.isBuiltInPrimitive(delegateRoot.name))
|
||||
return "image://qmldesigner_thumbnails/"
|
||||
+ delegateRoot.name.substring(1, delegateRoot.name.length)
|
||||
+ ".builtin"
|
||||
|
||||
return "image://qmldesigner_thumbnails/" + delegateRoot.absoluteFilePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Text {
|
||||
text: delegateRoot.name
|
||||
color: StudioTheme.Values.themeToolTipText
|
||||
text: itemToolTip.text
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font: delegateToolTip.font
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: root.isBuiltInPrimitive(delegateToolTip.text)
|
||||
? qsTr("Built-in primitive")
|
||||
: delegateToolTip.text
|
||||
font: delegateToolTip.font
|
||||
color: StudioTheme.Values.themeToolTipText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,6 +332,10 @@ Row {
|
||||
inputValue = comboBox.items.get(index).model.relativeFilePath
|
||||
|
||||
root.backendValue.value = inputValue
|
||||
|
||||
if (!root.backendValue.isBound)
|
||||
root.absoluteFilePath = fileModel.resolve(root.backendValue.value)
|
||||
|
||||
comboBox.dirty = false
|
||||
}
|
||||
|
||||
@@ -259,6 +360,9 @@ Row {
|
||||
if (root.backendValue.value !== inputValue)
|
||||
root.backendValue.value = inputValue
|
||||
|
||||
if (!root.backendValue.isBound)
|
||||
root.absoluteFilePath = fileModel.resolve(root.backendValue.value)
|
||||
|
||||
comboBox.dirty = false
|
||||
}
|
||||
|
||||
@@ -275,6 +379,23 @@ Row {
|
||||
}
|
||||
}
|
||||
|
||||
function isBuiltInPrimitive(value) {
|
||||
return value.startsWith('#')
|
||||
}
|
||||
|
||||
function isMesh(value) {
|
||||
return root.isBuiltInPrimitive(value)
|
||||
|| root.hasFileExtension(root.fileName(value), "mesh")
|
||||
}
|
||||
|
||||
function hasFileExtension(fileName, extension) {
|
||||
return fileName.split('.').pop() === extension
|
||||
}
|
||||
|
||||
function fileName(filePath) {
|
||||
return filePath.substr(filePath.lastIndexOf('/') + 1)
|
||||
}
|
||||
|
||||
function createModel() {
|
||||
// Build the combobox model
|
||||
comboBox.listModel.clear()
|
||||
@@ -322,6 +443,9 @@ Row {
|
||||
Component.onCompleted: {
|
||||
root.createModel()
|
||||
comboBox.updateTextValue()
|
||||
|
||||
if (!root.backendValue.isBound)
|
||||
root.absoluteFilePath = fileModel.resolve(root.backendValue.value)
|
||||
}
|
||||
|
||||
function indexOf(model, criteria) {
|
||||
@@ -340,7 +464,7 @@ Row {
|
||||
if (comboBox.popup.opened && !root.backendValue.isBound) {
|
||||
var index = root.indexOf(comboBox.items,
|
||||
function(item) {
|
||||
return item.fullPath === root.backendValue.value
|
||||
return item.relativeFilePath === root.backendValue.value
|
||||
})
|
||||
|
||||
if (index !== -1) {
|
||||
@@ -359,8 +483,10 @@ Row {
|
||||
iconColor: root.textColor
|
||||
onClicked: {
|
||||
fileModel.openFileDialog()
|
||||
if (fileModel.fileName !== "")
|
||||
if (fileModel.fileName !== "") {
|
||||
root.backendValue.value = fileModel.fileName
|
||||
root.absoluteFilePath = fileModel.resolve(root.backendValue.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,6 +302,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
gradientpresetitem.cpp gradientpresetitem.h
|
||||
gradientpresetlistmodel.cpp gradientpresetlistmodel.h
|
||||
propertyeditorcontextobject.cpp propertyeditorcontextobject.h
|
||||
propertyeditorimageprovider.cpp propertyeditorimageprovider.h
|
||||
propertyeditorqmlbackend.cpp propertyeditorqmlbackend.h
|
||||
propertyeditortransaction.cpp propertyeditortransaction.h
|
||||
propertyeditorvalue.cpp propertyeditorvalue.h
|
||||
@@ -389,7 +390,8 @@ extend_qtc_plugin(QmlDesigner
|
||||
SOURCES
|
||||
explicitimagecacheimageprovider.cpp
|
||||
explicitimagecacheimageprovider.h
|
||||
|
||||
smallimagecacheprovider.cpp
|
||||
smallimagecacheprovider.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "propertyeditorimageprovider.h"
|
||||
#include "assetslibrarymodel.h"
|
||||
|
||||
#include <hdrimage.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <utils/stylehelper.h>
|
||||
|
||||
#include <QMetaObject>
|
||||
#include <QQuickImageResponse>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QString &id,
|
||||
const QSize &requestedSize)
|
||||
{
|
||||
const QString suffix = "*." + id.split('.').last().toLower();
|
||||
|
||||
if (suffix == "*.mesh")
|
||||
return m_smallImageCacheProvider.requestImageResponse(id, requestedSize);
|
||||
|
||||
if (suffix == "*.builtin")
|
||||
return m_smallImageCacheProvider.requestImageResponse("#" + id.split('.').first(),
|
||||
requestedSize);
|
||||
|
||||
QImage image;
|
||||
auto response = std::make_unique<QmlDesigner::ImageResponse>(image);
|
||||
|
||||
QMetaObject::invokeMethod(
|
||||
response.get(),
|
||||
[response = QPointer<QmlDesigner::ImageResponse>(response.get()), image, suffix, id] {
|
||||
if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix))
|
||||
response->setImage(QImage(Utils::StyleHelper::dpiSpecificImageFile(id)));
|
||||
else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix))
|
||||
response->setImage(HdrImage{id}.image());
|
||||
else
|
||||
response->abort();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
return response.release();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,48 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imagecache/smallimagecacheprovider.h"
|
||||
|
||||
#include <QQuickAsyncImageProvider>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class PropertyEditorImageProvider : public QQuickAsyncImageProvider
|
||||
{
|
||||
public:
|
||||
PropertyEditorImageProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {})
|
||||
: m_smallImageCacheProvider(imageCache, defaultImage)
|
||||
{}
|
||||
|
||||
QQuickImageResponse *requestImageResponse(const QString &id,
|
||||
const QSize &requestedSize) override;
|
||||
|
||||
private:
|
||||
SmallImageCacheProvider m_smallImageCacheProvider;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -95,9 +95,12 @@ static QObject *variantToQObject(const QVariant &value)
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor) :
|
||||
m_view(new Quick2PropertyEditorView), m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor)), m_dummyPropertyEditorValue(new PropertyEditorValue()),
|
||||
m_contextObject(new PropertyEditorContextObject())
|
||||
PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor,
|
||||
AsynchronousImageCache &imageCache)
|
||||
: m_view(new Quick2PropertyEditorView(imageCache))
|
||||
, m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor))
|
||||
, m_dummyPropertyEditorValue(new PropertyEditorValue())
|
||||
, m_contextObject(new PropertyEditorContextObject())
|
||||
{
|
||||
m_view->engine()->setOutputWarningsToStandardError(QmlDesignerPlugin::instance()
|
||||
->settings().value(DesignerSettingsKey::SHOW_PROPERTYEDITOR_WARNINGS).toBool());
|
||||
@@ -115,7 +118,9 @@ PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyE
|
||||
|
||||
PropertyEditorQmlBackend::~PropertyEditorQmlBackend() = default;
|
||||
|
||||
void PropertyEditorQmlBackend::setupPropertyEditorValue(const PropertyName &name, PropertyEditorView *propertyEditor, const QString &type)
|
||||
void PropertyEditorQmlBackend::setupPropertyEditorValue(const PropertyName &name,
|
||||
PropertyEditorView *propertyEditor,
|
||||
const QString &type)
|
||||
{
|
||||
QmlDesigner::PropertyName propertyName(name);
|
||||
propertyName.replace('.', '_');
|
||||
|
||||
@@ -50,7 +50,8 @@ class PropertyEditorQmlBackend
|
||||
|
||||
|
||||
public:
|
||||
PropertyEditorQmlBackend(PropertyEditorView *propertyEditor);
|
||||
PropertyEditorQmlBackend(PropertyEditorView *propertyEditor,
|
||||
class AsynchronousImageCache &imageCache);
|
||||
~PropertyEditorQmlBackend();
|
||||
|
||||
void setup(const QmlObjectNode &fxObjectNode, const QString &stateName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor);
|
||||
|
||||
@@ -69,16 +69,16 @@ static bool propertyIsAttachedLayoutProperty(const PropertyName &propertyName)
|
||||
return propertyName.contains("Layout.");
|
||||
}
|
||||
|
||||
PropertyEditorView::PropertyEditorView(QWidget *parent) :
|
||||
AbstractView(parent),
|
||||
m_parent(parent),
|
||||
m_updateShortcut(nullptr),
|
||||
m_timerId(0),
|
||||
m_stackedWidget(new PropertyEditorWidget(parent)),
|
||||
m_qmlBackEndForCurrentType(nullptr),
|
||||
m_locked(false),
|
||||
m_setupCompleted(false),
|
||||
m_singleShotTimer(new QTimer(this))
|
||||
PropertyEditorView::PropertyEditorView(AsynchronousImageCache &imageCache)
|
||||
: AbstractView()
|
||||
, m_imageCache(imageCache)
|
||||
, m_updateShortcut(nullptr)
|
||||
, m_timerId(0)
|
||||
, m_stackedWidget(new PropertyEditorWidget())
|
||||
, m_qmlBackEndForCurrentType(nullptr)
|
||||
, m_locked(false)
|
||||
, m_setupCompleted(false)
|
||||
, m_singleShotTimer(new QTimer(this))
|
||||
{
|
||||
m_qmlDir = PropertyEditorQmlBackend::propertyEditorResourcesPath();
|
||||
|
||||
@@ -117,7 +117,7 @@ void PropertyEditorView::setupPane(const TypeName &typeName)
|
||||
PropertyEditorQmlBackend *qmlBackend = m_qmlBackendHash.value(qmlFile.toString());
|
||||
|
||||
if (!qmlBackend) {
|
||||
qmlBackend = new PropertyEditorQmlBackend(this);
|
||||
qmlBackend = new PropertyEditorQmlBackend(this, m_imageCache);
|
||||
|
||||
qmlBackend->initialSetup(typeName, qmlSpecificsFile, this);
|
||||
qmlBackend->setSource(qmlFile);
|
||||
@@ -484,7 +484,7 @@ void PropertyEditorView::setupQmlBackend()
|
||||
QString currentStateName = currentState().isBaseState() ? currentState().name() : QStringLiteral("invalid state");
|
||||
|
||||
if (!currentQmlBackend) {
|
||||
currentQmlBackend = new PropertyEditorQmlBackend(this);
|
||||
currentQmlBackend = new PropertyEditorQmlBackend(this, m_imageCache);
|
||||
|
||||
m_stackedWidget->addWidget(currentQmlBackend->widget());
|
||||
m_qmlBackendHash.insert(qmlFile.toString(), currentQmlBackend);
|
||||
|
||||
@@ -51,7 +51,7 @@ class PropertyEditorView: public AbstractView
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PropertyEditorView(QWidget *parent = nullptr);
|
||||
PropertyEditorView(class AsynchronousImageCache &imageCache);
|
||||
~PropertyEditorView() override;
|
||||
|
||||
bool hasWidget() const override;
|
||||
@@ -119,8 +119,8 @@ private: //functions
|
||||
bool noValidSelection() const;
|
||||
|
||||
private: //variables
|
||||
AsynchronousImageCache &m_imageCache;
|
||||
ModelNode m_selectedNode;
|
||||
QWidget *m_parent;
|
||||
QShortcut *m_updateShortcut;
|
||||
int m_timerId;
|
||||
PropertyEditorWidget* m_stackedWidget;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "gradientpresetdefaultlistmodel.h"
|
||||
#include "itemfiltermodel.h"
|
||||
#include "propertyeditorcontextobject.h"
|
||||
#include "propertyeditorimageprovider.h"
|
||||
#include "propertyeditorqmlbackend.h"
|
||||
#include "propertyeditorvalue.h"
|
||||
#include "qmlanchorbindingproxy.h"
|
||||
@@ -45,11 +46,13 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
Quick2PropertyEditorView::Quick2PropertyEditorView(QWidget *parent) :
|
||||
QQuickWidget(parent)
|
||||
Quick2PropertyEditorView::Quick2PropertyEditorView(AsynchronousImageCache &imageCache)
|
||||
: QQuickWidget()
|
||||
{
|
||||
setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||
Theme::setupTheme(engine());
|
||||
engine()->addImageProvider("qmldesigner_thumbnails",
|
||||
new PropertyEditorImageProvider(imageCache));
|
||||
}
|
||||
|
||||
void Quick2PropertyEditorView::registerQmlTypes()
|
||||
|
||||
@@ -35,7 +35,7 @@ class Quick2PropertyEditorView : public QQuickWidget
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Quick2PropertyEditorView(QWidget *parent = nullptr);
|
||||
explicit Quick2PropertyEditorView(class AsynchronousImageCache &imageCache);
|
||||
|
||||
static void registerQmlTypes();
|
||||
};
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
#include <QMetaObject>
|
||||
#include <QQuickImageResponse>
|
||||
|
||||
namespace QmlDesigner {
|
||||
namespace {
|
||||
|
||||
class ImageRespose : public QQuickImageResponse
|
||||
class ImageResponse : public QQuickImageResponse
|
||||
{
|
||||
public:
|
||||
ImageRespose(const QImage &defaultImage)
|
||||
ImageResponse(const QImage &defaultImage)
|
||||
: m_image(defaultImage)
|
||||
{}
|
||||
|
||||
@@ -57,14 +57,18 @@ private:
|
||||
QImage m_image;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const QString &id,
|
||||
const QSize &)
|
||||
{
|
||||
auto response = std::make_unique<ImageRespose>(m_defaultImage);
|
||||
auto response = std::make_unique<::ImageResponse>(m_defaultImage);
|
||||
|
||||
m_cache.requestImage(
|
||||
id,
|
||||
[response = QPointer<ImageRespose>(response.get())](const QImage &image) {
|
||||
[response = QPointer<::ImageResponse>(response.get())](const QImage &image) {
|
||||
QMetaObject::invokeMethod(
|
||||
response,
|
||||
[response, image] {
|
||||
@@ -73,7 +77,7 @@ QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
},
|
||||
[response = QPointer<ImageRespose>(response.get())](ImageCache::AbortReason abortReason) {
|
||||
[response = QPointer<::ImageResponse>(response.get())](ImageCache::AbortReason abortReason) {
|
||||
QMetaObject::invokeMethod(
|
||||
response,
|
||||
[response, abortReason] {
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "meshimagecachecollector.h"
|
||||
#include "imagecacheconnectionmanager.h"
|
||||
|
||||
#include <projectexplorer/target.h>
|
||||
#include <utils/smallstring.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
|
||||
#include <QTemporaryFile>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
MeshImageCacheCollector::MeshImageCacheCollector(
|
||||
ImageCacheConnectionManager &connectionManager,
|
||||
QSize captureImageMinimumSize,
|
||||
QSize captureImageMaximumSize,
|
||||
ImageCacheCollectorNullImageHandling nullImageHandling)
|
||||
: m_imageCacheCollector(connectionManager,
|
||||
captureImageMinimumSize,
|
||||
captureImageMaximumSize,
|
||||
nullImageHandling)
|
||||
{}
|
||||
|
||||
MeshImageCacheCollector::~MeshImageCacheCollector() = default;
|
||||
|
||||
void MeshImageCacheCollector::start(Utils::SmallStringView name,
|
||||
Utils::SmallStringView state,
|
||||
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback)
|
||||
{
|
||||
QTemporaryFile file(QDir::tempPath() + "/mesh-XXXXXX.qml");
|
||||
if (file.open()) {
|
||||
QString qtQuickVersion;
|
||||
QString qtQuick3DVersion;
|
||||
QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit());
|
||||
if (qtVersion && qtVersion->qtVersion() < QtSupport::QtVersionNumber(6, 0, 0)) {
|
||||
qtQuickVersion = "2.15";
|
||||
qtQuick3DVersion = "1.15";
|
||||
}
|
||||
|
||||
QString content{
|
||||
R"(import QtQuick %1
|
||||
import QtQuick3D %2
|
||||
Node {
|
||||
Model {
|
||||
source: "%3"
|
||||
DefaultMaterial { id: defaultMaterial; diffuseColor: "#ff999999" }
|
||||
materials: [ defaultMaterial ]
|
||||
}
|
||||
})"};
|
||||
|
||||
content = content.arg(qtQuickVersion, qtQuick3DVersion, QString(name));
|
||||
|
||||
file.write(content.toUtf8());
|
||||
file.close();
|
||||
}
|
||||
|
||||
Utils::PathString path{file.fileName()};
|
||||
|
||||
m_imageCacheCollector.start(path, state, auxiliaryData, captureCallback, abortCallback);
|
||||
}
|
||||
|
||||
std::pair<QImage, QImage> MeshImageCacheCollector::createImage(Utils::SmallStringView,
|
||||
Utils::SmallStringView,
|
||||
const ImageCache::AuxiliaryData &)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QIcon MeshImageCacheCollector::createIcon(Utils::SmallStringView,
|
||||
Utils::SmallStringView,
|
||||
const ImageCache::AuxiliaryData &)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void MeshImageCacheCollector::setTarget(ProjectExplorer::Target *target)
|
||||
{
|
||||
m_imageCacheCollector.setTarget(target);
|
||||
}
|
||||
|
||||
ProjectExplorer::Target *MeshImageCacheCollector::target() const
|
||||
{
|
||||
return m_imageCacheCollector.target();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,70 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imagecachecollectorinterface.h"
|
||||
#include "imagecachecollector.h"
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Target;
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ImageCacheConnectionManager;
|
||||
|
||||
class MeshImageCacheCollector final : public ImageCacheCollectorInterface
|
||||
{
|
||||
public:
|
||||
MeshImageCacheCollector(ImageCacheConnectionManager &connectionManager,
|
||||
QSize captureImageMinimumSize,
|
||||
QSize captureImageMaximumSize,
|
||||
ImageCacheCollectorNullImageHandling nullImageHandling = {});
|
||||
|
||||
~MeshImageCacheCollector();
|
||||
|
||||
void start(Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView state,
|
||||
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback) override;
|
||||
|
||||
std::pair<QImage, QImage> createImage(Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView state,
|
||||
const ImageCache::AuxiliaryData &auxiliaryData) override;
|
||||
|
||||
QIcon createIcon(Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView state,
|
||||
const ImageCache::AuxiliaryData &auxiliaryData) override;
|
||||
|
||||
void setTarget(ProjectExplorer::Target *target);
|
||||
ProjectExplorer::Target *target() const;
|
||||
|
||||
private:
|
||||
ImageCacheCollector m_imageCacheCollector;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "smallimagecacheprovider.h"
|
||||
|
||||
#include <asynchronousimagecache.h>
|
||||
|
||||
#include <QMetaObject>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
QQuickTextureFactory *ImageResponse::textureFactory() const
|
||||
{
|
||||
return QQuickTextureFactory::textureFactoryForImage(m_image);
|
||||
}
|
||||
|
||||
void ImageResponse::setImage(const QImage &image)
|
||||
{
|
||||
m_image = image;
|
||||
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void ImageResponse::abort()
|
||||
{
|
||||
emit finished();
|
||||
}
|
||||
|
||||
QQuickImageResponse *SmallImageCacheProvider::requestImageResponse(const QString &id, const QSize &)
|
||||
{
|
||||
auto response = std::make_unique<QmlDesigner::ImageResponse>(m_defaultImage);
|
||||
|
||||
m_cache.requestSmallImage(
|
||||
id,
|
||||
[response = QPointer<QmlDesigner::ImageResponse>(response.get())](const QImage &image) {
|
||||
QMetaObject::invokeMethod(
|
||||
response,
|
||||
[response, image] {
|
||||
if (response)
|
||||
response->setImage(image);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
},
|
||||
[response = QPointer<QmlDesigner::ImageResponse>(response.get())](
|
||||
ImageCache::AbortReason abortReason) {
|
||||
QMetaObject::invokeMethod(
|
||||
response,
|
||||
[response, abortReason] {
|
||||
switch (abortReason) {
|
||||
case ImageCache::AbortReason::Failed:
|
||||
if (response)
|
||||
response->abort();
|
||||
break;
|
||||
case ImageCache::AbortReason::Abort:
|
||||
response->cancel();
|
||||
break;
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
});
|
||||
|
||||
return response.release();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,68 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QQuickAsyncImageProvider>
|
||||
#include <QQuickImageResponse>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class AsynchronousImageCache;
|
||||
|
||||
class ImageResponse : public QQuickImageResponse
|
||||
{
|
||||
public:
|
||||
ImageResponse(const QImage &defaultImage)
|
||||
: m_image(defaultImage)
|
||||
{}
|
||||
|
||||
QQuickTextureFactory *textureFactory() const override;
|
||||
|
||||
void setImage(const QImage &image);
|
||||
|
||||
void abort();
|
||||
|
||||
private:
|
||||
QImage m_image;
|
||||
};
|
||||
|
||||
class SmallImageCacheProvider : public QQuickAsyncImageProvider
|
||||
{
|
||||
public:
|
||||
SmallImageCacheProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {})
|
||||
: m_cache{imageCache}
|
||||
, m_defaultImage(defaultImage)
|
||||
{}
|
||||
|
||||
QQuickImageResponse *requestImageResponse(const QString &id,
|
||||
const QSize &requestedSize) override;
|
||||
|
||||
private:
|
||||
AsynchronousImageCache &m_cache;
|
||||
QImage m_defaultImage;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -28,11 +28,17 @@
|
||||
#include <QDateTime>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
Sqlite::TimeStamp TimeStampProvider::timeStamp(Utils::SmallStringView name) const
|
||||
{
|
||||
return QFileInfo{QString{name}}.lastModified().toSecsSinceEpoch();
|
||||
QFileInfo info{QString{name}};
|
||||
if (info.exists())
|
||||
return info.lastModified().toSecsSinceEpoch();
|
||||
|
||||
return {std::numeric_limits<long long>::max()};
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -51,7 +51,8 @@ class ViewManagerData;
|
||||
class QMLDESIGNERCORE_EXPORT ViewManager
|
||||
{
|
||||
public:
|
||||
ViewManager(class AsynchronousImageCache &imageCache);
|
||||
ViewManager(class AsynchronousImageCache &imageCache,
|
||||
class AsynchronousImageCache &meshImageCache);
|
||||
~ViewManager();
|
||||
|
||||
void attachRewriterView();
|
||||
|
||||
@@ -62,8 +62,9 @@ static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg)
|
||||
class ViewManagerData
|
||||
{
|
||||
public:
|
||||
ViewManagerData(AsynchronousImageCache &imageCache)
|
||||
ViewManagerData(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache)
|
||||
: itemLibraryView(imageCache)
|
||||
, propertyEditorView(meshImageCache)
|
||||
{}
|
||||
|
||||
InteractiveConnectionManager connectionManager;
|
||||
@@ -94,8 +95,8 @@ static CrumbleBar *crumbleBar() {
|
||||
return QmlDesignerPlugin::instance()->mainWidget()->crumbleBar();
|
||||
}
|
||||
|
||||
ViewManager::ViewManager(AsynchronousImageCache &imageCache)
|
||||
: d(std::make_unique<ViewManagerData>(imageCache))
|
||||
ViewManager::ViewManager(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache)
|
||||
: d(std::make_unique<ViewManagerData>(imageCache, meshImageCache))
|
||||
{
|
||||
d->formEditorView.setGotoErrorCallback([this](int line, int column) {
|
||||
d->textEditorView.gotoCursorPosition(line, column);
|
||||
|
||||
@@ -123,6 +123,8 @@ function(extend_with_qmldesigner_core target_name)
|
||||
imagecache/imagecachegeneratorinterface.h
|
||||
imagecache/imagecachestorage.h
|
||||
imagecache/imagecachestorageinterface.h
|
||||
imagecache/meshimagecachecollector.cpp
|
||||
imagecache/meshimagecachecollector.h
|
||||
imagecache/synchronousimagecache.cpp
|
||||
imagecache/timestampprovider.cpp
|
||||
imagecache/timestampprovider.h
|
||||
|
||||
@@ -137,7 +137,8 @@ class QmlDesignerPluginPrivate
|
||||
{
|
||||
public:
|
||||
QmlDesignerProjectManager projectManager;
|
||||
ViewManager viewManager{projectManager.asynchronousImageCache()};
|
||||
ViewManager viewManager{projectManager.asynchronousImageCache(),
|
||||
projectManager.asynchronousMeshImageCache()};
|
||||
DocumentManager documentManager;
|
||||
ShortCutManager shortCutManager;
|
||||
SettingsPage settingsPage;
|
||||
|
||||
@@ -442,6 +442,10 @@ Project {
|
||||
"imagecache/imagecachegenerator.h",
|
||||
"imagecache/imagecachestorageinterface.h",
|
||||
"imagecache/imagecachestorage.h",
|
||||
"imagecache/meshimagecachecollector.cpp",
|
||||
"imagecache/meshimagecachecollector.h",
|
||||
"imagecache/smallimagecacheprovider.cpp",
|
||||
"imagecache/smallimagecacheprovider.h",
|
||||
"imagecache/synchronousimagecache.cpp",
|
||||
"imagecache/timestampproviderinterface.h",
|
||||
"imagecache/timestampprovider.h",
|
||||
@@ -737,6 +741,8 @@ Project {
|
||||
"propertyeditor/gradientpresetlistmodel.h",
|
||||
"propertyeditor/propertyeditorcontextobject.cpp",
|
||||
"propertyeditor/propertyeditorcontextobject.h",
|
||||
"propertyeditor/propertyeditorimageprovider.cpp",
|
||||
"propertyeditor/propertyeditorimageprovider.h",
|
||||
"propertyeditor/propertyeditortransaction.cpp",
|
||||
"propertyeditor/propertyeditortransaction.h",
|
||||
"propertyeditor/propertyeditorvalue.cpp",
|
||||
|
||||
@@ -51,7 +51,8 @@
|
||||
#include <imagecache/imagecacheconnectionmanager.h>
|
||||
#include <imagecache/imagecachegenerator.h>
|
||||
#include <imagecache/imagecachestorage.h>
|
||||
#include <imagecache/timestampproviderinterface.h>
|
||||
#include <imagecache/meshimagecachecollector.h>
|
||||
#include <imagecache/timestampprovider.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
@@ -79,7 +80,7 @@ QString defaultImagePath()
|
||||
return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem());
|
||||
}
|
||||
|
||||
class TimeStampProvider : public TimeStampProviderInterface
|
||||
class PreviewTimeStampProvider : public TimeStampProviderInterface
|
||||
{
|
||||
public:
|
||||
Sqlite::TimeStamp timeStamp(Utils::SmallStringView) const override
|
||||
@@ -107,10 +108,13 @@ public:
|
||||
Sqlite::LockingMode::Normal};
|
||||
ImageCacheStorage<Sqlite::Database> storage{database};
|
||||
ImageCacheConnectionManager connectionManager;
|
||||
ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}};
|
||||
ImageCacheGenerator generator{collector, storage};
|
||||
MeshImageCacheCollector meshImageCollector{connectionManager, QSize{300, 300}, QSize{600, 600}};
|
||||
ImageCacheGenerator meshGenerator{meshImageCollector, storage};
|
||||
ImageCacheCollector nodeInstanceCollector{connectionManager, QSize{300, 300}, QSize{600, 600}};
|
||||
ImageCacheGenerator nodeInstanceGenerator{nodeInstanceCollector, storage};
|
||||
TimeStampProvider timeStampProvider;
|
||||
AsynchronousImageCache asynchronousImageCache{storage, generator, timeStampProvider};
|
||||
AsynchronousImageCache asynchronousImageCache{storage, nodeInstanceGenerator, timeStampProvider};
|
||||
AsynchronousImageCache asynchronousMeshImageCache{storage, meshGenerator, timeStampProvider};
|
||||
};
|
||||
|
||||
class QmlDesignerProjectManager::PreviewImageCacheData
|
||||
@@ -135,7 +139,7 @@ public:
|
||||
QSize{300, 300},
|
||||
QSize{1000, 1000},
|
||||
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
|
||||
TimeStampProvider timeStampProvider;
|
||||
PreviewTimeStampProvider timeStampProvider;
|
||||
AsynchronousImageFactory factory;
|
||||
::ProjectExplorer::Target *activeTarget = nullptr;
|
||||
};
|
||||
@@ -180,6 +184,11 @@ AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache()
|
||||
return imageCacheData()->asynchronousImageCache;
|
||||
}
|
||||
|
||||
AsynchronousImageCache &QmlDesignerProjectManager::asynchronousMeshImageCache()
|
||||
{
|
||||
return imageCacheData()->asynchronousMeshImageCache;
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::editorOpened(::Core::IEditor *) {}
|
||||
|
||||
void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *)
|
||||
@@ -218,17 +227,21 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache
|
||||
m_imageCacheData = std::make_unique<ImageCacheData>();
|
||||
auto setTargetInImageCache =
|
||||
[imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) {
|
||||
if (target == imageCacheData->collector.target())
|
||||
if (target == imageCacheData->nodeInstanceCollector.target())
|
||||
return;
|
||||
|
||||
if (target)
|
||||
imageCacheData->asynchronousImageCache.clean();
|
||||
|
||||
imageCacheData->collector.setTarget(target);
|
||||
// TODO wrap in function in image cache data
|
||||
imageCacheData->meshImageCollector.setTarget(target);
|
||||
imageCacheData->nodeInstanceCollector.setTarget(target);
|
||||
};
|
||||
|
||||
if (auto project = ProjectExplorer::SessionManager::startupProject(); project) {
|
||||
m_imageCacheData->collector.setTarget(project->activeTarget());
|
||||
// TODO wrap in function in image cache data
|
||||
m_imageCacheData->meshImageCollector.setTarget(project->activeTarget());
|
||||
m_imageCacheData->nodeInstanceCollector.setTarget(project->activeTarget());
|
||||
QObject::connect(project,
|
||||
&ProjectExplorer::Project::activeTargetChanged,
|
||||
this,
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
void registerPreviewImageProvider(QQmlEngine *engine) const;
|
||||
|
||||
class AsynchronousImageCache &asynchronousImageCache();
|
||||
class AsynchronousImageCache &asynchronousMeshImageCache();
|
||||
|
||||
private:
|
||||
void editorOpened(::Core::IEditor *editor);
|
||||
|
||||
Reference in New Issue
Block a user