QmlDesigner: Add image cache

The image cache is saving images and icon of this images in a sqlite
database. If there are no images they are generated in the backgound.
The icons are fetched by item library.

Task-number: QDS-2782
Task-number: QDS-2783
Task-number: QDS-2858
Change-Id: I5a32cccfef7f8fd8eb78902605a09f5da18ce88e
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2020-09-16 13:44:43 +02:00
committed by Tim Jenssen
parent 58e612c85f
commit d1b0c12d6b
111 changed files with 4407 additions and 241 deletions

View File

@@ -151,8 +151,19 @@ public:
qint32 nodeId = -1; qint32 nodeId = -1;
}; };
CapturedDataCommand() = default;
CapturedDataCommand(QVector<StateData> &&stateData)
: stateData{std::move(stateData)}
{}
CapturedDataCommand(QImage &&image)
: image{std::move(image)}
{}
friend QDataStream &operator<<(QDataStream &out, const CapturedDataCommand &command) friend QDataStream &operator<<(QDataStream &out, const CapturedDataCommand &command)
{ {
out << command.image;
out << command.stateData; out << command.stateData;
return out; return out;
@@ -160,12 +171,14 @@ public:
friend QDataStream &operator>>(QDataStream &in, CapturedDataCommand &command) friend QDataStream &operator>>(QDataStream &in, CapturedDataCommand &command)
{ {
in >> command.image;
in >> command.stateData; in >> command.stateData;
return in; return in;
} }
public: public:
QImage image;
QVector<StateData> stateData; QVector<StateData> stateData;
}; };

View File

@@ -86,6 +86,7 @@ public:
virtual void requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command) = 0; virtual void requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command) = 0;
virtual void changeLanguage(const ChangeLanguageCommand &command) = 0; virtual void changeLanguage(const ChangeLanguageCommand &command) = 0;
virtual void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) = 0; virtual void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) = 0;
virtual void dispatchCommand(const QVariant &) {}
virtual void benchmark(const QString &) {} virtual void benchmark(const QString &) {}

View File

@@ -9,6 +9,7 @@ HEADERS += $$PWD/qt5nodeinstanceserver.h \
$$PWD/capturenodeinstanceserverdispatcher.h \ $$PWD/capturenodeinstanceserverdispatcher.h \
$$PWD/capturescenecreatedcommand.h \ $$PWD/capturescenecreatedcommand.h \
$$PWD/nodeinstanceserverdispatcher.h \ $$PWD/nodeinstanceserverdispatcher.h \
$$PWD/qt5captureimagenodeinstanceserver.h \
$$PWD/qt5capturepreviewnodeinstanceserver.h \ $$PWD/qt5capturepreviewnodeinstanceserver.h \
$$PWD/qt5testnodeinstanceserver.h \ $$PWD/qt5testnodeinstanceserver.h \
$$PWD/qt5informationnodeinstanceserver.h \ $$PWD/qt5informationnodeinstanceserver.h \
@@ -33,11 +34,13 @@ HEADERS += $$PWD/qt5nodeinstanceserver.h \
$$PWD/layoutnodeinstance.h \ $$PWD/layoutnodeinstance.h \
$$PWD/qt3dpresentationnodeinstance.h \ $$PWD/qt3dpresentationnodeinstance.h \
$$PWD/quick3dnodeinstance.h \ $$PWD/quick3dnodeinstance.h \
$$PWD/quick3dtexturenodeinstance.h $$PWD/quick3dtexturenodeinstance.h \
SOURCES += $$PWD/qt5nodeinstanceserver.cpp \ SOURCES += $$PWD/qt5nodeinstanceserver.cpp \
$$PWD/capturenodeinstanceserverdispatcher.cpp \ $$PWD/capturenodeinstanceserverdispatcher.cpp \
$$PWD/nodeinstanceserverdispatcher.cpp \ $$PWD/nodeinstanceserverdispatcher.cpp \
$$PWD/qt5captureimagenodeinstanceserver.cpp \
$$PWD/qt5capturepreviewnodeinstanceserver.cpp \ $$PWD/qt5capturepreviewnodeinstanceserver.cpp \
$$PWD/qt5testnodeinstanceserver.cpp \ $$PWD/qt5testnodeinstanceserver.cpp \
$$PWD/qt5informationnodeinstanceserver.cpp \ $$PWD/qt5informationnodeinstanceserver.cpp \

View File

@@ -25,6 +25,7 @@
#include "nodeinstanceserverdispatcher.h" #include "nodeinstanceserverdispatcher.h"
#include "qt5captureimagenodeinstanceserver.h"
#include "qt5capturepreviewnodeinstanceserver.h" #include "qt5capturepreviewnodeinstanceserver.h"
#include "qt5informationnodeinstanceserver.h" #include "qt5informationnodeinstanceserver.h"
#include "qt5rendernodeinstanceserver.h" #include "qt5rendernodeinstanceserver.h"
@@ -183,6 +184,8 @@ std::unique_ptr<NodeInstanceServer> createNodeInstanceServer(
{ {
if (serverName == "capturemode") if (serverName == "capturemode")
return std::make_unique<Qt5CapturePreviewNodeInstanceServer>(nodeInstanceClient); return std::make_unique<Qt5CapturePreviewNodeInstanceServer>(nodeInstanceClient);
else if (serverName == "captureiconmode")
return std::make_unique<Qt5CaptureImageNodeInstanceServer>(nodeInstanceClient);
else if (serverName == "rendermode") else if (serverName == "rendermode")
return std::make_unique<Qt5RenderNodeInstanceServer>(nodeInstanceClient); return std::make_unique<Qt5RenderNodeInstanceServer>(nodeInstanceClient);
else if (serverName == "editormode") else if (serverName == "editormode")

View File

@@ -0,0 +1,84 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qt5captureimagenodeinstanceserver.h"
#include "servernodeinstance.h"
#include <captureddatacommand.h>
#include <createscenecommand.h>
#include <nodeinstanceclientinterface.h>
#include <QImage>
#include <QQuickItem>
#include <QQuickView>
namespace QmlDesigner {
namespace {
QImage renderImage(ServerNodeInstance rootNodeInstance)
{
rootNodeInstance.updateDirtyNodeRecursive();
QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize();
if (previewImageSize.isEmpty())
previewImageSize = {640, 480};
if (previewImageSize.width() > 800 || previewImageSize.height() > 800)
previewImageSize.scale({800, 800}, Qt::KeepAspectRatio);
QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize);
return previewImage;
}
} // namespace
void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
static bool inFunction = false;
if (!rootNodeInstance().holdsGraphical()) {
nodeInstanceClient()->capturedData(CapturedDataCommand{});
return;
}
if (!inFunction) {
inFunction = true;
auto rooNodeInstance = rootNodeInstance();
rooNodeInstance.rootQuickItem()->setClip(true);
DesignerSupport::polishItems(quickView());
QImage image = renderImage(rooNodeInstance);
nodeInstanceClient()->capturedData(CapturedDataCommand{std::move(image)});
slowDownRenderTimer();
inFunction = false;
}
}
} // namespace

View File

@@ -0,0 +1,45 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <qt5previewnodeinstanceserver.h>
namespace QmlDesigner {
class Qt5CaptureImageNodeInstanceServer : public Qt5PreviewNodeInstanceServer
{
public:
explicit Qt5CaptureImageNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient)
: Qt5PreviewNodeInstanceServer(nodeInstanceClient)
{}
protected:
void collectItemChangesAndSendChangeCommands() override;
private:
};
} // namespace QmlDesigner

View File

@@ -100,7 +100,7 @@ void Qt5CapturePreviewNodeInstanceServer::collectItemChangesAndSendChangeCommand
stateInstance.deactivateState(); stateInstance.deactivateState();
} }
nodeInstanceClient()->capturedData(CapturedDataCommand{stateDatas}); nodeInstanceClient()->capturedData(CapturedDataCommand{std::move(stateDatas)});
slowDownRenderTimer(); slowDownRenderTimer();
inFunction = false; inFunction = false;

View File

@@ -28,6 +28,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include "capturenodeinstanceserverdispatcher.h" #include "capturenodeinstanceserverdispatcher.h"
#include "qt5captureimagenodeinstanceserver.h"
#include "qt5capturepreviewnodeinstanceserver.h" #include "qt5capturepreviewnodeinstanceserver.h"
#include "qt5informationnodeinstanceserver.h" #include "qt5informationnodeinstanceserver.h"
#include "qt5previewnodeinstanceserver.h" #include "qt5previewnodeinstanceserver.h"
@@ -92,6 +93,9 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
} else if (QCoreApplication::arguments().at(2) == QLatin1String("capturemode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("capturemode")) {
setNodeInstanceServer(std::make_unique<Qt5CapturePreviewNodeInstanceServer>(this)); setNodeInstanceServer(std::make_unique<Qt5CapturePreviewNodeInstanceServer>(this));
initializeSocket(); initializeSocket();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("captureiconmode")) {
setNodeInstanceServer(std::make_unique<Qt5CaptureImageNodeInstanceServer>(this));
initializeSocket();
} }
} }

View File

@@ -566,7 +566,7 @@ QRectF QuickItemNodeInstance::boundingRectWithStepChilds(QQuickItem *parentItem)
boundingRect = boundingRect.united(QRectF(QPointF(0, 0), size())); boundingRect = boundingRect.united(QRectF(QPointF(0, 0), size()));
foreach (QQuickItem *childItem, parentItem->childItems()) { for (QQuickItem *childItem : parentItem->childItems()) {
if (!nodeInstanceServer()->hasInstanceForObject(childItem)) { if (!nodeInstanceServer()->hasInstanceForObject(childItem)) {
QRectF transformedRect = childItem->mapRectToItem(parentItem, boundingRectWithStepChilds(childItem)); QRectF transformedRect = childItem->mapRectToItem(parentItem, boundingRectWithStepChilds(childItem));
if (isRectangleSane(transformedRect)) if (isRectangleSane(transformedRect))
@@ -574,6 +574,9 @@ QRectF QuickItemNodeInstance::boundingRectWithStepChilds(QQuickItem *parentItem)
} }
} }
if (boundingRect.isEmpty())
QRectF{0, 0, 640, 480};
return boundingRect; return boundingRect;
} }

View File

@@ -42,9 +42,11 @@
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <windows.h> #include <Windows.h>
#endif #endif
namespace {
int internalMain(QGuiApplication *application) int internalMain(QGuiApplication *application)
{ {
QCoreApplication::setOrganizationName("QtProject"); QCoreApplication::setOrganizationName("QtProject");
@@ -138,6 +140,7 @@ int internalMain(QGuiApplication *application)
return application->exec(); return application->exec();
} }
} // namespace
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {

View File

@@ -46,8 +46,6 @@ Item {
width: itemLibraryIconWidth // to be set in Qml context width: itemLibraryIconWidth // to be set in Qml context
height: itemLibraryIconHeight // to be set in Qml context height: itemLibraryIconHeight // to be set in Qml context
source: itemLibraryIconPath // to be set by model source: itemLibraryIconPath // to be set by model
cache: false // Allow thumbnail to be dynamically updated
} }
Text { Text {
@@ -71,10 +69,11 @@ Item {
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
ToolTipArea { ImagePreviewTooltipArea {
id: mouseRegion id: mouseRegion
anchors.fill: parent anchors.fill: parent
tooltip: itemName
onPressed: { onPressed: {
rootView.startDragAndDrop(mouseRegion, itemLibraryEntry) rootView.startDragAndDrop(mouseRegion, itemLibraryEntry)
} }

View File

@@ -0,0 +1,48 @@
/****************************************************************************
**
** Copyright (C) 2016 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.
**
****************************************************************************/
import QtQuick 2.1
import HelperWidgets 2.0
import QtQuick.Layouts 1.0
MouseArea {
id: mouseArea
onExited: tooltipBackend.hideTooltip()
onCanceled: tooltipBackend.hideTooltip()
onClicked: forceActiveFocus()
hoverEnabled: true
Timer {
interval: 1000
running: mouseArea.containsMouse
onTriggered: {
tooltipBackend.componentName = itemName
tooltipBackend.componentPath = componentPath
tooltipBackend.showTooltip()
}
}
}

View File

@@ -47,3 +47,4 @@ ExpressionTextField 2.0 ExpressionTextField.qml
MarginSection 2.0 MarginSection.qml MarginSection 2.0 MarginSection.qml
HorizontalScrollBar 2.0 HorizontalScrollBar.qml HorizontalScrollBar 2.0 HorizontalScrollBar.qml
VerticalScrollBar 2.0 VerticalScrollBar.qml VerticalScrollBar 2.0 VerticalScrollBar.qml
ImagePreviewTooltipArea 2.0 ImagePreviewTooltipArea.qml

View File

@@ -44,4 +44,6 @@ add_qtc_library(Sqlite
tableconstraints.h tableconstraints.h
utf8string.cpp utf8string.h utf8string.cpp utf8string.h
utf8stringvector.cpp utf8stringvector.h utf8stringvector.cpp utf8stringvector.h
sqliteblob.h
sqlitetimestamp.h
) )

View File

@@ -27,6 +27,8 @@ SOURCES += \
$$PWD/sqlitebasestatement.cpp $$PWD/sqlitebasestatement.cpp
HEADERS += \ HEADERS += \
$$PWD/constraints.h \ $$PWD/constraints.h \
$$PWD/sqliteblob.h \
$$PWD/sqlitetimestamp.h \
$$PWD/tableconstraints.h \ $$PWD/tableconstraints.h \
$$PWD/createtablesqlstatementbuilder.h \ $$PWD/createtablesqlstatementbuilder.h \
$$PWD/lastchangedrowid.h \ $$PWD/lastchangedrowid.h \

View File

@@ -191,12 +191,12 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
checkForBindingError(resultCode); checkForBindingError(resultCode);
} }
void BaseStatement::bind(int index, Utils::span<const byte> bytes) void BaseStatement::bind(int index, BlobView blobView)
{ {
int resultCode = sqlite3_bind_blob64(m_compiledStatement.get(), int resultCode = sqlite3_bind_blob64(m_compiledStatement.get(),
index, index,
bytes.data(), blobView.data(),
static_cast<long long>(bytes.size()), blobView.size(),
SQLITE_STATIC); SQLITE_STATIC);
if (resultCode != SQLITE_OK) if (resultCode != SQLITE_OK)
checkForBindingError(resultCode); checkForBindingError(resultCode);
@@ -498,7 +498,7 @@ StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
return StringType(text, size); return StringType(text, size);
} }
Utils::span<const byte> blobForColumn(sqlite3_stmt *sqlStatment, int column) BlobView blobForColumn(sqlite3_stmt *sqlStatment, int column)
{ {
const byte *blob = reinterpret_cast<const byte *>(sqlite3_column_blob(sqlStatment, column)); const byte *blob = reinterpret_cast<const byte *>(sqlite3_column_blob(sqlStatment, column));
std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column)); std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column));
@@ -506,7 +506,7 @@ Utils::span<const byte> blobForColumn(sqlite3_stmt *sqlStatment, int column)
return {blob, size}; return {blob, size};
} }
Utils::span<const byte> convertToBlobForColumn(sqlite3_stmt *sqlStatment, int column) BlobView convertToBlobForColumn(sqlite3_stmt *sqlStatment, int column)
{ {
int dataType = sqlite3_column_type(sqlStatment, column); int dataType = sqlite3_column_type(sqlStatment, column);
if (dataType == SQLITE_BLOB) if (dataType == SQLITE_BLOB)
@@ -571,7 +571,7 @@ double BaseStatement::fetchDoubleValue(int column) const
return sqlite3_column_double(m_compiledStatement.get(), column); return sqlite3_column_double(m_compiledStatement.get(), column);
} }
Utils::span<const byte> BaseStatement::fetchBlobValue(int column) const BlobView BaseStatement::fetchBlobValue(int column) const
{ {
return convertToBlobForColumn(m_compiledStatement.get(), column); return convertToBlobForColumn(m_compiledStatement.get(), column);
} }

View File

@@ -27,6 +27,7 @@
#include "sqliteglobal.h" #include "sqliteglobal.h"
#include "sqliteblob.h"
#include "sqliteexception.h" #include "sqliteexception.h"
#include "sqlitevalue.h" #include "sqlitevalue.h"
@@ -70,7 +71,7 @@ public:
double fetchDoubleValue(int column) const; double fetchDoubleValue(int column) const;
Utils::SmallStringView fetchSmallStringViewValue(int column) const; Utils::SmallStringView fetchSmallStringViewValue(int column) const;
ValueView fetchValueView(int column) const; ValueView fetchValueView(int column) const;
Utils::span<const byte> fetchBlobValue(int column) const; BlobView fetchBlobValue(int column) const;
template<typename Type> template<typename Type>
Type fetchValue(int column) const; Type fetchValue(int column) const;
int columnCount() const; int columnCount() const;
@@ -82,7 +83,7 @@ public:
void bind(int index, void *pointer); void bind(int index, void *pointer);
void bind(int index, Utils::SmallStringView fetchValue); void bind(int index, Utils::SmallStringView fetchValue);
void bind(int index, const Value &fetchValue); void bind(int index, const Value &fetchValue);
void bind(int index, Utils::span<const byte> bytes); void bind(int index, BlobView blobView);
void bind(int index, uint value) { bind(index, static_cast<long long>(value)); } void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
@@ -358,7 +359,7 @@ private:
operator long long() { return statement.fetchLongLongValue(column); } operator long long() { return statement.fetchLongLongValue(column); }
operator double() { return statement.fetchDoubleValue(column); } operator double() { return statement.fetchDoubleValue(column); }
operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); } operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
operator Utils::span<const Sqlite::byte>() { return statement.fetchBlobValue(column); } operator BlobView() { return statement.fetchBlobValue(column); }
operator ValueView() { return statement.fetchValueView(column); } operator ValueView() { return statement.fetchValueView(column); }
StatementImplementation &statement; StatementImplementation &statement;

View File

@@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "sqliteglobal.h"
#include <utils/span.h>
#include <QByteArray>
#include <algorithm>
#include <cstring>
#include <vector>
namespace Sqlite {
class BlobView
{
public:
BlobView() = default;
BlobView(const byte *data, std::size_t size)
: m_data(data)
, m_size(size)
{}
BlobView(const QByteArray &byteArray)
: m_data(reinterpret_cast<const byte *>(byteArray.constData()))
, m_size(static_cast<std::size_t>(byteArray.size()))
{}
BlobView(const std::vector<Sqlite::byte> &bytes)
: m_data(bytes.data())
, m_size(static_cast<std::size_t>(bytes.size()))
{}
const byte *data() const { return m_data; }
const char *cdata() const { return reinterpret_cast<const char *>(m_data); }
std::size_t size() const { return m_size; }
int sisize() const { return static_cast<int>(m_size); }
long long ssize() const { return static_cast<long long>(m_size); }
bool empty() const { return !m_size; }
friend bool operator==(Sqlite::BlobView first, Sqlite::BlobView second)
{
return first.size() == second.size()
&& std::memcmp(first.data(), second.data(), first.size()) == 0;
}
private:
const byte *m_data{};
std::size_t m_size{};
};
class Blob
{
public:
Blob(BlobView blobView)
{
bytes.reserve(blobView.size());
std::copy_n(blobView.data(), blobView.size(), std::back_inserter(bytes));
}
std::vector<Sqlite::byte> bytes;
};
class ByteArrayBlob
{
public:
ByteArrayBlob(BlobView blobView)
: byteArray{blobView.cdata(), blobView.sisize()}
{}
QByteArray byteArray;
};
} // namespace Sqlite

View File

@@ -46,7 +46,7 @@ void checkResultCode(int resultCode)
} // namespace } // namespace
SessionChangeSet::SessionChangeSet(Utils::span<const byte> blob) SessionChangeSet::SessionChangeSet(BlobView blob)
: data(sqlite3_malloc64(blob.size())) : data(sqlite3_malloc64(blob.size()))
, size(int(blob.size())) , size(int(blob.size()))
{ {
@@ -64,7 +64,7 @@ SessionChangeSet::~SessionChangeSet()
sqlite3_free(data); sqlite3_free(data);
} }
Utils::span<const byte> SessionChangeSet::asSpan() const BlobView SessionChangeSet::asBlobView() const
{ {
return {static_cast<const byte *>(data), static_cast<std::size_t>(size)}; return {static_cast<const byte *>(data), static_cast<std::size_t>(size)};
} }

View File

@@ -25,10 +25,9 @@
#pragma once #pragma once
#include "sqliteblob.h"
#include "sqliteglobal.h" #include "sqliteglobal.h"
#include <utils/span.h>
#include <memory> #include <memory>
#include <vector> #include <vector>
@@ -41,7 +40,7 @@ class Sessions;
class SessionChangeSet class SessionChangeSet
{ {
public: public:
SessionChangeSet(Utils::span<const byte> blob); SessionChangeSet(BlobView blob);
SessionChangeSet(Sessions &session); SessionChangeSet(Sessions &session);
~SessionChangeSet(); ~SessionChangeSet();
SessionChangeSet(const SessionChangeSet &) = delete; SessionChangeSet(const SessionChangeSet &) = delete;
@@ -54,7 +53,7 @@ public:
} }
void operator=(SessionChangeSet &); void operator=(SessionChangeSet &);
Utils::span<const byte> asSpan() const; BlobView asBlobView() const;
friend void swap(SessionChangeSet &first, SessionChangeSet &second) noexcept friend void swap(SessionChangeSet &first, SessionChangeSet &second) noexcept
{ {

View File

@@ -103,7 +103,7 @@ void Sessions::commit()
if (session && !sqlite3session_isempty(session.get())) { if (session && !sqlite3session_isempty(session.get())) {
SessionChangeSet changeSet{*this}; SessionChangeSet changeSet{*this};
insertSession.write(changeSet.asSpan()); insertSession.write(changeSet.asBlobView());
} }
session.reset(); session.reset();

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
namespace Sqlite {
class TimeStamp
{
public:
TimeStamp() = default;
TimeStamp(long long value)
: value(value)
{}
friend bool operator==(TimeStamp first, TimeStamp second)
{
return first.value == second.value;
}
public:
long long value = -1;
};
} // namespace Sqlite

View File

@@ -23,6 +23,8 @@
** **
****************************************************************************/ ****************************************************************************/
#pragma once
#include "sqliteexception.h" #include "sqliteexception.h"
#include <utils/smallstring.h> #include <utils/smallstring.h>
@@ -32,9 +34,6 @@
#include <cstddef> #include <cstddef>
#pragma once
namespace Sqlite { namespace Sqlite {
enum class ValueType : unsigned char { Null, Integer, Float, String }; enum class ValueType : unsigned char { Null, Integer, Float, String };

View File

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

View File

@@ -6,7 +6,7 @@ endif()
add_qtc_plugin(QmlDesigner add_qtc_plugin(QmlDesigner
DEPENDS DEPENDS
QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
Qt5::QuickWidgets Qt5::CorePrivate Qt5::QuickWidgets Qt5::CorePrivate Sqlite
DEFINES DEFINES
DESIGNER_CORE_LIBRARY DESIGNER_CORE_LIBRARY
IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\" IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\"
@@ -317,6 +317,7 @@ extend_qtc_plugin(QmlDesigner
itemlibraryassetimportdialog.cpp itemlibraryassetimportdialog.h itemlibraryassetimportdialog.cpp itemlibraryassetimportdialog.h
itemlibraryassetimportdialog.ui itemlibraryassetimportdialog.ui
itemlibraryassetimporter.cpp itemlibraryassetimporter.h itemlibraryassetimporter.cpp itemlibraryassetimporter.h
itemlibraryiconimageprovider.cpp itemlibraryiconimageprovider.h
) )
find_package(Qt5 COMPONENTS Quick3DAssetImport QUIET) find_package(Qt5 COMPONENTS Quick3DAssetImport QUIET)
@@ -502,6 +503,7 @@ extend_qtc_plugin(QmlDesigner
include/textmodifier.h include/textmodifier.h
include/variantproperty.h include/variantproperty.h
include/viewmanager.h include/viewmanager.h
include/imagecache.h
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
@@ -586,6 +588,21 @@ extend_qtc_plugin(QmlDesigner
pluginmanager/widgetpluginmanager.cpp pluginmanager/widgetpluginmanager.h pluginmanager/widgetpluginmanager.cpp pluginmanager/widgetpluginmanager.h
pluginmanager/widgetpluginpath.cpp pluginmanager/widgetpluginpath.h pluginmanager/widgetpluginpath.cpp pluginmanager/widgetpluginpath.h
rewritertransaction.cpp rewritertransaction.h rewritertransaction.cpp rewritertransaction.h
imagecache/imagecachecollector.h
imagecache/imagecachecollector.cpp
imagecache/imagecache.cpp
imagecache/imagecachecollectorinterface.h
imagecache/imagecacheconnectionmanager.cpp
imagecache/imagecacheconnectionmanager.h
imagecache/imagecachegenerator.cpp
imagecache/imagecachegenerator.h
imagecache/imagecachestorage.h
imagecache/imagecachegeneratorinterface.h
imagecache/imagecachestorageinterface.h
imagecache/timestampproviderinterface.h
imagecache/timestampprovider.h
imagecache/timestampprovider.cpp
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -14,6 +14,7 @@ include (../../../../share/qtcreator/qml/qmlpuppet/container/container.pri)
include (../../../../share/qtcreator/qml/qmlpuppet/types/types.pri) include (../../../../share/qtcreator/qml/qmlpuppet/types/types.pri)
SOURCES += $$PWD/model/abstractview.cpp \ SOURCES += $$PWD/model/abstractview.cpp \
$$PWD/imagecache/imagecachecollector.cpp \
$$PWD/model/rewriterview.cpp \ $$PWD/model/rewriterview.cpp \
$$PWD/model/documentmessage.cpp \ $$PWD/model/documentmessage.cpp \
$$PWD/metainfo/metainfo.cpp \ $$PWD/metainfo/metainfo.cpp \
@@ -84,9 +85,15 @@ SOURCES += $$PWD/model/abstractview.cpp \
$$PWD/model/qmltimeline.cpp \ $$PWD/model/qmltimeline.cpp \
$$PWD/model/qmltimelinekeyframegroup.cpp \ $$PWD/model/qmltimelinekeyframegroup.cpp \
$$PWD/model/annotation.cpp \ $$PWD/model/annotation.cpp \
$$PWD/model/stylesheetmerger.cpp $$PWD/model/stylesheetmerger.cpp \
$$PWD/imagecache/imagecache.cpp \
$$PWD/imagecache/imagecacheconnectionmanager.cpp \
$$PWD/imagecache/imagecachegenerator.cpp \
$$PWD/imagecache/timestampprovider.cpp
HEADERS += $$PWD/include/qmldesignercorelib_global.h \ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
$$PWD/imagecache/imagecachecollector.h \
$$PWD/include/abstractview.h \ $$PWD/include/abstractview.h \
$$PWD/include/nodeinstanceview.h \ $$PWD/include/nodeinstanceview.h \
$$PWD/include/rewriterview.h \ $$PWD/include/rewriterview.h \
@@ -162,7 +169,17 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
$$PWD/include/qmltimeline.h \ $$PWD/include/qmltimeline.h \
$$PWD/include/qmltimelinekeyframegroup.h \ $$PWD/include/qmltimelinekeyframegroup.h \
$$PWD/include/annotation.h \ $$PWD/include/annotation.h \
$$PWD/include/stylesheetmerger.h $$PWD/include/stylesheetmerger.h \
$$PWD/include/imagecache.h \
$$PWD/imagecache/imagecachecollectorinterface.h \
$$PWD/imagecache/imagecacheconnectionmanager.h \
$$PWD/imagecache/imagecachegeneratorinterface.h \
$$PWD/imagecache/imagecachestorageinterface.h \
$$PWD/imagecache/imagecachegenerator.h \
$$PWD/imagecache/imagecachestorage.h \
$$PWD/imagecache/timestampprovider.h \
$$PWD/imagecache/timestampproviderinterface.h
FORMS += \ FORMS += \
$$PWD/instances/puppetdialog.ui $$PWD/instances/puppetdialog.ui

View File

@@ -0,0 +1,166 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "imagecache.h"
#include "imagecachegenerator.h"
#include "imagecachestorage.h"
#include "timestampprovider.h"
#include <thread>
namespace QmlDesigner {
ImageCache::ImageCache(ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider)
: m_storage(storage)
, m_generator(generator)
, m_timeStampProvider(timeStampProvider)
{
m_backgroundThread = std::thread{[this] {
while (isRunning()) {
if (auto [hasEntry, entry] = getEntry(); hasEntry) {
request(entry.name,
entry.requestType,
std::move(entry.captureCallback),
std::move(entry.abortCallback),
m_storage,
m_generator,
m_timeStampProvider);
}
waitForEntries();
}
}};
}
ImageCache::~ImageCache()
{
clean();
stopThread();
m_condition.notify_all();
if (m_backgroundThread.joinable())
m_backgroundThread.join();
}
void ImageCache::request(Utils::SmallStringView name,
ImageCache::RequestType requestType,
ImageCache::CaptureCallback captureCallback,
ImageCache::AbortCallback abortCallback,
ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider)
{
const auto timeStamp = timeStampProvider.timeStamp(name);
const auto entry = requestType == RequestType::Image ? storage.fetchImage(name, timeStamp)
: storage.fetchIcon(name, timeStamp);
if (entry.hasEntry) {
if (entry.image.isNull())
abortCallback();
else
captureCallback(entry.image);
} else {
generator.generateImage(name, timeStamp, std::move(captureCallback), std::move(abortCallback));
}
}
void ImageCache::requestImage(Utils::PathString name,
ImageCache::CaptureCallback captureCallback,
AbortCallback abortCallback)
{
addEntry(std::move(name), std::move(captureCallback), std::move(abortCallback), RequestType::Image);
m_condition.notify_all();
}
void ImageCache::requestIcon(Utils::PathString name,
ImageCache::CaptureCallback captureCallback,
ImageCache::AbortCallback abortCallback)
{
addEntry(std::move(name), std::move(captureCallback), std::move(abortCallback), RequestType::Icon);
m_condition.notify_all();
}
void ImageCache::clean()
{
clearEntries();
m_generator.clean();
}
std::tuple<bool, ImageCache::Entry> ImageCache::getEntry()
{
std::unique_lock lock{m_mutex};
if (m_entries.empty())
return {false, Entry{}};
Entry entry = m_entries.back();
m_entries.pop_back();
return {true, entry};
}
void ImageCache::addEntry(Utils::PathString &&name,
ImageCache::CaptureCallback &&captureCallback,
AbortCallback &&abortCallback,
RequestType requestType)
{
std::unique_lock lock{m_mutex};
m_entries.emplace_back(std::move(name),
std::move(captureCallback),
std::move(abortCallback),
requestType);
}
void ImageCache::clearEntries()
{
std::unique_lock lock{m_mutex};
for (Entry &entry : m_entries)
entry.abortCallback();
m_entries.clear();
}
void ImageCache::waitForEntries()
{
std::unique_lock lock{m_mutex};
if (m_entries.empty())
m_condition.wait(lock, [&] { return m_entries.size() || m_finishing; });
}
void ImageCache::stopThread()
{
std::unique_lock lock{m_mutex};
m_finishing = true;
}
bool ImageCache::isRunning()
{
std::unique_lock lock{m_mutex};
return !m_finishing;
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,117 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "imagecachecollector.h"
#include "imagecacheconnectionmanager.h"
#include <metainfo.h>
#include <model.h>
#include <nodeinstanceview.h>
#include <plaintexteditmodifier.h>
#include <rewriterview.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <utils/fileutils.h>
#include <QPlainTextEdit>
namespace QmlDesigner {
namespace {
QByteArray fileToByteArray(QString const &filename)
{
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
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager)
: m_connectionManager{connectionManager}
{}
ImageCacheCollector::~ImageCacheCollector() = default;
void ImageCacheCollector::start(Utils::SmallStringView name,
CaptureCallback captureCallback,
AbortCallback abortCallback)
{
RewriterView rewriterView{RewriterView::Amend, nullptr};
NodeInstanceView nodeInstanceView{m_connectionManager};
const QString filePath{name};
std::unique_ptr<Model> model{QmlDesigner::Model::create("QtQuick/Item", 2, 1)};
model->setFileUrl(QUrl::fromLocalFile(filePath));
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);
if (rewriterView.inErrorState() || !rewriterView.rootModelNode().metaInfo().isGraphicalItem()) {
abortCallback();
return;
}
m_connectionManager.setCallback(std::move(captureCallback));
nodeInstanceView.setTarget(m_target.get());
nodeInstanceView.setCrashCallback(abortCallback);
model->setNodeInstanceView(&nodeInstanceView);
bool capturedDataArrived = m_connectionManager.waitForCapturedData();
m_connectionManager.setCallback({});
m_connectionManager.setCrashCallback({});
model->setNodeInstanceView({});
model->setRewriterView({});
if (!capturedDataArrived)
abortCallback();
}
void ImageCacheCollector::setTarget(std::unique_ptr<ProjectExplorer::Target> target)
{
m_target = std::move(target);
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,66 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "imagecachecollectorinterface.h"
#include <memory>
QT_BEGIN_NAMESPACE
class QTextDocument;
QT_END_NAMESPACE
namespace ProjectExplorer {
class Target;
}
namespace QmlDesigner {
class Model;
class NotIndentingTextEditModifier;
class ImageCacheConnectionManager;
class RewriterView;
class NodeInstanceView;
class ImageCacheCollector final : public ImageCacheCollectorInterface
{
public:
ImageCacheCollector(ImageCacheConnectionManager &connectionManager);
~ImageCacheCollector();
void start(Utils::SmallStringView filePath,
CaptureCallback captureCallback,
AbortCallback abortCallback) override;
void setTarget(std::unique_ptr<ProjectExplorer::Target> target);
private:
ImageCacheConnectionManager &m_connectionManager;
std::unique_ptr<ProjectExplorer::Target> m_target;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,48 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <utils/smallstringview.h>
#include <QImage>
namespace QmlDesigner {
class ImageCacheCollectorInterface
{
public:
using CaptureCallback = std::function<void(QImage &&image)>;
using AbortCallback = std::function<void()>;
virtual void start(Utils::SmallStringView filePath,
CaptureCallback captureCallback,
AbortCallback abortCallback)
= 0;
protected:
~ImageCacheCollectorInterface() = default;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,68 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
****************************************************************************/
#include "imagecacheconnectionmanager.h"
#include <captureddatacommand.h>
#include <QLocalSocket>
namespace QmlDesigner {
ImageCacheConnectionManager::ImageCacheConnectionManager()
{
connections().emplace_back("Capture icon", "captureiconmode");
}
void ImageCacheConnectionManager::setCallback(ImageCacheConnectionManager::Callback callback)
{
m_captureCallback = std::move(callback);
}
bool ImageCacheConnectionManager::waitForCapturedData()
{
if (connections().empty())
return false;
disconnect(connections().front().socket.get(), &QIODevice::readyRead, nullptr, nullptr);
while (!m_capturedDataArrived) {
bool dataArrived = connections().front().socket->waitForReadyRead(600000);
if (!dataArrived)
return false;
readDataStream(connections().front());
}
m_capturedDataArrived = false;
return true;
}
void ImageCacheConnectionManager::dispatchCommand(const QVariant &command,
ConnectionManagerInterface::Connection &)
{
static const int capturedDataCommandType = QMetaType::type("CapturedDataCommand");
if (command.userType() == capturedDataCommandType) {
m_captureCallback(command.value<CapturedDataCommand>().image);
m_capturedDataArrived = true;
}
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,45 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
****************************************************************************/
#pragma once
#include <designercore/instances/connectionmanager.h>
namespace QmlDesigner {
class CapturedDataCommand;
class ImageCacheConnectionManager : public ConnectionManager
{
public:
using Callback = std::function<void(QImage &&)>;
ImageCacheConnectionManager();
void setCallback(Callback captureCallback);
bool waitForCapturedData();
protected:
void dispatchCommand(const QVariant &command, Connection &connection) override;
private:
Callback m_captureCallback;
bool m_capturedDataArrived = false;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,159 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "imagecachegenerator.h"
#include "imagecachecollectorinterface.h"
#include "imagecachestorage.h"
#include <QThread>
namespace QmlDesigner {
ImageCacheGenerator::~ImageCacheGenerator()
{
std::lock_guard threadLock{*m_threadMutex.get()};
if (m_backgroundThread)
m_backgroundThread->wait();
clean();
}
void ImageCacheGenerator::generateImage(Utils::SmallStringView name,
Sqlite::TimeStamp timeStamp,
ImageCacheGeneratorInterface::CaptureCallback &&captureCallback,
AbortCallback &&abortCallback)
{
{
std::lock_guard lock{m_dataMutex};
m_tasks.emplace_back(name, timeStamp, std::move(captureCallback), std::move(abortCallback));
}
startGenerationAsynchronously();
}
void ImageCacheGenerator::clean()
{
std::lock_guard dataLock{m_dataMutex};
m_tasks.clear();
}
class ReleaseProcessing
{
public:
ReleaseProcessing(std::atomic_flag &processing)
: m_processing(processing)
{
m_processing.test_and_set(std::memory_order_acquire);
}
~ReleaseProcessing() { m_processing.clear(std::memory_order_release); }
private:
std::atomic_flag &m_processing;
};
void ImageCacheGenerator::startGeneration(std::shared_ptr<std::mutex> threadMutex)
{
ReleaseProcessing guard(m_processing);
while (true) {
Task task;
{
std::unique_lock threadLock{*threadMutex.get(), std::defer_lock_t{}};
if (!threadLock.try_lock())
return;
std::lock_guard dataLock{m_dataMutex};
if (m_tasks.empty()) {
m_storage.walCheckpointFull();
return;
}
task = std::move(m_tasks.back());
m_tasks.pop_back();
}
m_collector.start(
task.filePath,
[this, threadMutex, task](QImage &&image) {
std::unique_lock lock{*threadMutex.get(), std::defer_lock_t{}};
if (!lock.try_lock())
return;
if (threadMutex.use_count() == 1)
return;
if (image.isNull())
task.abortCallback();
else
task.captureCallback(image);
m_storage.storeImage(std::move(task.filePath), task.timeStamp, image);
},
[this, threadMutex, task] {
std::unique_lock lock{*threadMutex.get(), std::defer_lock_t{}};
if (!lock.try_lock())
return;
if (threadMutex.use_count() == 1)
return;
task.abortCallback();
m_storage.storeImage(std::move(task.filePath), task.timeStamp, {});
});
}
}
void ImageCacheGenerator::startGenerationAsynchronously()
{
if (m_processing.test_and_set(std::memory_order_acquire))
return;
std::unique_lock lock{*m_threadMutex.get(), std::defer_lock_t{}};
if (!lock.try_lock())
return;
if (m_backgroundThread)
m_backgroundThread->wait();
m_backgroundThread.reset(QThread::create(
[this](std::shared_ptr<std::mutex> threadMutex) { startGeneration(threadMutex); },
m_threadMutex));
m_backgroundThread->start();
// m_backgroundThread = std::thread(
// [this](std::shared_ptr<std::mutex> threadMutex) { startGeneration(threadMutex); },
// m_threadMutex);
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,95 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "imagecachegeneratorinterface.h"
#include <utils/smallstring.h>
#include <QThread>
#include <memory>
#include <mutex>
QT_BEGIN_NAMESPACE
class QPlainTextEdit;
QT_END_NAMESPACE
namespace QmlDesigner {
class ImageCacheCollectorInterface;
class ImageCacheStorageInterface;
class ImageCacheGenerator final : public ImageCacheGeneratorInterface
{
public:
ImageCacheGenerator(ImageCacheCollectorInterface &collector, ImageCacheStorageInterface &storage)
: m_collector{collector}
, m_storage(storage)
{}
~ImageCacheGenerator();
void generateImage(Utils::SmallStringView filePath,
Sqlite::TimeStamp timeStamp,
CaptureCallback &&captureCallback,
AbortCallback &&abortCallback) override;
void clean() override;
private:
struct Task
{
Task() = default;
Task(Utils::SmallStringView filePath,
Sqlite::TimeStamp timeStamp,
CaptureCallback &&captureCallback,
AbortCallback &&abortCallback)
: filePath(filePath)
, captureCallback(std::move(captureCallback))
, abortCallback(std::move(abortCallback))
, timeStamp(timeStamp)
{}
Utils::PathString filePath;
CaptureCallback captureCallback;
AbortCallback abortCallback;
Sqlite::TimeStamp timeStamp;
};
void startGeneration(std::shared_ptr<std::mutex> threadMutex);
void startGenerationAsynchronously();
private:
std::unique_ptr<QThread> m_backgroundThread;
std::mutex m_dataMutex;
std::shared_ptr<std::mutex> m_threadMutex{std::make_shared<std::mutex>()};
std::vector<Task> m_tasks;
ImageCacheCollectorInterface &m_collector;
ImageCacheStorageInterface &m_storage;
std::atomic_flag m_processing = ATOMIC_FLAG_INIT;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,53 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <sqlitetimestamp.h>
#include <utils/smallstringview.h>
#include <QImage>
namespace QmlDesigner {
class ImageCacheGeneratorInterface
{
public:
using CaptureCallback = std::function<void(const QImage &image)>;
using AbortCallback = std::function<void()>;
virtual void generateImage(Utils::SmallStringView name,
Sqlite::TimeStamp timeStamp,
CaptureCallback &&captureCallback,
AbortCallback &&abortCallback)
= 0;
virtual void clean() = 0;
protected:
~ImageCacheGeneratorInterface() = default;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,197 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "imagecachestorageinterface.h"
#include <createtablesqlstatementbuilder.h>
#include <sqliteblob.h>
#include <sqlitereadstatement.h>
#include <sqlitetable.h>
#include <sqlitetransaction.h>
#include <sqlitewritestatement.h>
#include <QBuffer>
#include <QImageReader>
#include <QImageWriter>
namespace QmlDesigner {
template<typename DatabaseType>
class ImageCacheStorage : public ImageCacheStorageInterface
{
public:
using ReadStatement = typename DatabaseType::ReadStatement;
using WriteStatement = typename DatabaseType::WriteStatement;
ImageCacheStorage(DatabaseType &database)
: database(database)
{
transaction.commit();
}
Entry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
{
try {
Sqlite::DeferredTransaction transaction{database};
auto optionalBlob = selectImageStatement.template value<Sqlite::ByteArrayBlob>(
name, minimumTimeStamp.value);
transaction.commit();
if (optionalBlob) {
QBuffer buffer{&optionalBlob->byteArray};
QImageReader reader{&buffer, "PNG"};
return Entry{reader.read(), true};
}
return {};
} catch (const Sqlite::StatementIsBusy &) {
return fetchImage(name, minimumTimeStamp);
}
}
Entry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
{
try {
Sqlite::DeferredTransaction transaction{database};
auto optionalBlob = selectIconStatement.template value<Sqlite::ByteArrayBlob>(
name, minimumTimeStamp.value);
transaction.commit();
if (optionalBlob) {
QBuffer buffer{&optionalBlob->byteArray};
QImageReader reader{&buffer, "PNG"};
return Entry{reader.read(), true};
}
return {};
} catch (const Sqlite::StatementIsBusy &) {
return fetchIcon(name, minimumTimeStamp);
}
}
void storeImage(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QImage &image) override
{
try {
Sqlite::ImmediateTransaction transaction{database};
if (image.isNull()) {
upsertImageStatement.write(name,
newTimeStamp.value,
Sqlite::NullValue{},
Sqlite::NullValue{});
} else {
QSize iconSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
Qt::KeepAspectRatio);
QImage icon = image.scaled(iconSize);
upsertImageStatement.write(name,
newTimeStamp.value,
Sqlite::BlobView{createImageBuffer(image)->data()},
Sqlite::BlobView{createImageBuffer(icon)->data()});
}
transaction.commit();
} catch (const Sqlite::StatementIsBusy &) {
return storeImage(name, newTimeStamp, image);
}
}
void walCheckpointFull()
{
try {
database.walCheckpointFull();
} catch (const Sqlite::StatementIsBusy &) {
return walCheckpointFull();
}
}
private:
class Initializer
{
public:
Initializer(DatabaseType &database)
{
if (!database.isInitialized()) {
Sqlite::ExclusiveTransaction transaction{database};
createImagesTable(database);
transaction.commit();
database.setIsInitialized(true);
database.walCheckpointFull();
}
}
void createImagesTable(DatabaseType &database)
{
Sqlite::Table table;
table.setUseIfNotExists(true);
table.setName("images");
table.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
table.addColumn("name", Sqlite::ColumnType::Text, {Sqlite::NotNull{}, Sqlite::Unique{}});
table.addColumn("mtime", Sqlite::ColumnType::Integer);
table.addColumn("image", Sqlite::ColumnType::Blob);
table.addColumn("icon", Sqlite::ColumnType::Blob);
table.initialize(database);
}
};
std::unique_ptr<QBuffer> createImageBuffer(const QImage &image)
{
auto buffer = std::make_unique<QBuffer>();
buffer->open(QIODevice::WriteOnly);
QImageWriter writer{buffer.get(), "PNG"};
writer.write(image);
return buffer;
}
public:
DatabaseType &database;
Initializer initializer{database};
Sqlite::ImmediateNonThrowingDestructorTransaction transaction{database};
mutable ReadStatement selectImageStatement{
"SELECT image FROM images WHERE name=?1 AND mtime >= ?2", database};
mutable ReadStatement selectIconStatement{
"SELECT icon FROM images WHERE name=?1 AND mtime >= ?2", database};
WriteStatement upsertImageStatement{
"INSERT INTO images(name, mtime, image, icon) VALUES (?1, ?2, ?3, ?4) ON "
"CONFLICT(name) DO UPDATE SET mtime=excluded.mtime, image=excluded.image, "
"icon=excluded.icon",
database};
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QImage>
#include <sqlitetimestamp.h>
#include <utils/smallstringview.h>
namespace QmlDesigner {
namespace Internal {
class ImageCacheStorageEntry
{
public:
QImage image;
bool hasEntry = false;
};
} // namespace Internal
class ImageCacheStorageInterface
{
public:
using Entry = Internal::ImageCacheStorageEntry;
virtual Entry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const = 0;
virtual Entry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const = 0;
virtual void storeImage(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QImage &image) = 0;
virtual void walCheckpointFull() = 0;
protected:
~ImageCacheStorageInterface() = default;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,38 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "timestampprovider.h"
#include <QDateTime>
#include <QFileInfo>
namespace QmlDesigner {
Sqlite::TimeStamp TimeStampProvider::timeStamp(Utils::SmallStringView name) const
{
return QFileInfo{QString{name}}.lastModified().toSecsSinceEpoch();
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,39 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "timestampproviderinterface.h"
namespace QmlDesigner {
class TimeStampProvider : public TimeStampProviderInterface
{
public:
Sqlite::TimeStamp timeStamp(Utils::SmallStringView name) const override;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,44 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <sqlitetimestamp.h>
#include <utils/smallstringview.h>
#include <QImage>
namespace QmlDesigner {
class TimeStampProviderInterface
{
public:
virtual Sqlite::TimeStamp timeStamp(Utils::SmallStringView name) const = 0;
protected:
~TimeStampProviderInterface() = default;
};
} // namespace QmlDesigner

View File

@@ -49,6 +49,9 @@ public:
bool renameId(const QString &oldId, const QString &newId) override; bool renameId(const QString &oldId, const QString &newId) override;
bool moveToComponent(int nodeOffset) override; bool moveToComponent(int nodeOffset) override;
QStringList autoComplete(QTextDocument *textDocument, int position, bool explicitComplete) override; QStringList autoComplete(QTextDocument *textDocument, int position, bool explicitComplete) override;
private:
TextEditor::TextEditorWidget *m_textEdit;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -0,0 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
namespace QmlDesigner {
class FileSystemFacadeInterface
{
public:
protected:
~FileSystemFacadeInterface() = default;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,113 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <utils/smallstring.h>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
#include <QImage>
namespace QmlDesigner {
class TimeStampProviderInterface;
class ImageCacheStorageInterface;
class ImageCacheGeneratorInterface;
class ImageCache
{
public:
using CaptureCallback = std::function<void(const QImage &)>;
using AbortCallback = std::function<void()>;
~ImageCache();
ImageCache(ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider);
void requestImage(Utils::PathString name,
CaptureCallback captureCallback,
AbortCallback abortCallback);
void requestIcon(Utils::PathString name,
CaptureCallback captureCallback,
AbortCallback abortCallback);
void clean();
private:
enum class RequestType { Image, Icon };
struct Entry
{
Entry() = default;
Entry(Utils::PathString name,
CaptureCallback &&captureCallback,
AbortCallback &&abortCallback,
RequestType requestType)
: name{std::move(name)}
, captureCallback{std::move(captureCallback)}
, abortCallback{std::move(abortCallback)}
, requestType{requestType}
{}
Utils::PathString name;
CaptureCallback captureCallback;
AbortCallback abortCallback;
RequestType requestType = RequestType::Image;
};
std::tuple<bool, Entry> getEntry();
void addEntry(Utils::PathString &&name,
CaptureCallback &&captureCallback,
AbortCallback &&abortCallback,
RequestType requestType);
void clearEntries();
void waitForEntries();
void stopThread();
bool isRunning();
static void request(Utils::SmallStringView name,
ImageCache::RequestType requestType,
ImageCache::CaptureCallback captureCallback,
ImageCache::AbortCallback abortCallback,
ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider);
private:
std::vector<Entry> m_entries;
mutable std::mutex m_mutex;
std::condition_variable m_condition;
std::thread m_backgroundThread;
ImageCacheStorageInterface &m_storage;
ImageCacheGeneratorInterface &m_generator;
TimeStampProviderInterface &m_timeStampProvider;
bool m_finishing{false};
};
} // namespace QmlDesigner

View File

@@ -146,6 +146,11 @@ public:
QVariant previewImageDataForGenericNode(const ModelNode &modelNode, const ModelNode &renderNode); QVariant previewImageDataForGenericNode(const ModelNode &modelNode, const ModelNode &renderNode);
QVariant previewImageDataForImageNode(const ModelNode &modelNode); QVariant previewImageDataForImageNode(const ModelNode &modelNode);
void setCrashCallback(std::function<void()> crashCallback)
{
m_crashCallback = std::move(crashCallback);
}
protected: protected:
void timerEvent(QTimerEvent *event) override; void timerEvent(QTimerEvent *event) override;
@@ -231,6 +236,7 @@ private:
// key: fileUrl value: (key: instance qml id, value: related tool states) // key: fileUrl value: (key: instance qml id, value: related tool states)
QHash<QUrl, QHash<QString, QVariantMap>> m_edit3DToolStates; QHash<QUrl, QHash<QString, QVariantMap>> m_edit3DToolStates;
std::function<void()> m_crashCallback{[this] { handleCrash(); }};
}; };
} // namespace ProxyNodeInstanceView } // namespace ProxyNodeInstanceView

View File

@@ -47,6 +47,7 @@ private:
public: public:
PlainTextEditModifier(QPlainTextEdit *textEdit); PlainTextEditModifier(QPlainTextEdit *textEdit);
PlainTextEditModifier(QTextDocument *document, const QTextCursor &textCursor);
~PlainTextEditModifier() override; ~PlainTextEditModifier() override;
QTextDocument *textDocument() const override; QTextDocument *textDocument() const override;
@@ -76,20 +77,17 @@ public:
bool moveToComponent(int /* nodeOffset */) override bool moveToComponent(int /* nodeOffset */) override
{ return false; } { return false; }
protected:
QPlainTextEdit *plainTextEdit() const
{ return m_textEdit; }
private: private:
void textEditChanged(); void textEditChanged();
void runRewriting(Utils::ChangeSet *writer); void runRewriting(Utils::ChangeSet *writer);
private: private:
Utils::ChangeSet *m_changeSet; Utils::ChangeSet *m_changeSet = nullptr;
QPlainTextEdit *m_textEdit; QTextDocument *m_textDocument;
bool m_changeSignalsEnabled; QTextCursor m_textCursor;
bool m_pendingChangeSignal; bool m_changeSignalsEnabled{true};
bool m_ongoingTextChange; bool m_pendingChangeSignal{false};
bool m_ongoingTextChange{false};
}; };
class QMLDESIGNERCORE_EXPORT NotIndentingTextEditModifier: public PlainTextEditModifier class QMLDESIGNERCORE_EXPORT NotIndentingTextEditModifier: public PlainTextEditModifier
@@ -99,6 +97,10 @@ public:
: PlainTextEditModifier(textEdit) : PlainTextEditModifier(textEdit)
{} {}
NotIndentingTextEditModifier(QTextDocument *document, const QTextCursor &textCursor)
: PlainTextEditModifier{document, textCursor}
{}
void indent(int /*offset*/, int /*length*/) override void indent(int /*offset*/, int /*length*/) override
{} {}
void indentLines(int /*offset*/, int /*length*/) override void indentLines(int /*offset*/, int /*length*/) override

View File

@@ -33,11 +33,12 @@
namespace QmlDesigner { namespace QmlDesigner {
void BaseConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, void BaseConnectionManager::setUp(NodeInstanceServerInterface *nodeInstanceServer,
const QString &, const QString &,
ProjectExplorer::Target *) ProjectExplorer::Target *,
AbstractView *view)
{ {
m_nodeInstanceServerProxy = nodeInstanceServerProxy; m_nodeInstanceServer = nodeInstanceServer;
m_isActive = true; m_isActive = true;
} }
@@ -47,7 +48,14 @@ void BaseConnectionManager::shutDown()
writeCommand(QVariant::fromValue(EndPuppetCommand())); writeCommand(QVariant::fromValue(EndPuppetCommand()));
m_nodeInstanceServerProxy = nullptr; m_nodeInstanceServer = nullptr;
}
void BaseConnectionManager::setCrashCallback(std::function<void()> callback)
{
std::lock_guard<std::mutex> lock{m_callbackMutex};
m_crashCallback = std::move(callback);
} }
bool BaseConnectionManager::isActive() const bool BaseConnectionManager::isActive() const
@@ -85,7 +93,7 @@ void BaseConnectionManager::dispatchCommand(const QVariant &command, Connection
if (!isActive()) if (!isActive())
return; return;
m_nodeInstanceServerProxy->dispatchCommand(command); m_nodeInstanceServer->dispatchCommand(command);
} }
void BaseConnectionManager::readDataStream(Connection &connection) void BaseConnectionManager::readDataStream(Connection &connection)
@@ -123,5 +131,12 @@ void BaseConnectionManager::readDataStream(Connection &connection)
for (const QVariant &command : commandList) for (const QVariant &command : commandList)
dispatchCommand(command, connection); dispatchCommand(command, connection);
} }
void BaseConnectionManager::callCrashCallback()
{
std::lock_guard<std::mutex> lock{m_callbackMutex};
m_crashCallback();
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -29,6 +29,8 @@
#include <QProcess> #include <QProcess>
#include <mutex>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QLocalSocket; class QLocalSocket;
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -40,7 +42,6 @@ class Target;
namespace QmlDesigner { namespace QmlDesigner {
class AbstractView; class AbstractView;
class NodeInstanceServerProxy;
class QMLDESIGNERCORE_EXPORT BaseConnectionManager : public QObject, public ConnectionManagerInterface class QMLDESIGNERCORE_EXPORT BaseConnectionManager : public QObject, public ConnectionManagerInterface
{ {
@@ -49,11 +50,14 @@ class QMLDESIGNERCORE_EXPORT BaseConnectionManager : public QObject, public Conn
public: public:
BaseConnectionManager() = default; BaseConnectionManager() = default;
void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, void setUp(NodeInstanceServerInterface *nodeInstanceServer,
const QString &qrcMappingString, const QString &qrcMappingString,
ProjectExplorer::Target *target) override; ProjectExplorer::Target *target,
AbstractView *view) override;
void shutDown() override; void shutDown() override;
void setCrashCallback(std::function<void()> callback) override;
bool isActive() const; bool isActive() const;
protected: protected:
@@ -61,15 +65,19 @@ protected:
virtual void showCannotConnectToPuppetWarningAndSwitchToEditMode(); virtual void showCannotConnectToPuppetWarningAndSwitchToEditMode();
using ConnectionManagerInterface::processFinished; using ConnectionManagerInterface::processFinished;
void processFinished(); void processFinished();
void writeCommandToIODevice(const QVariant &command, static void writeCommandToIODevice(const QVariant &command,
QIODevice *ioDevice, QIODevice *ioDevice,
unsigned int commandCounter); unsigned int commandCounter);
void readDataStream(Connection &connection); void readDataStream(Connection &connection);
NodeInstanceServerProxy *nodeInstanceServerProxy() const { return m_nodeInstanceServerProxy; } NodeInstanceServerInterface *nodeInstanceServer() const { return m_nodeInstanceServer; }
void callCrashCallback();
private: private:
NodeInstanceServerProxy *m_nodeInstanceServerProxy{}; std::mutex m_callbackMutex;
std::function<void()> m_crashCallback;
NodeInstanceServerInterface *m_nodeInstanceServer{};
bool m_isActive = false; bool m_isActive = false;
}; };

View File

@@ -34,11 +34,12 @@
namespace QmlDesigner { namespace QmlDesigner {
void CapturingConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, void CapturingConnectionManager::setUp(NodeInstanceServerInterface *nodeInstanceServer,
const QString &qrcMappingString, const QString &qrcMappingString,
ProjectExplorer::Target *target) ProjectExplorer::Target *target,
AbstractView *view)
{ {
InteractiveConnectionManager::setUp(nodeInstanceServerProxy, qrcMappingString, target); InteractiveConnectionManager::setUp(nodeInstanceServer, qrcMappingString, target, view);
int indexOfCapturePuppetStream = QCoreApplication::arguments().indexOf( int indexOfCapturePuppetStream = QCoreApplication::arguments().indexOf(
"-capture-puppet-stream"); "-capture-puppet-stream");
@@ -72,7 +73,7 @@ void CapturingConnectionManager::writeCommand(const QVariant &command)
if (m_captureFileForTest.isWritable()) { if (m_captureFileForTest.isWritable()) {
qDebug() << "command name: " << QMetaType::typeName(command.userType()); qDebug() << "command name: " << QMetaType::typeName(command.userType());
writeCommandToIODevice(command, &m_captureFileForTest, m_writeCommandCounter); writeCommandToIODevice(command, &m_captureFileForTest, writeCommandCounter());
qDebug() << "\tcatpure file offset: " << m_captureFileForTest.pos(); qDebug() << "\tcatpure file offset: " << m_captureFileForTest.pos();
} }
} }

View File

@@ -32,9 +32,10 @@ namespace QmlDesigner {
class QMLDESIGNERCORE_EXPORT CapturingConnectionManager : public InteractiveConnectionManager class QMLDESIGNERCORE_EXPORT CapturingConnectionManager : public InteractiveConnectionManager
{ {
public: public:
void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, void setUp(NodeInstanceServerInterface *nodeInstanceServer,
const QString &qrcMappingString, const QString &qrcMappingString,
ProjectExplorer::Target *target) override; ProjectExplorer::Target *target,
AbstractView *view) override;
void processFinished(int exitCode, QProcess::ExitStatus exitStatus) override; void processFinished(int exitCode, QProcess::ExitStatus exitStatus) override;

View File

@@ -46,19 +46,19 @@ ConnectionManager::ConnectionManager() = default;
ConnectionManager::~ConnectionManager() = default; ConnectionManager::~ConnectionManager() = default;
void ConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, void ConnectionManager::setUp(NodeInstanceServerInterface *nodeInstanceServerProxy,
const QString &qrcMappingString, const QString &qrcMappingString,
ProjectExplorer::Target *target) ProjectExplorer::Target *target,
AbstractView *view)
{ {
BaseConnectionManager::setUp(nodeInstanceServerProxy, qrcMappingString, target); BaseConnectionManager::setUp(nodeInstanceServerProxy, qrcMappingString, target, view);
m_localServer = std::make_unique<QLocalServer>(); m_localServer = std::make_unique<QLocalServer>();
QString socketToken(QUuid::createUuid().toString()); QString socketToken(QUuid::createUuid().toString());
m_localServer->listen(socketToken); m_localServer->listen(socketToken);
m_localServer->setMaxPendingConnections(3); m_localServer->setMaxPendingConnections(3);
NodeInstanceView *nodeInstanceView = nodeInstanceServerProxy->nodeInstanceView(); PuppetCreator puppetCreator(target, view->model());
PuppetCreator puppetCreator(target, nodeInstanceView->model());
puppetCreator.setQrcMappingString(qrcMappingString); puppetCreator.setQrcMappingString(qrcMappingString);
puppetCreator.createQml2PuppetExecutableIfMissing(); puppetCreator.createQml2PuppetExecutableIfMissing();
@@ -67,7 +67,6 @@ void ConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
connection.qmlPuppetProcess = puppetCreator.createPuppetProcess( connection.qmlPuppetProcess = puppetCreator.createPuppetProcess(
connection.mode, connection.mode,
socketToken, socketToken,
nodeInstanceView,
[&] { printProcessOutput(connection.qmlPuppetProcess.get(), connection.name); }, [&] { printProcessOutput(connection.qmlPuppetProcess.get(), connection.name); },
[&](int exitCode, QProcess::ExitStatus exitStatus) { [&](int exitCode, QProcess::ExitStatus exitStatus) {
processFinished(exitCode, exitStatus); processFinished(exitCode, exitStatus);
@@ -90,7 +89,7 @@ void ConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
if (connectedToPuppet) { if (connectedToPuppet) {
connection.socket.reset(m_localServer->nextPendingConnection()); connection.socket.reset(m_localServer->nextPendingConnection());
QObject::connect(connection.socket.get(), &QIODevice::readyRead, [&] { QObject::connect(connection.socket.get(), &QIODevice::readyRead, this, [&] {
readDataStream(connection); readDataStream(connection);
}); });
} else { } else {
@@ -101,11 +100,6 @@ void ConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
} }
m_localServer->close(); m_localServer->close();
connect(this,
&ConnectionManager::processCrashed,
nodeInstanceServerProxy,
&NodeInstanceServerProxy::processCrashed);
} }
void ConnectionManager::shutDown() void ConnectionManager::shutDown()
@@ -143,7 +137,7 @@ void ConnectionManager::processFinished(int exitCode, QProcess::ExitStatus exitS
closeSocketsAndKillProcesses(); closeSocketsAndKillProcesses();
if (exitStatus == QProcess::CrashExit) if (exitStatus == QProcess::CrashExit)
emit processCrashed(); callCrashCallback();
} }
void ConnectionManager::closeSocketsAndKillProcesses() void ConnectionManager::closeSocketsAndKillProcesses()

View File

@@ -48,19 +48,20 @@ public:
~ConnectionManager() override; ~ConnectionManager() override;
enum PuppetStreamType { FirstPuppetStream, SecondPuppetStream, ThirdPuppetStream }; enum PuppetStreamType { FirstPuppetStream, SecondPuppetStream, ThirdPuppetStream };
void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, void setUp(NodeInstanceServerInterface *nodeInstanceServerProxy,
const QString &qrcMappingString, const QString &qrcMappingString,
ProjectExplorer::Target *target) override; ProjectExplorer::Target *target,
AbstractView *view) override;
void shutDown() override; void shutDown() override;
void writeCommand(const QVariant &command) override; void writeCommand(const QVariant &command) override;
signals:
void processCrashed();
protected: protected:
using BaseConnectionManager::processFinished; using BaseConnectionManager::processFinished;
void processFinished(int exitCode, QProcess::ExitStatus exitStatus) override; void processFinished(int exitCode, QProcess::ExitStatus exitStatus) override;
std::vector<Connection> &connections() { return m_connections; }
quint32 &writeCommandCounter() { return m_writeCommandCounter; }
private: private:
void printProcessOutput(QProcess *process, const QString &connectionName); void printProcessOutput(QProcess *process, const QString &connectionName);
@@ -69,7 +70,6 @@ private:
private: private:
std::unique_ptr<QLocalServer> m_localServer; std::unique_ptr<QLocalServer> m_localServer;
protected:
std::vector<Connection> m_connections; std::vector<Connection> m_connections;
quint32 m_writeCommandCounter = 0; quint32 m_writeCommandCounter = 0;
}; };

View File

@@ -38,7 +38,8 @@ class Target;
namespace QmlDesigner { namespace QmlDesigner {
class NodeInstanceServerProxy; class NodeInstanceServerInterface;
class AbstractView;
class QMLDESIGNERCORE_EXPORT ConnectionManagerInterface class QMLDESIGNERCORE_EXPORT ConnectionManagerInterface
{ {
@@ -65,12 +66,15 @@ public:
virtual ~ConnectionManagerInterface(); virtual ~ConnectionManagerInterface();
virtual void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, virtual void setUp(NodeInstanceServerInterface *nodeInstanceServer,
const QString &qrcMappingString, const QString &qrcMappingString,
ProjectExplorer::Target *target) ProjectExplorer::Target *target,
AbstractView *view)
= 0; = 0;
virtual void shutDown() = 0; virtual void shutDown() = 0;
virtual void setCrashCallback(std::function<void()> callback) = 0;
virtual void writeCommand(const QVariant &command) = 0; virtual void writeCommand(const QVariant &command) = 0;
protected: protected:

View File

@@ -38,20 +38,21 @@ namespace QmlDesigner {
InteractiveConnectionManager::InteractiveConnectionManager() InteractiveConnectionManager::InteractiveConnectionManager()
{ {
m_connections.emplace_back("Editor", "editormode"); connections().emplace_back("Editor", "editormode");
m_connections.emplace_back("Render", "rendermode"); connections().emplace_back("Render", "rendermode");
m_connections.emplace_back("Preview", "previewmode"); connections().emplace_back("Preview", "previewmode");
} }
void InteractiveConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, void InteractiveConnectionManager::setUp(NodeInstanceServerInterface *nodeInstanceServer,
const QString &qrcMappingString, const QString &qrcMappingString,
ProjectExplorer::Target *target) ProjectExplorer::Target *target,
AbstractView *view)
{ {
ConnectionManager::setUp(nodeInstanceServerProxy, qrcMappingString, target); ConnectionManager::setUp(nodeInstanceServer, qrcMappingString, target, view);
DesignerSettings settings = QmlDesignerPlugin::instance()->settings(); DesignerSettings settings = QmlDesignerPlugin::instance()->settings();
int timeOutTime = settings.value(DesignerSettingsKey::PUPPET_KILL_TIMEOUT).toInt(); int timeOutTime = settings.value(DesignerSettingsKey::PUPPET_KILL_TIMEOUT).toInt();
for (Connection &connection : m_connections) for (Connection &connection : connections())
connection.timer->setInterval(timeOutTime); connection.timer->setInterval(timeOutTime);
if (QmlDesignerPlugin::instance() if (QmlDesignerPlugin::instance()
@@ -59,7 +60,7 @@ void InteractiveConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceSe
.value(DesignerSettingsKey::DEBUG_PUPPET) .value(DesignerSettingsKey::DEBUG_PUPPET)
.toString() .toString()
.isEmpty()) { .isEmpty()) {
for (Connection &connection : m_connections) { for (Connection &connection : connections()) {
QObject::connect(connection.timer.get(), &QTimer::timeout, [&]() { QObject::connect(connection.timer.get(), &QTimer::timeout, [&]() {
puppetTimeout(connection); puppetTimeout(connection);
}); });
@@ -67,6 +68,12 @@ void InteractiveConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceSe
} }
} }
void InteractiveConnectionManager::shutDown()
{
m_view = {};
ConnectionManager::shutDown();
}
void InteractiveConnectionManager::showCannotConnectToPuppetWarningAndSwitchToEditMode() void InteractiveConnectionManager::showCannotConnectToPuppetWarningAndSwitchToEditMode()
{ {
Core::AsynchronousMessageBox::warning( Core::AsynchronousMessageBox::warning(
@@ -75,8 +82,8 @@ void InteractiveConnectionManager::showCannotConnectToPuppetWarningAndSwitchToEd
"Switching to another kit might help.")); "Switching to another kit might help."));
QmlDesignerPlugin::instance()->switchToTextModeDeferred(); QmlDesignerPlugin::instance()->switchToTextModeDeferred();
nodeInstanceServerProxy()->nodeInstanceView()->emitDocumentMessage( if (m_view)
tr("Cannot Connect to QML Emulation Layer (QML Puppet)")); m_view->emitDocumentMessage(tr("Cannot Connect to QML Emulation Layer (QML Puppet)"));
} }
void InteractiveConnectionManager::dispatchCommand(const QVariant &command, Connection &connection) void InteractiveConnectionManager::dispatchCommand(const QVariant &command, Connection &connection)

View File

@@ -34,9 +34,12 @@ class InteractiveConnectionManager : public ConnectionManager
public: public:
InteractiveConnectionManager(); InteractiveConnectionManager();
void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy, void setUp(NodeInstanceServerInterface *nodeInstanceServer,
const QString &qrcMappingString, const QString &qrcMappingString,
ProjectExplorer::Target *target) override; ProjectExplorer::Target *target,
AbstractView *view) override;
void shutDown() override;
void showCannotConnectToPuppetWarningAndSwitchToEditMode() override; void showCannotConnectToPuppetWarningAndSwitchToEditMode() override;
@@ -46,6 +49,9 @@ protected:
private: private:
void puppetTimeout(Connection &connection); void puppetTimeout(Connection &connection);
void puppetAlive(Connection &connection); void puppetAlive(Connection &connection);
private:
AbstractView *m_view{};
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -100,7 +100,7 @@ NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceV
if (instanceViewBenchmark().isInfoEnabled()) if (instanceViewBenchmark().isInfoEnabled())
m_benchmarkTimer.start(); m_benchmarkTimer.start();
m_connectionManager.setUp(this, qrcMappingString(), target); m_connectionManager.setUp(this, qrcMappingString(), target, nodeInstanceView);
qCInfo(instanceViewBenchmark) << "puppets setup:" << m_benchmarkTimer.elapsed(); qCInfo(instanceViewBenchmark) << "puppets setup:" << m_benchmarkTimer.elapsed();
} }

View File

@@ -84,6 +84,7 @@ public:
void requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command) override; void requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command) override;
void changeLanguage(const ChangeLanguageCommand &command) override; void changeLanguage(const ChangeLanguageCommand &command) override;
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override; void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
void dispatchCommand(const QVariant &command) override;
NodeInstanceView *nodeInstanceView() const { return m_nodeInstanceView; } NodeInstanceView *nodeInstanceView() const { return m_nodeInstanceView; }
@@ -91,12 +92,8 @@ public:
protected: protected:
void writeCommand(const QVariant &command); void writeCommand(const QVariant &command);
void dispatchCommand(const QVariant &command);
NodeInstanceClientInterface *nodeInstanceClient() const; NodeInstanceClientInterface *nodeInstanceClient() const;
signals:
void processCrashed();
private: private:
NodeInstanceView *m_nodeInstanceView{}; NodeInstanceView *m_nodeInstanceView{};
QElapsedTimer m_benchmarkTimer; QElapsedTimer m_benchmarkTimer;

View File

@@ -196,10 +196,7 @@ void NodeInstanceView::modelAttached(Model *model)
AbstractView::modelAttached(model); AbstractView::modelAttached(model);
m_nodeInstanceServer = createNodeInstanceServerProxy(); m_nodeInstanceServer = createNodeInstanceServerProxy();
m_lastCrashTime.start(); m_lastCrashTime.start();
connect(m_nodeInstanceServer.get(), m_connectionManager.setCrashCallback(m_crashCallback);
&NodeInstanceServerProxy::processCrashed,
this,
&NodeInstanceView::handleCrash);
if (!isSkippedRootNode(rootModelNode())) { if (!isSkippedRootNode(rootModelNode())) {
m_nodeInstanceServer->createScene(createCreateSceneCommand()); m_nodeInstanceServer->createScene(createCreateSceneCommand());
@@ -215,6 +212,8 @@ void NodeInstanceView::modelAttached(Model *model)
void NodeInstanceView::modelAboutToBeDetached(Model * model) void NodeInstanceView::modelAboutToBeDetached(Model * model)
{ {
m_connectionManager.setCrashCallback({});
removeAllInstanceNodeRelationships(); removeAllInstanceNodeRelationships();
if (m_nodeInstanceServer) { if (m_nodeInstanceServer) {
m_nodeInstanceServer->clearScene(createClearSceneCommand()); m_nodeInstanceServer->clearScene(createClearSceneCommand());
@@ -281,11 +280,6 @@ void NodeInstanceView::restartProcess()
m_nodeInstanceServer.reset(); m_nodeInstanceServer.reset();
m_nodeInstanceServer = createNodeInstanceServerProxy(); m_nodeInstanceServer = createNodeInstanceServerProxy();
connect(m_nodeInstanceServer.get(),
&NodeInstanceServerProxy::processCrashed,
this,
&NodeInstanceView::handleCrash);
if (!isSkippedRootNode(rootModelNode())) { if (!isSkippedRootNode(rootModelNode())) {
m_nodeInstanceServer->createScene(createCreateSceneCommand()); m_nodeInstanceServer->createScene(createCreateSceneCommand());
m_nodeInstanceServer->changeSelection( m_nodeInstanceServer->changeSelection(

View File

@@ -181,7 +181,6 @@ PuppetCreator::PuppetCreator(ProjectExplorer::Target *target, const Model *model
QProcessUniquePointer PuppetCreator::createPuppetProcess( QProcessUniquePointer PuppetCreator::createPuppetProcess(
const QString &puppetMode, const QString &puppetMode,
const QString &socketToken, const QString &socketToken,
QObject *handlerObject,
std::function<void()> processOutputCallback, std::function<void()> processOutputCallback,
std::function<void(int, QProcess::ExitStatus)> processFinishCallback, std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const const QStringList &customOptions) const
@@ -190,7 +189,6 @@ QProcessUniquePointer PuppetCreator::createPuppetProcess(
qmlPuppetDirectory(m_availablePuppetType), qmlPuppetDirectory(m_availablePuppetType),
puppetMode, puppetMode,
socketToken, socketToken,
handlerObject,
processOutputCallback, processOutputCallback,
processFinishCallback, processFinishCallback,
customOptions); customOptions);
@@ -201,7 +199,6 @@ QProcessUniquePointer PuppetCreator::puppetProcess(
const QString &workingDirectory, const QString &workingDirectory,
const QString &puppetMode, const QString &puppetMode,
const QString &socketToken, const QString &socketToken,
QObject *handlerObject,
std::function<void()> processOutputCallback, std::function<void()> processOutputCallback,
std::function<void(int, QProcess::ExitStatus)> processFinishCallback, std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const const QStringList &customOptions) const
@@ -216,7 +213,6 @@ QProcessUniquePointer PuppetCreator::puppetProcess(
&QProcess::kill); &QProcess::kill);
QObject::connect(puppetProcess.get(), QObject::connect(puppetProcess.get(),
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
handlerObject,
processFinishCallback); processFinishCallback);
#ifndef QMLDESIGNER_TEST #ifndef QMLDESIGNER_TEST
@@ -227,7 +223,7 @@ QProcessUniquePointer PuppetCreator::puppetProcess(
#endif #endif
if (forwardOutput == puppetMode || forwardOutput == "all") { if (forwardOutput == puppetMode || forwardOutput == "all") {
puppetProcess->setProcessChannelMode(QProcess::MergedChannels); puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
QObject::connect(puppetProcess.get(), &QProcess::readyRead, handlerObject, processOutputCallback); QObject::connect(puppetProcess.get(), &QProcess::readyRead, processOutputCallback);
} }
puppetProcess->setWorkingDirectory(workingDirectory); puppetProcess->setWorkingDirectory(workingDirectory);

View File

@@ -58,7 +58,6 @@ public:
QProcessUniquePointer createPuppetProcess( QProcessUniquePointer createPuppetProcess(
const QString &puppetMode, const QString &puppetMode,
const QString &socketToken, const QString &socketToken,
QObject *handlerObject,
std::function<void()> processOutputCallback, std::function<void()> processOutputCallback,
std::function<void(int, QProcess::ExitStatus)> processFinishCallback, std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions = {}) const; const QStringList &customOptions = {}) const;
@@ -89,7 +88,6 @@ protected:
const QString &workingDirectory, const QString &workingDirectory,
const QString &puppetMode, const QString &puppetMode,
const QString &socketToken, const QString &socketToken,
QObject *handlerObject,
std::function<void()> processOutputCallback, std::function<void()> processOutputCallback,
std::function<void(int, QProcess::ExitStatus)> processFinishCallback, std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const; const QStringList &customOptions) const;

View File

@@ -38,8 +38,9 @@
using namespace QmlDesigner; using namespace QmlDesigner;
BaseTextEditModifier::BaseTextEditModifier(TextEditor::TextEditorWidget *textEdit): BaseTextEditModifier::BaseTextEditModifier(TextEditor::TextEditorWidget *textEdit)
PlainTextEditModifier(textEdit) : PlainTextEditModifier(textEdit)
, m_textEdit{textEdit}
{ {
} }
@@ -47,21 +48,20 @@ void BaseTextEditModifier::indentLines(int startLine, int endLine)
{ {
if (startLine < 0) if (startLine < 0)
return; return;
auto baseTextEditorWidget = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit());
if (!baseTextEditorWidget) if (!m_textEdit)
return; return;
QTextDocument *textDocument = plainTextEdit()->document(); TextEditor::TextDocument *baseTextEditorDocument = m_textEdit->textDocument();
TextEditor::TextDocument *baseTextEditorDocument = baseTextEditorWidget->textDocument();
TextEditor::TabSettings tabSettings = baseTextEditorDocument->tabSettings(); TextEditor::TabSettings tabSettings = baseTextEditorDocument->tabSettings();
QTextCursor tc(textDocument); QTextCursor tc(textDocument());
tc.beginEditBlock(); tc.beginEditBlock();
for (int i = startLine; i <= endLine; i++) { for (int i = startLine; i <= endLine; i++) {
QTextBlock start = textDocument->findBlockByNumber(i); QTextBlock start = textDocument()->findBlockByNumber(i);
if (start.isValid()) { if (start.isValid()) {
QmlJSEditor::Internal::Indenter indenter(textDocument); QmlJSEditor::Internal::Indenter indenter(textDocument());
indenter.indentBlock(start, QChar::Null, tabSettings); indenter.indentBlock(start, QChar::Null, tabSettings);
} }
} }
@@ -82,22 +82,23 @@ void BaseTextEditModifier::indent(int offset, int length)
int BaseTextEditModifier::indentDepth() const int BaseTextEditModifier::indentDepth() const
{ {
if (auto bte = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit())) if (m_textEdit)
return bte->textDocument()->tabSettings().m_indentSize; return m_textEdit->textDocument()->tabSettings().m_indentSize;
else else
return 0; return 0;
} }
bool BaseTextEditModifier::renameId(const QString &oldId, const QString &newId) bool BaseTextEditModifier::renameId(const QString &oldId, const QString &newId)
{ {
if (auto bte = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit())) { if (m_textEdit) {
if (auto document = qobject_cast<QmlJSEditor::QmlJSEditorDocument *>(bte->textDocument())) { if (auto document = qobject_cast<QmlJSEditor::QmlJSEditorDocument *>(
m_textEdit->textDocument())) {
Utils::ChangeSet changeSet; Utils::ChangeSet changeSet;
foreach (const QmlJS::SourceLocation &loc, foreach (const QmlJS::SourceLocation &loc,
document->semanticInfo().idLocations.value(oldId)) { document->semanticInfo().idLocations.value(oldId)) {
changeSet.replace(loc.begin(), loc.end(), newId); changeSet.replace(loc.begin(), loc.end(), newId);
} }
QTextCursor tc = bte->textCursor(); QTextCursor tc = textCursor();
changeSet.apply(&tc); changeSet.apply(&tc);
return true; return true;
} }
@@ -120,10 +121,9 @@ static QmlJS::AST::UiObjectDefinition *getObjectDefinition(const QList<QmlJS::AS
bool BaseTextEditModifier::moveToComponent(int nodeOffset) bool BaseTextEditModifier::moveToComponent(int nodeOffset)
{ {
if (auto bte = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit())) { if (m_textEdit) {
if (auto document if (auto document = qobject_cast<QmlJSEditor::QmlJSEditorDocument *>(
= qobject_cast<QmlJSEditor::QmlJSEditorDocument *>(bte->textDocument())) { m_textEdit->textDocument())) {
auto qualifiedId = QmlJS::AST::cast<QmlJS::AST::UiQualifiedId *>(document->semanticInfo().astNodeAt(nodeOffset)); auto qualifiedId = QmlJS::AST::cast<QmlJS::AST::UiQualifiedId *>(document->semanticInfo().astNodeAt(nodeOffset));
QList<QmlJS::AST::Node *> path = document->semanticInfo().rangePath(nodeOffset); QList<QmlJS::AST::Node *> path = document->semanticInfo().rangePath(nodeOffset);
QmlJS::AST::UiObjectDefinition *object = getObjectDefinition(path, qualifiedId); QmlJS::AST::UiObjectDefinition *object = getObjectDefinition(path, qualifiedId);
@@ -140,9 +140,9 @@ bool BaseTextEditModifier::moveToComponent(int nodeOffset)
QStringList BaseTextEditModifier::autoComplete(QTextDocument *textDocument, int position, bool explicitComplete) QStringList BaseTextEditModifier::autoComplete(QTextDocument *textDocument, int position, bool explicitComplete)
{ {
if (auto bte = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit())) if (m_textEdit)
if (auto document if (auto document = qobject_cast<QmlJSEditor::QmlJSEditorDocument *>(
= qobject_cast<QmlJSEditor::QmlJSEditorDocument *>(bte->textDocument())) m_textEdit->textDocument()))
return QmlJSEditor::qmlJSAutoComplete(textDocument, return QmlJSEditor::qmlJSAutoComplete(textDocument,
position, position,
document->filePath(), document->filePath(),

View File

@@ -35,19 +35,17 @@
using namespace Utils; using namespace Utils;
using namespace QmlDesigner; using namespace QmlDesigner;
PlainTextEditModifier::PlainTextEditModifier(QPlainTextEdit *textEdit): PlainTextEditModifier::PlainTextEditModifier(QPlainTextEdit *textEdit)
m_changeSet(nullptr), : PlainTextEditModifier(textEdit->document(), textEdit->textCursor())
m_textEdit(textEdit),
m_changeSignalsEnabled(true),
m_pendingChangeSignal(false),
m_ongoingTextChange(false)
{ {
Q_ASSERT(textEdit); connect(textEdit, &QPlainTextEdit::textChanged, this, &PlainTextEditModifier::textEditChanged);
connect(m_textEdit, &QPlainTextEdit::textChanged,
this, &PlainTextEditModifier::textEditChanged);
} }
PlainTextEditModifier::PlainTextEditModifier(QTextDocument *document, const QTextCursor &textCursor)
: m_textDocument{document}
, m_textCursor{textCursor}
{}
PlainTextEditModifier::~PlainTextEditModifier() = default; PlainTextEditModifier::~PlainTextEditModifier() = default;
void PlainTextEditModifier::replace(int offset, int length, const QString &replacement) void PlainTextEditModifier::replace(int offset, int length, const QString &replacement)
@@ -158,17 +156,17 @@ void PlainTextEditModifier::runRewriting(ChangeSet *changeSet)
QTextDocument *PlainTextEditModifier::textDocument() const QTextDocument *PlainTextEditModifier::textDocument() const
{ {
return m_textEdit->document(); return m_textDocument;
} }
QString PlainTextEditModifier::text() const QString PlainTextEditModifier::text() const
{ {
return m_textEdit->toPlainText(); return m_textDocument->toPlainText();
} }
QTextCursor PlainTextEditModifier::textCursor() const QTextCursor PlainTextEditModifier::textCursor() const
{ {
return m_textEdit->textCursor(); return m_textCursor;
} }
void PlainTextEditModifier::deactivateChangeSignals() void PlainTextEditModifier::deactivateChangeSignals()

View File

@@ -3,7 +3,8 @@ QTC_LIB_DEPENDS += \
utils \ utils \
qmljs \ qmljs \
qmleditorwidgets \ qmleditorwidgets \
advanceddockingsystem advanceddockingsystem \
sqlite
QTC_PLUGIN_DEPENDS += \ QTC_PLUGIN_DEPENDS += \
coreplugin \ coreplugin \
texteditor \ texteditor \

View File

@@ -35,6 +35,7 @@ include(components/annotationeditor/annotationeditor.pri)
include(components/richtexteditor/richtexteditor.pri) include(components/richtexteditor/richtexteditor.pri)
include(components/transitioneditor/transitioneditor.pri) include(components/transitioneditor/transitioneditor.pri)
include(components/listmodeleditor/listmodeleditor.pri) include(components/listmodeleditor/listmodeleditor.pri)
include(components/previewtooltip/previewtooltipbackend.pri)
BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH) BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH)
!isEmpty(BUILD_PUPPET_IN_CREATOR_BINPATH) { !isEmpty(BUILD_PUPPET_IN_CREATOR_BINPATH) {

View File

@@ -27,6 +27,7 @@ Project {
Depends { name: "LanguageUtils" } Depends { name: "LanguageUtils" }
Depends { name: "QtSupport" } Depends { name: "QtSupport" }
Depends { name: "app_version_header" } Depends { name: "app_version_header" }
Depends { name: "Sqlite" }
cpp.defines: base.concat([ cpp.defines: base.concat([
"DESIGNER_CORE_LIBRARY", "DESIGNER_CORE_LIBRARY",
@@ -411,6 +412,21 @@ Project {
"pluginmanager/widgetpluginmanager.h", "pluginmanager/widgetpluginmanager.h",
"pluginmanager/widgetpluginpath.cpp", "pluginmanager/widgetpluginpath.cpp",
"pluginmanager/widgetpluginpath.h", "pluginmanager/widgetpluginpath.h",
"include/imagecache.h",
"imagecache/imagecachecollector.cpp",
"imagecache/imagecachecollector.h",
"imagecache/imagecache.cpp",
"imagecache/imagecachecollectorinterface.h",
"imagecache/imagecacheconnectionmanager.cpp",
"imagecache/imagecacheconnectionmanager.h",
"imagecache/imagecachegeneratorinterface.h",
"imagecache/imagecachegenerator.cpp",
"imagecache/imagecachegenerator.h",
"imagecache/imagecachestorageinterface.h",
"imagecache/imagecachestorage.h",
"imagecache/timestampproviderinterface.h",
"imagecache/timestampprovider.h",
"imagecache/timestampprovider.cpp",
] ]
} }
@@ -602,6 +618,8 @@ Project {
"itemlibrary/itemlibrarywidget.h", "itemlibrary/itemlibrarywidget.h",
"itemlibrary/customfilesystemmodel.cpp", "itemlibrary/customfilesystemmodel.cpp",
"itemlibrary/customfilesystemmodel.h", "itemlibrary/customfilesystemmodel.h",
"itemlibrary/itemlibraryiconimageprovider.cpp",
"itemlibrary/itemlibraryiconimageprovider.h",
"navigator/iconcheckboxitemdelegate.cpp", "navigator/iconcheckboxitemdelegate.cpp",
"navigator/iconcheckboxitemdelegate.h", "navigator/iconcheckboxitemdelegate.h",
"navigator/nameitemdelegate.cpp", "navigator/nameitemdelegate.cpp",

View File

@@ -1,5 +1,6 @@
INCLUDEPATH += $$PWD INCLUDEPATH += $$PWD
INCLUDEPATH += $$PWD/designercore/include INCLUDEPATH += $$PWD/designercore/include
INCLUDEPATH += $$PWD/designercore/imagecache
INCLUDEPATH += $$PWD/designercore INCLUDEPATH += $$PWD/designercore
INCLUDEPATH += $$PWD/../../../share/qtcreator/qml/qmlpuppet/interfaces INCLUDEPATH += $$PWD/../../../share/qtcreator/qml/qmlpuppet/interfaces
INCLUDEPATH += $$PWD/../../../share/qtcreator/qml/qmlpuppet/types INCLUDEPATH += $$PWD/../../../share/qtcreator/qml/qmlpuppet/types
@@ -30,9 +31,18 @@ SOURCES += \
$$PWD/designercore/model/variantproperty.cpp\ $$PWD/designercore/model/variantproperty.cpp\
$$PWD/designercore/model/annotation.cpp \ $$PWD/designercore/model/annotation.cpp \
$$PWD/designercore/rewritertransaction.cpp \ $$PWD/designercore/rewritertransaction.cpp \
$$PWD/components/listmodeleditor/listmodeleditormodel.cpp $$PWD/components/listmodeleditor/listmodeleditormodel.cpp \
$$PWD/designercore/imagecache/imagecache.cpp \
$$PWD/designercore/imagecache/imagecachegenerator.cpp
HEADERS += \ HEADERS += \
$$PWD/designercore/imagecache/imagecachecollectorinterface.h \
$$PWD/designercore/imagecache/imagecachestorage.h \
$$PWD/designercore/imagecache/imagecachegenerator.h \
$$PWD/designercore/imagecache/imagecachestorageinterface.h \
$$PWD/designercore/imagecache/imagecachegeneratorinterface.h \
$$PWD/designercore/imagecache/timestampproviderinterface.h \
$$PWD/designercore/include/imagecache.h \
$$PWD/designercore/include/modelnode.h \ $$PWD/designercore/include/modelnode.h \
$$PWD/designercore/include/model.h \ $$PWD/designercore/include/model.h \
$$PWD/../../../share/qtcreator/qml/qmlpuppet/interfaces/commondefines.h \ $$PWD/../../../share/qtcreator/qml/qmlpuppet/interfaces/commondefines.h \

View File

@@ -174,6 +174,7 @@ extend_qtc_executable(qml2puppet
qt5capturepreviewnodeinstanceserver.cpp qt5capturepreviewnodeinstanceserver.h qt5capturepreviewnodeinstanceserver.cpp qt5capturepreviewnodeinstanceserver.h
nodeinstanceserverdispatcher.cpp nodeinstanceserverdispatcher.h nodeinstanceserverdispatcher.cpp nodeinstanceserverdispatcher.h
capturenodeinstanceserverdispatcher.cpp capturenodeinstanceserverdispatcher.h capturenodeinstanceserverdispatcher.cpp capturenodeinstanceserverdispatcher.h
qt5captureimagenodeinstanceserver.cpp qt5captureimagenodeinstanceserver.h
) )
extend_qtc_executable(qml2puppet extend_qtc_executable(qml2puppet

View File

@@ -224,6 +224,8 @@ QtcTool {
"instances/servernodeinstance.h", "instances/servernodeinstance.h",
"instances/qt5capturepreviewnodeinstanceserver.cpp", "instances/qt5capturepreviewnodeinstanceserver.cpp",
"instances/qt5capturepreviewnodeinstanceserver.h", "instances/qt5capturepreviewnodeinstanceserver.h",
"instances/qt5captureimagenodeinstanceserver.cpp",
"instances/qt5captureimagenodeinstanceserver.h",
"instances/nodeinstanceserverdispatcher.cpp", "instances/nodeinstanceserverdispatcher.cpp",
"instances/nodeinstanceserverdispatcher.h", "instances/nodeinstanceserverdispatcher.h",
"instances/capturenodeinstanceserverdispatcher.cpp", "instances/capturenodeinstanceserverdispatcher.cpp",

View File

@@ -28,6 +28,10 @@
#include "qmldesignercorelib_global.h" #include "qmldesignercorelib_global.h"
#include "abstractview.h" #include "abstractview.h"
namespace ProjectExplorer {
class Target;
}
namespace QmlDesigner { namespace QmlDesigner {
class NodeInstanceView : public AbstractView class NodeInstanceView : public AbstractView
@@ -88,6 +92,8 @@ public:
void requestModelNodePreviewImage(const ModelNode &node) {} void requestModelNodePreviewImage(const ModelNode &node) {}
void sendToken(const QString &token, int number, const QVector<ModelNode> &nodeVector) {} void sendToken(const QString &token, int number, const QVector<ModelNode> &nodeVector) {}
void setTarget(ProjectExplorer::Target *newTarget) {}
void setCrashCallback(std::function<void()>) {}
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -174,6 +174,19 @@ add_qtc_test(unittest GTEST
sqlstatementbuilder-test.cpp sqlstatementbuilder-test.cpp
createtablesqlstatementbuilder-test.cpp createtablesqlstatementbuilder-test.cpp
sqlitevalue-test.cpp sqlitevalue-test.cpp
imagecache-test.cpp
imagecachegenerator-test.cpp
imagecachestorage-test.cpp
sqlitedatabasemock.h
sqlitereadstatementmock.cpp sqlitereadstatementmock.h
sqlitestatementmock.h
sqlitetransactionbackendmock.h
sqlitewritestatementmock.cpp sqlitewritestatementmock.h
notification.h
mocktimestampprovider.h
imagecachecollectormock.h
mockimagecachegenerator.h
mockimagecachestorage.h
) )
function(extend_qtc_test_with_target_sources target) function(extend_qtc_test_with_target_sources target)
@@ -335,6 +348,7 @@ extend_qtc_test(unittest
"${QmlDesignerDir}" "${QmlDesignerDir}"
"${QmlDesignerDir}/designercore" "${QmlDesignerDir}/designercore"
"${QmlDesignerDir}/designercore/include" "${QmlDesignerDir}/designercore/include"
"${QmlDesignerDir}/designercore/imagecache"
"${QmlDesignerDir}/../../../share/qtcreator/qml/qmlpuppet/interfaces" "${QmlDesignerDir}/../../../share/qtcreator/qml/qmlpuppet/interfaces"
"${QmlDesignerDir}/../../../share/qtcreator/qml/qmlpuppet/types" "${QmlDesignerDir}/../../../share/qtcreator/qml/qmlpuppet/types"
DEFINES DEFINES
@@ -382,6 +396,13 @@ extend_qtc_test(unittest
model/signalhandlerproperty.cpp include/signalhandlerproperty.h model/signalhandlerproperty.cpp include/signalhandlerproperty.h
model/variantproperty.cpp include/variantproperty.h model/variantproperty.cpp include/variantproperty.h
rewritertransaction.cpp rewritertransaction.h rewritertransaction.cpp rewritertransaction.h
imagecache/imagecache.cpp include/imagecache.h
imagecache/imagecachecollectorinterface.h
imagecache/imagecachegenerator.cpp imagecache/imagecachegenerator.h
imagecache/imagecachegeneratorinterface.h
imagecache/imagecachestorage.h
imagecache/imagecachestorageinterface.h
imagecache/timestampproviderinterface.h
include/qmldesignercorelib_global.h include/qmldesignercorelib_global.h

View File

@@ -14,10 +14,8 @@ defineTest(setGoogleTestDirectories) {
} }
isEmpty(GOOGLETEST_DIR) { isEmpty(GOOGLETEST_DIR) {
exists($$PWD/../../../../googletest) { exists($$PWD/3rdparty/googletest) {
setGoogleTestDirectories($$PWD/../../../../googletest) setGoogleTestDirectories($$PWD/3rdparty/googletest)
} else: exists($$PWD/../../../../../googletest) {
setGoogleTestDirectories($$PWD/../../../../../googletest)
} else: linux { } else: linux {
GTEST_INCLUDE_DIR = /usr/include/gtest GTEST_INCLUDE_DIR = /usr/include/gtest
GMOCK_INCLUDE_DIR = /usr/include/gmock GMOCK_INCLUDE_DIR = /usr/include/gmock

View File

@@ -35,12 +35,16 @@ using testing::An;
using testing::AnyNumber; using testing::AnyNumber;
using testing::AnyOf; using testing::AnyOf;
using testing::Assign; using testing::Assign;
using testing::AtLeast;
using testing::AtMost;
using testing::Between;
using testing::ByMove; using testing::ByMove;
using testing::ByRef; using testing::ByRef;
using testing::ContainerEq; using testing::ContainerEq;
using testing::Contains; using testing::Contains;
using testing::ElementsAre; using testing::ElementsAre;
using testing::Eq; using testing::Eq;
using testing::Exactly;
using testing::Field; using testing::Field;
using testing::Ge; using testing::Ge;
using testing::Gt; using testing::Gt;

View File

@@ -70,6 +70,7 @@
#include <usedmacro.h> #include <usedmacro.h>
#include <utils/link.h> #include <utils/link.h>
#include <variantproperty.h> #include <variantproperty.h>
#include <qmldesigner/designercore/imagecache/imagecachestorageinterface.h>
#include <sqlite3ext.h> #include <sqlite3ext.h>
@@ -1468,6 +1469,15 @@ std::ostream &operator<<(std::ostream &out, const VariantProperty &property)
return out << "(" << property.parentModelNode() << ", " << property.name() << ", " return out << "(" << property.parentModelNode() << ", " << property.name() << ", "
<< property.value() << ")"; << property.value() << ")";
} }
namespace Internal {
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageEntry &entry)
{
return out << "(" << entry.image << ", " << entry.hasEntry << ")";
}
} // namespace Internal
} // namespace QmlDesigner } // namespace QmlDesigner
void setFilePathCache(ClangBackEnd::FilePathCaching *cache) void setFilePathCache(ClangBackEnd::FilePathCaching *cache)

View File

@@ -356,6 +356,13 @@ class VariantProperty;
std::ostream &operator<<(std::ostream &out, const ModelNode &node); std::ostream &operator<<(std::ostream &out, const ModelNode &node);
std::ostream &operator<<(std::ostream &out, const VariantProperty &property); std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
namespace Internal {
class ImageCacheStorageEntry;
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageEntry &entry);
} // namespace Internal
} // namespace QmlDesigner } // namespace QmlDesigner
void setFilePathCache(ClangBackEnd::FilePathCaching *filePathCache); void setFilePathCache(ClangBackEnd::FilePathCaching *filePathCache);

View File

@@ -85,6 +85,11 @@ std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format)
return out; return out;
} }
std::ostream &operator<<(std::ostream &out, const QImage &image)
{
return out << "(" << image.width() << ", " << image.height() << ", " << image.format() << ")";
}
void PrintTo(const QString &text, std::ostream *os) void PrintTo(const QString &text, std::ostream *os)
{ {
*os << text; *os << text;

View File

@@ -34,11 +34,13 @@ QT_BEGIN_NAMESPACE
class QVariant; class QVariant;
class QString; class QString;
class QTextCharFormat; class QTextCharFormat;
class QImage;
std::ostream &operator<<(std::ostream &out, const QVariant &QVariant); std::ostream &operator<<(std::ostream &out, const QVariant &QVariant);
std::ostream &operator<<(std::ostream &out, const QString &text); std::ostream &operator<<(std::ostream &out, const QString &text);
std::ostream &operator<<(std::ostream &out, const QByteArray &byteArray); std::ostream &operator<<(std::ostream &out, const QByteArray &byteArray);
std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format); std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format);
std::ostream &operator<<(std::ostream &out, const QImage &image);
void PrintTo(const QString &text, std::ostream *os); void PrintTo(const QString &text, std::ostream *os);
void PrintTo(const QVariant &variant, std::ostream *os); void PrintTo(const QVariant &variant, std::ostream *os);

View File

@@ -0,0 +1,326 @@
/****************************************************************************
**
** Copyright (C) 2016 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 "googletest.h"
#include "mockimagecachegenerator.h"
#include "mockimagecachestorage.h"
#include "mocktimestampprovider.h"
#include "notification.h"
#include <imagecache.h>
namespace {
class ImageCache : public testing::Test
{
protected:
Notification notification;
Notification waitInThread;
NiceMock<MockImageCacheStorage> mockStorage;
NiceMock<MockImageCacheGenerator> mockGenerator;
NiceMock<MockTimeStampProvider> mockTimeStampProvider;
QmlDesigner::ImageCache cache{mockStorage, mockGenerator, mockTimeStampProvider};
NiceMock<MockFunction<void()>> mockAbortCallback;
NiceMock<MockFunction<void(const QImage &image)>> mockCaptureCallback;
QImage image1{10, 10, QImage::Format_ARGB32};
};
TEST_F(ImageCache, RequestImageFetchesImageFromStorage)
{
EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
.WillRepeatedly([&](Utils::SmallStringView, auto) {
notification.notify();
return QmlDesigner::ImageCacheStorageInterface::Entry{{}, false};
});
cache.requestImage("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestImageFetchesImageFromStorageWithTimeStamp)
{
EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
.WillRepeatedly(Return(Sqlite::TimeStamp{123}));
EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
.WillRepeatedly([&](Utils::SmallStringView, auto) {
notification.notify();
return QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, false};
});
cache.requestImage("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestImageCallsCaptureCallbackWithImageFromStorage)
{
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{image1, true}));
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))).WillRepeatedly([&](const QImage &) {
notification.notify();
});
cache.requestImage("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestImageCallsAbortCallbackWithoutImage)
{
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, true}));
EXPECT_CALL(mockAbortCallback, Call()).WillRepeatedly([&] { notification.notify(); });
cache.requestImage("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestImageRequestImageFromGenerator)
{
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{123}));
EXPECT_CALL(mockGenerator,
generateImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123}), _, _))
.WillRepeatedly([&](auto &&, auto, auto &&callback, auto) { notification.notify(); });
cache.requestImage("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestImageCallsCaptureCallbackWithImageFromGenerator)
{
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _))
.WillByDefault([&](auto &&, auto, auto &&callback, auto) {
callback(QImage{image1});
notification.notify();
});
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1)));
cache.requestImage("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestImageCallsAbortCallbackFromGenerator)
{
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _))
.WillByDefault([&](auto &&, auto, auto &&, auto &&abortCallback) {
abortCallback();
notification.notify();
});
EXPECT_CALL(mockAbortCallback, Call());
cache.requestImage("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestIconFetchesIconFromStorage)
{
EXPECT_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _))
.WillRepeatedly([&](Utils::SmallStringView, auto) {
notification.notify();
return QmlDesigner::ImageCacheStorageInterface::Entry{{}, false};
});
cache.requestIcon("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestIconFetchesIconFromStorageWithTimeStamp)
{
EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
.WillRepeatedly(Return(Sqlite::TimeStamp{123}));
EXPECT_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
.WillRepeatedly([&](Utils::SmallStringView, auto) {
notification.notify();
return QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, false};
});
cache.requestIcon("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestIconCallsCaptureCallbackWithImageFromStorage)
{
ON_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{image1, true}));
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))).WillRepeatedly([&](const QImage &) {
notification.notify();
});
cache.requestIcon("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestIconCallsAbortCallbackWithoutIcon)
{
ON_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, true}));
EXPECT_CALL(mockAbortCallback, Call()).WillRepeatedly([&] { notification.notify(); });
cache.requestIcon("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestIconRequestImageFromGenerator)
{
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{123}));
EXPECT_CALL(mockGenerator,
generateImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123}), _, _))
.WillRepeatedly([&](auto &&, auto, auto &&callback, auto) { notification.notify(); });
cache.requestIcon("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestIconCallsCaptureCallbackWithImageFromGenerator)
{
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _))
.WillByDefault([&](auto &&, auto, auto &&callback, auto) {
callback(QImage{image1});
notification.notify();
});
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1)));
cache.requestIcon("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, RequestIconCallsAbortCallbackFromGenerator)
{
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _))
.WillByDefault([&](auto &&, auto, auto &&, auto &&abortCallback) {
abortCallback();
notification.notify();
});
EXPECT_CALL(mockAbortCallback, Call());
cache.requestIcon("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
TEST_F(ImageCache, CleanRemovesEntries)
{
EXPECT_CALL(mockGenerator, generateImage(Eq("/path/to/Component1.qml"), _, _, _))
.WillRepeatedly([&](auto &&, auto, auto &&mockCaptureCallback, auto &&) {
mockCaptureCallback(QImage{});
waitInThread.wait();
});
EXPECT_CALL(mockGenerator, generateImage(_, _, _, _))
.WillRepeatedly([&](auto &&, auto, auto &&mockCaptureCallback, auto &&) {
mockCaptureCallback(QImage{});
});
cache.requestIcon("/path/to/Component1.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
EXPECT_CALL(mockCaptureCallback, Call(_)).Times(AtMost(1));
cache.requestIcon("/path/to/Component3.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
cache.clean();
waitInThread.notify();
}
TEST_F(ImageCache, CleanCallsAbort)
{
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component1.qml"), _, _, _))
.WillByDefault(
[&](auto &&, auto, auto &&mockCaptureCallback, auto &&) { waitInThread.wait(); });
cache.requestIcon("/path/to/Component1.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
cache.requestIcon("/path/to/Component2.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
EXPECT_CALL(mockAbortCallback, Call()).Times(AtLeast(2));
cache.requestIcon("/path/to/Component3.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
cache.clean();
waitInThread.notify();
}
TEST_F(ImageCache, CleanCallsGeneratorClean)
{
EXPECT_CALL(mockGenerator, clean()).Times(AtLeast(1));
cache.clean();
}
TEST_F(ImageCache, AfterCleanNewJobsWorks)
{
cache.clean();
EXPECT_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _))
.WillRepeatedly([&](auto &&, auto, auto &&, auto &&) { notification.notify(); });
cache.requestIcon("/path/to/Component.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
notification.wait();
}
} // namespace

View File

@@ -0,0 +1,41 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "googletest.h"
#include <imagecachecollectorinterface.h>
class ImageCacheCollectorMock : public QmlDesigner::ImageCacheCollectorInterface
{
public:
MOCK_METHOD(void,
start,
(Utils::SmallStringView filePath,
ImageCacheCollectorInterface::CaptureCallback captureCallback,
ImageCacheCollectorInterface::AbortCallback abortCallback),
(override));
};

View File

@@ -0,0 +1,240 @@
/****************************************************************************
**
** Copyright (C) 2016 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 "googletest.h"
#include "imagecachecollectormock.h"
#include "mockimagecachestorage.h"
#include "notification.h"
#include <imagecachegenerator.h>
#include <mutex>
namespace {
class ImageCacheGenerator : public testing::Test
{
protected:
template<typename Callable, typename... Arguments>
static void executeAsync(Callable &&call, Arguments... arguments)
{
std::thread thread(
[](Callable &&call, Arguments... arguments) {
call(std::forward<Arguments>(arguments)...);
},
std::forward<Callable>(call),
std::forward<Arguments>(arguments)...);
thread.detach();
}
protected:
Notification waitInThread;
Notification notification;
QImage image1{10, 10, QImage::Format_ARGB32};
NiceMock<MockFunction<void(const QImage &)>> imageCallbackMock;
NiceMock<MockFunction<void()>> abortCallbackMock;
NiceMock<ImageCacheCollectorMock> collectorMock;
NiceMock<MockImageCacheStorage> storageMock;
QmlDesigner::ImageCacheGenerator generator{collectorMock, storageMock};
};
TEST_F(ImageCacheGenerator, CallsCollectorWithCaptureCallback)
{
EXPECT_CALL(collectorMock, start(Eq("name"), _, _))
.WillRepeatedly([&](auto, auto captureCallback, auto) { captureCallback(QImage{image1}); });
EXPECT_CALL(imageCallbackMock, Call(_)).WillRepeatedly([&](const QImage &) {
notification.notify();
});
generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {});
notification.wait();
}
TEST_F(ImageCacheGenerator, CallsCollectorOnlyIfNotProcessing)
{
EXPECT_CALL(collectorMock, start(Eq("name"), _, _)).WillRepeatedly([&](auto, auto, auto) {
notification.notify();
});
generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {});
generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {});
notification.wait(2);
}
TEST_F(ImageCacheGenerator, ProcessTaskAfterFirstFinished)
{
ON_CALL(imageCallbackMock, Call(_)).WillByDefault([&](const QImage &) { notification.notify(); });
EXPECT_CALL(collectorMock, start(Eq("name"), _, _)).WillOnce([&](auto, auto captureCallback, auto) {
captureCallback(QImage{image1});
});
EXPECT_CALL(collectorMock, start(Eq("name2"), _, _)).WillOnce([&](auto, auto captureCallback, auto) {
captureCallback(QImage{image1});
});
generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {});
generator.generateImage("name2", {}, imageCallbackMock.AsStdFunction(), {});
notification.wait(2);
}
TEST_F(ImageCacheGenerator, DontCrashAtDestructingGenerator)
{
ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) {
captureCallback(QImage{image1});
});
generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {});
generator.generateImage("name2", {}, imageCallbackMock.AsStdFunction(), {});
generator.generateImage("name3", {}, imageCallbackMock.AsStdFunction(), {});
generator.generateImage("name4", {}, imageCallbackMock.AsStdFunction(), {});
}
TEST_F(ImageCacheGenerator, StoreImage)
{
ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) {
captureCallback(QImage{image1});
});
EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(image1)))
.WillRepeatedly([&](auto, auto, auto) { notification.notify(); });
generator.generateImage("name", {11}, imageCallbackMock.AsStdFunction(), {});
notification.wait();
}
TEST_F(ImageCacheGenerator, StoreNullImage)
{
ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) {
captureCallback(QImage{});
});
EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{})))
.WillRepeatedly([&](auto, auto, auto) { notification.notify(); });
generator.generateImage("name",
{11},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
notification.wait();
}
TEST_F(ImageCacheGenerator, AbortCallback)
{
ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) {
captureCallback(QImage{image1});
});
ON_CALL(collectorMock, start(Eq("name2"), _, _)).WillByDefault([&](auto, auto, auto abortCallback) {
abortCallback();
});
EXPECT_CALL(imageCallbackMock, Call(_)).WillOnce([&](const QImage &) { notification.notify(); });
EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); });
generator.generateImage("name",
{},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
generator.generateImage("name2",
{},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
notification.wait(2);
}
TEST_F(ImageCacheGenerator, StoreNullImageForAbortCallback)
{
ON_CALL(collectorMock, start(_, _, _)).WillByDefault([&](auto, auto, auto abortCallback) {
abortCallback();
notification.notify();
});
EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); });
EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{})));
generator.generateImage("name",
{11},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
notification.wait();
}
TEST_F(ImageCacheGenerator, AbortForEmptyImage)
{
NiceMock<MockFunction<void()>> abortCallbackMock;
ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) {
captureCallback(QImage{});
});
EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); });
generator.generateImage("name",
{},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
notification.wait();
}
TEST_F(ImageCacheGenerator, CallWalCheckpointFullIfQueueIsEmpty)
{
ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) {
captureCallback({});
});
EXPECT_CALL(storageMock, walCheckpointFull()).WillRepeatedly([&]() { notification.notify(); });
generator.generateImage("name",
{11},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
generator.generateImage("name2",
{11},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
notification.wait();
}
TEST_F(ImageCacheGenerator, Clean)
{
ON_CALL(collectorMock, start(_, _, _)).WillByDefault([&](auto, auto captureCallback, auto) {
captureCallback({});
waitInThread.wait();
});
generator.generateImage("name",
{11},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
generator.generateImage("name2",
{11},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
EXPECT_CALL(imageCallbackMock, Call(_)).Times(0);
generator.clean();
waitInThread.notify();
}
} // namespace

View File

@@ -0,0 +1,334 @@
/****************************************************************************
**
** Copyright (C) 2016 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 "googletest.h"
#include "sqlitedatabasemock.h"
#include <imagecachestorage.h>
#include <sqlitedatabase.h>
namespace {
MATCHER_P2(IsEntry,
image,
hasEntry,
std::string(negation ? "is't" : "is")
+ PrintToString(QmlDesigner::ImageCacheStorageInterface::Entry{image, hasEntry}))
{
const QmlDesigner::ImageCacheStorageInterface::Entry &entry = arg;
return entry.image == image && entry.hasEntry == hasEntry;
}
class ImageCacheStorageTest : public testing::Test
{
protected:
QImage createImage()
{
QImage image{150, 150, QImage::Format_ARGB32};
image.fill(QColor{128, 64, 0, 11});
image.setPixelColor(75, 75, QColor{1, 255, 33, 196});
return image;
}
protected:
using ReadStatement = QmlDesigner::ImageCacheStorage<SqliteDatabaseMock>::ReadStatement;
using WriteStatement = QmlDesigner::ImageCacheStorage<SqliteDatabaseMock>::WriteStatement;
NiceMock<SqliteDatabaseMock> databaseMock;
QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
ReadStatement &selectImageStatement = storage.selectImageStatement;
ReadStatement &selectIconStatement = storage.selectIconStatement;
WriteStatement &upsertImageStatement = storage.upsertImageStatement;
QImage image1{createImage()};
};
TEST_F(ImageCacheStorageTest, Initialize)
{
InSequence s;
EXPECT_CALL(databaseMock, exclusiveBegin());
EXPECT_CALL(databaseMock,
execute(Eq("CREATE TABLE IF NOT EXISTS images(id INTEGER PRIMARY KEY, name TEXT "
"NOT NULL UNIQUE, mtime INTEGER, image BLOB, icon BLOB)")));
EXPECT_CALL(databaseMock, commit());
EXPECT_CALL(databaseMock, immediateBegin());
EXPECT_CALL(databaseMock, prepare(Eq(selectImageStatement.sqlStatement)));
EXPECT_CALL(databaseMock, prepare(Eq(selectIconStatement.sqlStatement)));
EXPECT_CALL(databaseMock, prepare(Eq(upsertImageStatement.sqlStatement)));
EXPECT_CALL(databaseMock, commit());
QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
}
TEST_F(ImageCacheStorageTest, FetchImageCalls)
{
InSequence s;
EXPECT_CALL(databaseMock, deferredBegin());
EXPECT_CALL(selectImageStatement,
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123)));
EXPECT_CALL(databaseMock, commit());
storage.fetchImage("/path/to/component", {123});
}
TEST_F(ImageCacheStorageTest, FetchImageCallsIsBusy)
{
InSequence s;
EXPECT_CALL(databaseMock, deferredBegin());
EXPECT_CALL(selectImageStatement,
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123)))
.WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
EXPECT_CALL(databaseMock, rollback());
EXPECT_CALL(databaseMock, deferredBegin());
EXPECT_CALL(selectImageStatement,
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123)));
EXPECT_CALL(databaseMock, commit());
storage.fetchImage("/path/to/component", {123});
}
TEST_F(ImageCacheStorageTest, FetchIconCalls)
{
InSequence s;
EXPECT_CALL(databaseMock, deferredBegin());
EXPECT_CALL(selectIconStatement,
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123)));
EXPECT_CALL(databaseMock, commit());
storage.fetchIcon("/path/to/component", {123});
}
TEST_F(ImageCacheStorageTest, FetchIconCallsIsBusy)
{
InSequence s;
EXPECT_CALL(databaseMock, deferredBegin());
EXPECT_CALL(selectIconStatement,
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123)))
.WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
EXPECT_CALL(databaseMock, rollback());
EXPECT_CALL(databaseMock, deferredBegin());
EXPECT_CALL(selectIconStatement,
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123)));
EXPECT_CALL(databaseMock, commit());
storage.fetchIcon("/path/to/component", {123});
}
TEST_F(ImageCacheStorageTest, StoreImageCalls)
{
InSequence s;
EXPECT_CALL(databaseMock, immediateBegin());
EXPECT_CALL(upsertImageStatement,
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123),
A<Sqlite::BlobView>(),
A<Sqlite::BlobView>()));
EXPECT_CALL(databaseMock, commit());
storage.storeImage("/path/to/component", {123}, image1);
}
TEST_F(ImageCacheStorageTest, StoreEmptyImageCalls)
{
InSequence s;
EXPECT_CALL(databaseMock, immediateBegin());
EXPECT_CALL(upsertImageStatement,
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123),
A<Sqlite::NullValue>(),
A<Sqlite::NullValue>()));
EXPECT_CALL(databaseMock, commit());
storage.storeImage("/path/to/component", {123}, QImage{});
}
TEST_F(ImageCacheStorageTest, StoreImageCallsIsBusy)
{
InSequence s;
EXPECT_CALL(databaseMock, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
EXPECT_CALL(databaseMock, immediateBegin());
EXPECT_CALL(upsertImageStatement,
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123),
A<Sqlite::NullValue>(),
A<Sqlite::NullValue>()));
EXPECT_CALL(databaseMock, commit());
storage.storeImage("/path/to/component", {123}, QImage{});
}
TEST_F(ImageCacheStorageTest, CallWalCheckointFull)
{
EXPECT_CALL(databaseMock, walCheckpointFull());
storage.walCheckpointFull();
}
TEST_F(ImageCacheStorageTest, CallWalCheckointFullIsBusy)
{
InSequence s;
EXPECT_CALL(databaseMock, walCheckpointFull()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
EXPECT_CALL(databaseMock, walCheckpointFull());
storage.walCheckpointFull();
}
class ImageCacheStorageSlowTest : public testing::Test
{
protected:
QImage createImage()
{
QImage image{150, 150, QImage::Format_ARGB32};
image.fill(QColor{128, 64, 0, 11});
image.setPixelColor(1, 1, QColor{1, 255, 33, 196});
return image;
}
protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
QmlDesigner::ImageCacheStorage<Sqlite::Database> storage{database};
QImage image1{createImage()};
QImage image2{10, 10, QImage::Format_ARGB32};
QImage icon1{image1.scaled(96, 96)};
};
TEST_F(ImageCacheStorageSlowTest, StoreImage)
{
storage.storeImage("/path/to/component", {123}, image1);
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(image1, true));
}
TEST_F(ImageCacheStorageSlowTest, StoreEmptyImageAfterEntry)
{
storage.storeImage("/path/to/component", {123}, image1);
storage.storeImage("/path/to/component", {123}, QImage{});
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(QImage{}, true));
}
TEST_F(ImageCacheStorageSlowTest, StoreEmptyEntry)
{
storage.storeImage("/path/to/component", {123}, QImage{});
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(QImage{}, true));
}
TEST_F(ImageCacheStorageSlowTest, FetchNonExistingImageIsEmpty)
{
auto image = storage.fetchImage("/path/to/component", {123});
ASSERT_THAT(image, IsEntry(QImage{}, false));
}
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeImage)
{
storage.storeImage("/path/to/component", {123}, image1);
auto image = storage.fetchImage("/path/to/component", {123});
ASSERT_THAT(image, IsEntry(image1, true));
}
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderImage)
{
storage.storeImage("/path/to/component", {123}, image1);
auto image = storage.fetchImage("/path/to/component", {124});
ASSERT_THAT(image, IsEntry(QImage{}, false));
}
TEST_F(ImageCacheStorageSlowTest, FetchNewerImage)
{
storage.storeImage("/path/to/component", {123}, image1);
auto image = storage.fetchImage("/path/to/component", {122});
ASSERT_THAT(image, IsEntry(image1, true));
}
TEST_F(ImageCacheStorageSlowTest, FetchNonExistingIconIsEmpty)
{
auto image = storage.fetchIcon("/path/to/component", {123});
ASSERT_THAT(image, IsEntry(QImage{}, false));
}
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeIcon)
{
storage.storeImage("/path/to/component", {123}, image1);
auto image = storage.fetchIcon("/path/to/component", {123});
ASSERT_THAT(image, IsEntry(icon1, true));
}
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderIcon)
{
storage.storeImage("/path/to/component", {123}, image1);
auto image = storage.fetchIcon("/path/to/component", {124});
ASSERT_THAT(image, IsEntry(QImage{}, false));
}
TEST_F(ImageCacheStorageSlowTest, FetchNewerIcon)
{
storage.storeImage("/path/to/component", {123}, image1);
auto image = storage.fetchIcon("/path/to/component", {122});
ASSERT_THAT(image, IsEntry(icon1, true));
}
TEST_F(ImageCacheStorageSlowTest, DontScaleSmallerIcon)
{
storage.storeImage("/path/to/component", {123}, image2);
auto image = storage.fetchImage("/path/to/component", {122});
ASSERT_THAT(image, IsEntry(image2, true));
}
} // namespace

View File

@@ -0,0 +1,43 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "googletest.h"
#include <imagecachegeneratorinterface.h>
class MockImageCacheGenerator : public QmlDesigner::ImageCacheGeneratorInterface
{
public:
MOCK_METHOD(void,
generateImage,
(Utils::SmallStringView name,
Sqlite::TimeStamp timeStamp,
CaptureCallback &&captureCallback,
AbortCallback &&abortCallback),
(override));
MOCK_METHOD(void, clean, (), (override));
};

View File

@@ -0,0 +1,50 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "googletest.h"
#include <imagecachestorageinterface.h>
class MockImageCacheStorage : public QmlDesigner::ImageCacheStorageInterface
{
public:
MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::Entry,
fetchImage,
(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
(const, override));
MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::Entry,
fetchIcon,
(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
(const, override));
MOCK_METHOD(void,
storeImage,
(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QImage &image),
(override));
MOCK_METHOD(void, walCheckpointFull, (), (override));
};

View File

@@ -0,0 +1,36 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "googletest.h"
#include <timestampproviderinterface.h>
class MockTimeStampProvider : public QmlDesigner::TimeStampProviderInterface
{
public:
MOCK_METHOD(Sqlite::TimeStamp, timeStamp, (Utils::SmallStringView name), (const, override));
};

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