FlightGear next
ThumbnailImageItem.cxx
Go to the documentation of this file.
2
3#include <QSGSimpleTextureNode>
4#include <QQuickWindow>
5#include <QFileInfo>
6#include <QDir>
7
8#include <Main/globals.hxx>
9
10#include <simgear/package/Root.hxx>
11#include <simgear/package/Package.hxx>
12#include <simgear/package/Delegate.hxx>
13#include <simgear/package/Catalog.hxx>
14#include <simgear/package/Install.hxx>
15
16using namespace simgear;
17
20
22{
23public:
25
26 void catalogRefreshed(pkg::CatalogRef, StatusCode) override {}
27 void startInstall(pkg::InstallRef) override {}
28 void installProgress(pkg::InstallRef, unsigned int, unsigned int) override {}
29 void finishInstall(pkg::InstallRef, StatusCode ) override {}
30 void dataForThumbnail(const std::string& aThumbnailUrl,
31 size_t length, const uint8_t* bytes) override;
32
34};
35
37 size_t length, const uint8_t* bytes)
38{
39 if (aThumbnailUrl != owner->url().toString().toStdString()) {
40 return;
41 }
42
43 const auto iLength = static_cast<int>(length);
44 QImage img = QImage::fromData(QByteArray::fromRawData(reinterpret_cast<const char*>(bytes), iLength));
45 if (img.isNull()) {
46 if (length > 0) {
47 // warn if we had valid bytes but couldn't load it, i.e corrupted data or similar
48 qWarning() << "failed to load image data for URL:" << QString::fromStdString(aThumbnailUrl);
49 owner->clearImage();
50 }
51 return;
52 }
53
54 owner->setImage(img);
55}
56
58 QQuickItem(parent),
59 m_delegate(new ThumbnailPackageDelegate(this)),
60 m_maximumSize(9999, 9999)
61{
62 globals->packageRoot()->addDelegate(m_delegate.get());
63 setFlag(ItemHasContents);
64 setImplicitWidth(STANDARD_THUMBNAIL_WIDTH);
65 setImplicitHeight(STANDARD_THUMBNAIL_HEIGHT);
66}
67
69{
70 globals->packageRoot()->removeDelegate(m_delegate.get());
71}
72
73QSGNode *ThumbnailImageItem::updatePaintNode(QSGNode* oldNode, QQuickItem::UpdatePaintNodeData *)
74{
75 if (m_image.isNull()) {
76 delete oldNode;
77 return nullptr;
78 }
79
80 QSGSimpleTextureNode* textureNode = static_cast<QSGSimpleTextureNode*>(oldNode);
81 if (m_imageDirty || !textureNode) {
82 if (!textureNode) {
83 textureNode = new QSGSimpleTextureNode;
84 textureNode->setOwnsTexture(true);
85 }
86 QSGTexture* tex = window()->createTextureFromImage(m_image, QQuickWindow::TextureIsOpaque);
87 textureNode->setTexture(tex);
88 textureNode->markDirty(QSGBasicGeometryNode::DirtyMaterial);
89 m_imageDirty = false;
90 }
91
92 textureNode->setRect(QRectF(0, 0, width(), height()));
93 return textureNode;
94}
95
97{
98 return m_imageUrl;
99}
100
102{
103 return m_aircraftUri;
104}
105
107{
108 return m_image.size();
109}
110
112{
113 return m_maximumSize;
114}
115
117{
118 if (m_aircraftUri == uri)
119 return;
120
121 m_aircraftUri = uri;
122
123 if (uri.startsWith("package:")) {
124 const std::string packageId = m_aircraftUri.toStdString().substr(8);
125 pkg::Root* root = globals->packageRoot();
126 pkg::PackageRef package = root->getPackageById(packageId);
127 if (package) {
128 auto variant = package->indexOfVariant(packageId);
129 const auto thumbnail = package->thumbnailForVariant(variant);
130 m_imageUrl = QUrl(QString::fromStdString(thumbnail.url));
131 if (m_imageUrl.isValid()) {
132 globals->packageRoot()->requestThumbnailData(m_imageUrl.toString().toStdString());
133 } else {
134 clearImage();
135 }
136 }
137 } else {
138 QFileInfo aircraftSetPath(QUrl(uri).toLocalFile());
139 const QString thumbnailPath = aircraftSetPath.dir().filePath("thumbnail.jpg");
140 m_imageUrl = QUrl::fromLocalFile(thumbnailPath);
141
142 if (QFileInfo(thumbnailPath).exists()) {
143 QImage img;
144 if (img.load(thumbnailPath)) {
145 setImage(img);
146 } else {
147 qWarning() << Q_FUNC_INFO << "failed to load thumbnail from:" << thumbnailPath;
148 clearImage();
149 }
150 }
151 } // of local aircraft case
152
153 emit aircraftUriChanged();
154}
155
157{
158 if (m_maximumSize == maximumSize)
159 return;
160
161 m_maximumSize = maximumSize;
162 emit maximumSizeChanged(m_maximumSize);
163
164 if (!m_image.isNull()) {
165 setImplicitSize(qMin(m_maximumSize.width(), m_image.width()),
166 qMin(m_maximumSize.height(), m_image.height()));
167 }
168}
169
170void ThumbnailImageItem::setImage(QImage image)
171{
172 m_image = image;
173 m_imageDirty = true;
174 setImplicitSize(qMin(m_maximumSize.width(), m_image.width()),
175 qMin(m_maximumSize.height(), m_image.height()));
176 emit sourceSizeChanged();
177 update();
178}
179
180void ThumbnailImageItem::clearImage()
181{
182 m_image = QImage{};
183 m_imageDirty = true;
184 setImplicitSize(m_maximumSize.width(), m_maximumSize.height());
185 emit sourceSizeChanged();
186 update();
187}
const int STANDARD_THUMBNAIL_WIDTH
const int STANDARD_THUMBNAIL_HEIGHT
void finishInstall(pkg::InstallRef, StatusCode) override
void catalogRefreshed(pkg::CatalogRef, StatusCode) override
void installProgress(pkg::InstallRef, unsigned int, unsigned int) override
void dataForThumbnail(const std::string &aThumbnailUrl, size_t length, const uint8_t *bytes) override
void setAircraftUri(QString uri)
void maximumSizeChanged(QSize maximumSize)
void setMaximumSize(QSize maximumSize)
ThumbnailImageItem(QQuickItem *parent=nullptr)
QSGNode * updatePaintNode(QSGNode *, UpdatePaintNodeData *) override
FGGlobals * globals
Definition globals.cxx:142