2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2020 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2020-09-16 13:44:43 +02:00
|
|
|
|
|
|
|
#include "imagecachecollector.h"
|
|
|
|
#include "imagecacheconnectionmanager.h"
|
|
|
|
|
|
|
|
#include <model.h>
|
|
|
|
#include <nodeinstanceview.h>
|
2023-09-21 13:00:40 +02:00
|
|
|
#include <nodemetainfo.h>
|
2020-09-16 13:44:43 +02:00
|
|
|
#include <plaintexteditmodifier.h>
|
|
|
|
#include <rewriterview.h>
|
|
|
|
|
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
#include <projectexplorer/target.h>
|
|
|
|
#include <utils/fileutils.h>
|
|
|
|
|
2022-11-24 17:30:12 +02:00
|
|
|
#include <QGuiApplication>
|
2020-09-16 13:44:43 +02:00
|
|
|
#include <QPlainTextEdit>
|
|
|
|
|
|
|
|
namespace QmlDesigner {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2023-09-21 13:00:40 +02:00
|
|
|
QByteArray fileToByteArray(const QString &filename)
|
2020-09-16 13:44:43 +02:00
|
|
|
{
|
|
|
|
QFile file(filename);
|
|
|
|
QFileInfo fleInfo(file);
|
|
|
|
|
|
|
|
if (fleInfo.exists() && file.open(QFile::ReadOnly))
|
|
|
|
return file.readAll();
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
QString fileToString(const QString &filename)
|
|
|
|
{
|
|
|
|
return QString::fromUtf8(fileToByteArray(filename));
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2022-01-10 15:46:19 +01:00
|
|
|
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
|
2022-04-11 17:20:37 +02:00
|
|
|
QSize captureImageMinimumSize,
|
|
|
|
QSize captureImageMaximumSize,
|
2022-09-15 15:01:49 +02:00
|
|
|
ExternalDependenciesInterface &externalDependencies,
|
2022-01-10 15:46:19 +01:00
|
|
|
ImageCacheCollectorNullImageHandling nullImageHandling)
|
2020-09-16 13:44:43 +02:00
|
|
|
: m_connectionManager{connectionManager}
|
2022-04-11 17:20:37 +02:00
|
|
|
, captureImageMinimumSize{captureImageMinimumSize}
|
|
|
|
, captureImageMaximumSize{captureImageMaximumSize}
|
2022-09-15 15:01:49 +02:00
|
|
|
, m_externalDependencies{externalDependencies}
|
2022-01-10 15:46:19 +01:00
|
|
|
, nullImageHandling{nullImageHandling}
|
2020-09-16 13:44:43 +02:00
|
|
|
{}
|
|
|
|
|
|
|
|
ImageCacheCollector::~ImageCacheCollector() = default;
|
|
|
|
|
2023-01-25 10:11:18 +01:00
|
|
|
namespace {
|
|
|
|
QImage scaleImage(const QImage &image, QSize targetSize)
|
|
|
|
{
|
|
|
|
if (image.isNull())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
const qreal ratio = qGuiApp->devicePixelRatio();
|
|
|
|
if (ratio > 1.0)
|
|
|
|
targetSize *= qRound(ratio);
|
|
|
|
QSize scaledImageSize = image.size().scaled(targetSize.boundedTo(image.size()),
|
|
|
|
Qt::KeepAspectRatio);
|
|
|
|
return image.scaled(scaledImageSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
|
|
|
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2020-09-16 13:44:43 +02:00
|
|
|
void ImageCacheCollector::start(Utils::SmallStringView name,
|
2020-11-09 16:35:00 +01:00
|
|
|
Utils::SmallStringView state,
|
2022-05-27 14:14:22 +03:00
|
|
|
const ImageCache::AuxiliaryData &auxiliaryData,
|
2020-09-16 13:44:43 +02:00
|
|
|
CaptureCallback captureCallback,
|
2023-10-13 22:06:05 +02:00
|
|
|
AbortCallback abortCallback,
|
|
|
|
ImageCache::TraceToken traceToken)
|
2020-09-16 13:44:43 +02:00
|
|
|
{
|
2024-03-20 14:00:32 +01:00
|
|
|
#ifdef QDS_USE_PROJECTSTORAGE
|
2024-03-06 19:37:43 +01:00
|
|
|
if (!m_projectStorage || !m_pathCache)
|
|
|
|
return;
|
2024-03-20 14:00:32 +01:00
|
|
|
#endif
|
2024-03-06 19:37:43 +01:00
|
|
|
|
2023-10-13 22:06:05 +02:00
|
|
|
using namespace NanotraceHR::Literals;
|
2023-10-18 13:14:58 +02:00
|
|
|
auto [collectorTraceToken, flowtoken] = traceToken.beginDurationWithFlow(
|
2024-10-23 07:12:24 +02:00
|
|
|
"generate image in standard collector");
|
2023-10-13 22:06:05 +02:00
|
|
|
|
2022-09-15 15:01:49 +02:00
|
|
|
RewriterView rewriterView{m_externalDependencies, RewriterView::Amend};
|
2025-02-13 12:24:38 +01:00
|
|
|
rewriterView.setPossibleImportsEnabled(false);
|
2022-09-15 15:01:49 +02:00
|
|
|
NodeInstanceView nodeInstanceView{m_connectionManager, m_externalDependencies};
|
2022-04-11 17:20:37 +02:00
|
|
|
nodeInstanceView.setCaptureImageMinimumAndMaximumSize(captureImageMinimumSize,
|
|
|
|
captureImageMaximumSize);
|
2020-09-16 13:44:43 +02:00
|
|
|
|
|
|
|
const QString filePath{name};
|
2024-03-06 19:37:43 +01:00
|
|
|
#ifdef QDS_USE_PROJECTSTORAGE
|
|
|
|
auto model = QmlDesigner::Model::create({*m_projectStorage, *m_pathCache},
|
|
|
|
"Item",
|
|
|
|
{},
|
|
|
|
QUrl::fromLocalFile(filePath));
|
|
|
|
#else
|
2022-10-27 12:17:22 +02:00
|
|
|
auto model = QmlDesigner::Model::create("QtQuick/Item", 2, 1);
|
2020-09-16 13:44:43 +02:00
|
|
|
model->setFileUrl(QUrl::fromLocalFile(filePath));
|
2024-03-06 19:37:43 +01:00
|
|
|
#endif
|
2020-09-16 13:44:43 +02:00
|
|
|
|
|
|
|
auto textDocument = std::make_unique<QTextDocument>(fileToString(filePath));
|
|
|
|
|
|
|
|
auto modifier = std::make_unique<NotIndentingTextEditModifier>(textDocument.get(),
|
|
|
|
QTextCursor{textDocument.get()});
|
|
|
|
|
|
|
|
rewriterView.setTextModifier(modifier.get());
|
|
|
|
|
|
|
|
model->setRewriterView(&rewriterView);
|
|
|
|
|
2022-08-24 13:11:33 +02:00
|
|
|
auto rootModelNodeMetaInfo = rewriterView.rootModelNode().metaInfo();
|
2022-06-21 14:16:01 +02:00
|
|
|
bool is3DRoot = rewriterView.errors().isEmpty()
|
2022-08-24 13:11:33 +02:00
|
|
|
&& (rootModelNodeMetaInfo.isQtQuick3DNode()
|
|
|
|
|| rootModelNodeMetaInfo.isQtQuick3DMaterial());
|
2022-05-27 14:14:22 +03:00
|
|
|
|
2022-06-21 14:16:01 +02:00
|
|
|
if (!rewriterView.errors().isEmpty() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem()
|
2022-05-27 14:14:22 +03:00
|
|
|
&& !is3DRoot)) {
|
2022-01-12 12:55:26 +01:00
|
|
|
if (abortCallback)
|
2023-10-18 13:14:58 +02:00
|
|
|
abortCallback(ImageCache::AbortReason::Failed, std::move(flowtoken));
|
2020-09-16 13:44:43 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-27 14:14:22 +03:00
|
|
|
if (is3DRoot) {
|
2022-08-19 14:47:59 +02:00
|
|
|
if (auto libIcon = std::get_if<ImageCache::LibraryIconAuxiliaryData>(&auxiliaryData))
|
2022-08-09 13:45:50 +02:00
|
|
|
rewriterView.rootModelNode().setAuxiliaryData(AuxiliaryDataType::NodeInstancePropertyOverwrite,
|
2022-07-25 20:16:58 +02:00
|
|
|
"isLibraryIcon",
|
|
|
|
libIcon->enable);
|
2022-05-27 14:14:22 +03:00
|
|
|
}
|
|
|
|
|
2020-11-09 16:35:00 +01:00
|
|
|
ModelNode stateNode = rewriterView.modelNodeForId(QString{state});
|
|
|
|
|
|
|
|
if (stateNode.isValid())
|
|
|
|
rewriterView.setCurrentStateNode(stateNode);
|
|
|
|
|
2023-10-13 22:06:05 +02:00
|
|
|
QImage captureImage;
|
|
|
|
|
|
|
|
auto callback = [&](const QImage &image) { captureImage = image; };
|
2021-01-13 13:23:46 +01:00
|
|
|
|
2022-01-06 10:21:37 +01:00
|
|
|
if (!m_target)
|
|
|
|
return;
|
2020-09-16 13:44:43 +02:00
|
|
|
|
2020-11-24 10:16:33 +01:00
|
|
|
nodeInstanceView.setTarget(m_target.data());
|
2022-01-06 10:21:37 +01:00
|
|
|
m_connectionManager.setCallback(std::move(callback));
|
2023-10-13 22:06:05 +02:00
|
|
|
bool isCrashed = false;
|
|
|
|
nodeInstanceView.setCrashCallback([&] { isCrashed = true; });
|
2020-09-16 13:44:43 +02:00
|
|
|
model->setNodeInstanceView(&nodeInstanceView);
|
|
|
|
|
|
|
|
bool capturedDataArrived = m_connectionManager.waitForCapturedData();
|
|
|
|
|
|
|
|
m_connectionManager.setCallback({});
|
|
|
|
m_connectionManager.setCrashCallback({});
|
|
|
|
|
|
|
|
model->setNodeInstanceView({});
|
|
|
|
model->setRewriterView({});
|
|
|
|
|
2023-10-13 22:06:05 +02:00
|
|
|
if (isCrashed)
|
2023-10-18 13:14:58 +02:00
|
|
|
abortCallback(ImageCache::AbortReason::Failed, std::move(flowtoken));
|
2023-10-13 22:06:05 +02:00
|
|
|
|
2022-01-12 12:55:26 +01:00
|
|
|
if (!capturedDataArrived && abortCallback)
|
2023-10-18 13:14:58 +02:00
|
|
|
abortCallback(ImageCache::AbortReason::Failed, std::move(flowtoken));
|
2023-10-13 22:06:05 +02:00
|
|
|
|
|
|
|
if (nullImageHandling == ImageCacheCollectorNullImageHandling::CaptureNullImage
|
|
|
|
|| !captureImage.isNull()) {
|
|
|
|
QImage midSizeImage = scaleImage(captureImage, QSize{300, 300});
|
|
|
|
QImage smallImage = scaleImage(midSizeImage, QSize{96, 96});
|
2023-10-18 13:14:58 +02:00
|
|
|
captureCallback(captureImage, midSizeImage, smallImage, std::move(flowtoken));
|
2023-10-13 22:06:05 +02:00
|
|
|
}
|
2020-09-16 13:44:43 +02:00
|
|
|
}
|
|
|
|
|
2023-01-25 10:11:18 +01:00
|
|
|
ImageCacheCollectorInterface::ImageTuple ImageCacheCollector::createImage(
|
|
|
|
Utils::SmallStringView, Utils::SmallStringView, const ImageCache::AuxiliaryData &)
|
2021-01-13 13:23:46 +01:00
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-01-10 15:46:19 +01:00
|
|
|
QIcon ImageCacheCollector::createIcon(Utils::SmallStringView,
|
|
|
|
Utils::SmallStringView,
|
|
|
|
const ImageCache::AuxiliaryData &)
|
2021-01-13 13:23:46 +01:00
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-11-24 10:16:33 +01:00
|
|
|
void ImageCacheCollector::setTarget(ProjectExplorer::Target *target)
|
2020-09-16 13:44:43 +02:00
|
|
|
{
|
2020-11-24 10:16:33 +01:00
|
|
|
m_target = target;
|
2020-09-16 13:44:43 +02:00
|
|
|
}
|
|
|
|
|
2021-01-26 17:05:27 +01:00
|
|
|
ProjectExplorer::Target *ImageCacheCollector::target() const
|
|
|
|
{
|
|
|
|
return m_target;
|
|
|
|
}
|
|
|
|
|
2020-09-16 13:44:43 +02:00
|
|
|
} // namespace QmlDesigner
|