/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
QElectroTech is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see .
*/
#include "qetapptest.h"
#include "diagramcontent.h"
#include "qetgraphicsitem/diagramimageitem.h"
#include
#include
/**
Diagram::fromXml() decodes a folio's pictures in parallel, then builds
the items in file order. Every picture must come back with its own
pixels and position, whatever thread decoded it.
*/
class tst_folioimageload : public QObject
{
Q_OBJECT
Diagram *m_diagram = nullptr;
/// A picture no other one equals: its own size and noise.
static QImage distinctImage(int n)
{
QImage image(40 + 7 * n, 30 + 3 * n, QImage::Format_ARGB32);
QRandomGenerator random(quint32(n + 1));
for (int y = 0 ; y < image.height() ; ++y)
for (int x = 0 ; x < image.width() ; ++x)
image.setPixel(x, y, random.generate() | 0xFF000000);
return image;
}
static QImage pixelsOf(const DiagramImageItem *item)
{
return item->pixmap().toImage()
.convertToFormat(QImage::Format_ARGB32);
}
void removePictures()
{
// A selected picture's handles are its children, in items()
// too: deleting the picture first would leave them dangling.
m_diagram->clearSelection();
for (QGraphicsItem *item : m_diagram->items())
if (item->type() == DiagramImageItem::Type)
delete item;
}
private slots:
void initTestCase()
{
QVERIFY(QetAppTest::editor());
m_diagram = QetAppTest::diagram();
QVERIFY(m_diagram);
}
void cleanup()
{
m_diagram->clearSelection();
removePictures();
m_diagram->undoStack().clear();
}
void everyPictureComesBackWithItsPixels()
{
QHash expected; // by x position, each its own
for (int n = 0 ; n < 6 ; ++n) {
const QImage image = distinctImage(n);
auto *picture = new DiagramImageItem(QPixmap::fromImage(image));
m_diagram->addItem(picture);
picture->setPos(100 + 150 * n, 200);
picture->setSelected(true);
expected.insert(qRound(picture->pos().x()), image);
}
QDomDocument document = m_diagram->toXml(false);
removePictures();
DiagramContent content;
QVERIFY(m_diagram->fromXml(document, QPointF(), false, &content));
QCOMPARE(content.m_images.size(), expected.size());
for (const DiagramImageItem *picture : std::as_const(content.m_images)) {
const int x = qRound(picture->pos().x());
QVERIFY2(expected.contains(x), "picture moved");
QCOMPARE(picture->pos().y(), 200.0);
QCOMPARE(pixelsOf(picture), expected.value(x));
}
}
void anImageWithoutPictureDoesNotStopTheOthers()
{
for (int n = 0 ; n < 3 ; ++n) {
auto *picture = new DiagramImageItem(
QPixmap::fromImage(distinctImage(n)));
m_diagram->addItem(picture);
picture->setSelected(true);
}
QDomDocument document = m_diagram->toXml(false);
removePictures();
QDomElement images = document.documentElement()
.firstChildElement(QStringLiteral("images"));
QVERIFY(!images.isNull());
QDomElement empty = document.createElement(QStringLiteral("image"));
images.insertBefore(empty, images.firstChild());
DiagramContent content;
QVERIFY(m_diagram->fromXml(document, QPointF(), false, &content));
int with_pixels = 0;
for (const DiagramImageItem *picture : std::as_const(content.m_images))
if (!picture->pixmap().isNull())
++with_pixels;
QCOMPARE(with_pixels, 3);
}
};
QET_APP_TEST_MAIN(tst_folioimageload)
#include "tst_folioimageload.moc"