mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-09 21:54:13 +02:00
Load a picture without a usable size at size 1, not 0
DiagramImageItem::fromXml() read the size attribute with a plain toDouble(). A picture whose size was missing or not a number got size 0, so it was invisible on the folio, left out of the SVG export, and a resave wrote size="0" back, which then stayed 0 on every load. "nan" was kept and written back as such. The <transform> child, which newer files carry, already defaults its scale to 1. Read the size with an ok flag and use 1, the size a picture is added with, when it is missing, not a number, not finite, or 0. No file-format change for usable sizes. A picture that an earlier save left at size="0" shows again, at size 1, after this change. Tests: tst_imagemissingsize runs the binary's --resave and --export-svg on a fixture with six small pictures: size missing, "0", "nan", "big", "0.5" and "2". The first four fail on master (saved as 0, 0, nan, 0) and the export draws only 3 of the 6 pictures there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Beat Hangartner <beat@hangartners.ch>
This commit is contained in:
@@ -1686,7 +1686,12 @@ bool DiagramImageItem::fromXml(const QDomElement &e)
|
||||
// pivot), the same two-tier fallback QetShapeItem's own fromXml()
|
||||
// already uses for its identical <transform> element.
|
||||
m_transform.rotation = e.attribute("rotation").toDouble();
|
||||
m_transform.scaleX = e.attribute("size").toDouble();
|
||||
//A missing, unreadable, non-finite or zero size would scale the
|
||||
//picture to nothing (and a resave wrote size="0" back): use 1,
|
||||
//the size a picture is added with, as the <transform> branch does
|
||||
bool size_ok = false;
|
||||
const qreal size = e.attribute("size").toDouble(&size_ok);
|
||||
m_transform.scaleX = (size_ok && qIsFinite(size) && size != 0) ? size : 1;
|
||||
m_transform.scaleY = m_transform.scaleX;
|
||||
m_transform.pivot = imageRect().center();
|
||||
m_pivotIsCustom = false;
|
||||
|
||||
@@ -1024,6 +1024,19 @@ target_compile_definitions(tst_terminaluuids PRIVATE
|
||||
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\""
|
||||
"QET_EXAMPLES_DIR=\"${QET_DIR}/examples\"")
|
||||
|
||||
# A picture whose size attribute is missing, unreadable, "nan" or 0 is
|
||||
# loaded at size 1, not 0: the real binary's --resave and --export-svg on
|
||||
# fixtures/image_missing_size.qet.
|
||||
add_executable(
|
||||
tst_imagemissingsize
|
||||
tst_imagemissingsize.cpp)
|
||||
add_test(NAME tst_imagemissingsize COMMAND tst_imagemissingsize)
|
||||
set_tests_properties(tst_imagemissingsize PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
|
||||
add_dependencies(tst_imagemissingsize qelectrotech)
|
||||
target_link_libraries(tst_imagemissingsize PRIVATE Qt::Test Qt::Xml)
|
||||
target_compile_definitions(tst_imagemissingsize PRIVATE
|
||||
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
|
||||
|
||||
# Sequential numbers saved the old way, as sequ_1/.../seqhf_1 attributes,
|
||||
# are all read: the real binary's --resave on
|
||||
# fixtures/legacy_sequential_attributes.qet, whose element and conductor
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<project title="Pictures without a usable size" uuid="{7b2e1d4f-3c55-4e2f-9a1b-4d6e8f0c2b00}" version="0.200.1">
|
||||
<properties>
|
||||
<property name="saveddate" show="1">10/2/26</property>
|
||||
<property name="saveddate-eu" show="1">02-10-2026</property>
|
||||
<property name="saveddate-us" show="1">2026-10-02</property>
|
||||
<property name="savedfilename" show="1">image_missing_size</property>
|
||||
<property name="savedtime" show="1">18:39</property>
|
||||
</properties>
|
||||
<usage enabled="true" time_spent="0"/>
|
||||
<newdiagrams>
|
||||
<border cols="17" colsize="60" displaycols="true" displayrows="true" rows="8" rowsize="80"/>
|
||||
<inset author="" auto_page_num="" date="null" displayAt="bottom" filename="" folio="" indexrev="" locmach="" plant="" title="" version=""/>
|
||||
<conductors bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="0" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
|
||||
<report label="%f-%l%c"/>
|
||||
<xrefs>
|
||||
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="coil" xrefpos="AlignBottom"/>
|
||||
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="commutator" xrefpos="AlignBottom"/>
|
||||
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="plc" xrefpos="AlignBottom"/>
|
||||
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="protection" xrefpos="AlignBottom"/>
|
||||
</xrefs>
|
||||
<conductors_autonums auto_break_conductors="false" current_autonum="" freeze_new_conductors="false"/>
|
||||
<folio_autonums/>
|
||||
<element_autonums current_autonum="" freeze_new_elements="false"/>
|
||||
<guides/>
|
||||
</newdiagrams>
|
||||
<diagram author="" auto_page_num="" cols="17" colsize="60" date="null" displayAt="bottom" displaycols="true" displayrows="true" filename="" folio="" freezeNewConductor="false" freezeNewElement="false" height="660" indexrev="" locmach="" order="1" plant="" rows="8" rowsize="80" title="" uuid="{7b2e1d4f-3c55-4e2f-9a1b-4d6e8f0c2b10}" version="0.200.1-dev">
|
||||
<defaultconductor bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="0" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
|
||||
<inputs/>
|
||||
<images>
|
||||
<image z="0" rotation="0" y="100" x="100" is_movable="1">iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC</image>
|
||||
<image z="0" rotation="0" y="160" x="100" size="0" is_movable="1">iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC</image>
|
||||
<image z="0" rotation="0" y="220" x="100" size="nan" is_movable="1">iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC</image>
|
||||
<image z="0" rotation="0" y="280" x="100" size="big" is_movable="1">iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC</image>
|
||||
<image z="0" rotation="0" y="340" x="100" size="0.5" is_movable="1">iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC</image>
|
||||
<image z="0" rotation="0" y="400" x="100" size="2" is_movable="1">iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC</image>
|
||||
</images>
|
||||
</diagram>
|
||||
<collection>
|
||||
<category name="import">
|
||||
<names>
|
||||
<name lang="en">Imported elements</name>
|
||||
</names>
|
||||
</category>
|
||||
</collection>
|
||||
</project>
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <QtTest>
|
||||
#include <QDir>
|
||||
#include <QDomDocument>
|
||||
#include <QProcess>
|
||||
#include <QTemporaryDir>
|
||||
|
||||
/**
|
||||
A picture on a folio (<image>, without a <transform> child) whose size
|
||||
attribute is missing, unreadable, "nan" or 0 is loaded at size 1. It
|
||||
used to be loaded at size 0, so it was invisible, not exported, and a
|
||||
resave wrote size="0" back. Runs the real binary's --resave and
|
||||
--export-svg on fixtures/image_missing_size.qet: six 20x10 pictures,
|
||||
one per size value, told apart by their y position.
|
||||
*/
|
||||
class tst_imagemissingsize : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QTemporaryDir m_dir;
|
||||
QString m_fixture;
|
||||
QDomDocument m_resaved;
|
||||
|
||||
static bool runQet(const QStringList &arguments)
|
||||
{
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen"));
|
||||
QProcess proc;
|
||||
proc.setProcessEnvironment(env);
|
||||
proc.start(QStringLiteral(QET_TEST_BINARY_PATH), arguments);
|
||||
return proc.waitForFinished(60000)
|
||||
&& proc.exitStatus() == QProcess::NormalExit
|
||||
&& proc.exitCode() == 0;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
QVERIFY2(QFile::exists(QStringLiteral(QET_TEST_BINARY_PATH)), "qelectrotech binary not found");
|
||||
QVERIFY(m_dir.isValid());
|
||||
m_fixture = QFINDTESTDATA("fixtures/image_missing_size.qet");
|
||||
QVERIFY2(!m_fixture.isEmpty(), "fixture project not found");
|
||||
const QString out = m_dir.filePath(QStringLiteral("resaved.qet"));
|
||||
QVERIFY2(runQet({QStringLiteral("--resave"), m_fixture, out}), "--resave failed");
|
||||
QFile file(out);
|
||||
QVERIFY(file.open(QIODevice::ReadOnly));
|
||||
QVERIFY(m_resaved.setContent(&file));
|
||||
}
|
||||
|
||||
void savedSize_data()
|
||||
{
|
||||
QTest::addColumn<QString>("y");
|
||||
QTest::addColumn<QString>("size");
|
||||
QTest::newRow("missing") << "100" << "1";
|
||||
QTest::newRow("0") << "160" << "1";
|
||||
QTest::newRow("nan") << "220" << "1";
|
||||
QTest::newRow("not a number") << "280" << "1";
|
||||
// Usable sizes are kept, below and above 1.
|
||||
QTest::newRow("0.5") << "340" << "0.5";
|
||||
QTest::newRow("2") << "400" << "2";
|
||||
}
|
||||
|
||||
void savedSize()
|
||||
{
|
||||
QFETCH(QString, y);
|
||||
QFETCH(QString, size);
|
||||
const QDomNodeList list = m_resaved.elementsByTagName(QStringLiteral("image"));
|
||||
QDomElement found;
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
const QDomElement e = list.at(i).toElement();
|
||||
if (e.attribute(QStringLiteral("y")) == y) found = e;
|
||||
}
|
||||
QVERIFY2(!found.isNull(), "picture not found in the resaved project");
|
||||
QCOMPARE(found.attribute(QStringLiteral("size")), size);
|
||||
}
|
||||
|
||||
// All six pictures are drawn in the export.
|
||||
void allPicturesAreExported()
|
||||
{
|
||||
const QString dir = m_dir.filePath(QStringLiteral("svg"));
|
||||
QVERIFY(QDir().mkpath(dir));
|
||||
QVERIFY2(runQet({QStringLiteral("--export-svg"), m_fixture, dir}), "--export-svg failed");
|
||||
const QStringList files = QDir(dir).entryList({QStringLiteral("*.svg")}, QDir::Files);
|
||||
QCOMPARE(files.size(), 1);
|
||||
QFile svg(QDir(dir).filePath(files.first()));
|
||||
QVERIFY(svg.open(QIODevice::ReadOnly));
|
||||
QCOMPARE(QString::fromUtf8(svg.readAll()).count(QStringLiteral("<image")), 6);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_imagemissingsize)
|
||||
#include "tst_imagemissingsize.moc"
|
||||
Reference in New Issue
Block a user