Compare commits

...

3 Commits

Author SHA1 Message Date
Laurent Trinques bbc995c91e Merge pull request #835 from ispyisail/fix/wiring-list-numeric-order
Wiring list: numeric wire-number order, UTF-8 BOM and atomic write
2026-09-11 08:01:58 +02:00
ispyisail 2322e6fd12 Write the wiring list CSV atomically, with a UTF-8 byte order mark
Second of @scorpio810's review notes on #630:

  exportWiring() follows the existing CLI exporters (QTextStream, plain
  QFile). On Qt6 the output is UTF-8, so encoding is fine. Once #830 is
  in, it could optionally reuse BomExport::writeCsv() to get a BOM,
  which Excel needs to detect UTF-8 when opening the file directly, and
  an atomic write.

Done directly rather than waiting on #830, since neither half depends on
it and both are small.

The bytes were already UTF-8; what was missing is the mark that tells
Excel so. Opening a .csv without one, Excel falls back to the local
8-bit codepage and mangles any accented element label -- the common case
for this project's users.

QSaveFile replaces QFile so a failure part-way through leaves the
previous file intact instead of a truncated one. QSaveFile is already the
codebase's pattern for this (QET::writeToFile, qet.cpp:664).

Verified on perceuse.qet: output now starts ef bb bf, the header follows
intact, all 156 rows are preserved, and the file parses as utf-8-sig.
Pointing the exporter at a missing project leaves an existing target file
untouched, where before it would have been truncated.

Left the other CLI exporters alone. They share the same pattern, but
changing exportBom() would add a BOM to output that existing scripts
already consume, which is a behaviour change outside the scope of this
review note.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 12:52:19 +12:00
ispyisail b5722c3f2a Sort the wiring list by wire number as a number, not as text
Follows @scorpio810's review note on merging #630:

  ORDER BY diagram_position, wire_number sorts wire numbers as text,
  so "10" comes before "9".

Confirmed against the corpus: perceuse.qet put 111 before 12, and
affuteuse_250h.qet put 45 before 5. industrial.qet happened to look
correct only because its wire numbers are all the same width.

Wire numbers are free text and are not always numeric -- perceuse.qet
also carries an unresolved "%sequ_1" -- so the ordering has to cope with
both. Numeric values come first, ordered by value; anything else follows,
ordered as text. The trailing wire_number keeps ties stable.

Fixed in both places the query appears: the CLI exporter and the wiring
list dialog. They had the same ORDER BY, so fixing only one would have
made the dialog and --export-wiring disagree about the order of the same
data.

Verified on perceuse, affuteuse_250h, industrial and tremie_vibrante:
zero out-of-order numeric pairs afterwards, row counts unchanged, and
"%sequ_1" now sorts after the numbers rather than among them. Folio 3 of
perceuse.qet reads 0 1 2 3 4 4 5 5 6 6 7 7 12 12 where it previously
interleaved 111 before 12.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 12:43:07 +12:00
2 changed files with 31 additions and 7 deletions
+23 -6
View File
@@ -39,6 +39,7 @@
#include <QDomDocument>
#include <QDate>
#include <QFile>
#include <QSaveFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
@@ -564,7 +565,14 @@ int exportWiring(QETProject &project, const QString &output)
QSqlQuery query = project.dataBase()->newQuery(
"SELECT " % columns.join(", ") %
" FROM wiring_list_view ORDER BY diagram_position, wire_number");
" FROM wiring_list_view"
//Wire numbers are text, so a plain sort puts "10" before "9".
//Numeric ones first, ordered by value; anything non-numeric after,
//ordered as text. The trailing wire_number keeps ties stable.
" ORDER BY diagram_position,"
" CASE WHEN wire_number GLOB '[0-9]*' THEN 0 ELSE 1 END,"
" CAST(wire_number AS INTEGER),"
" wire_number");
if (!query.exec()) {
err << "Wiring list query failed: " << query.lastError().text() << "\n";
return 1;
@@ -580,14 +588,23 @@ int exportWiring(QETProject &project, const QString &output)
++rows;
}
QFile file(output);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
//Written through QSaveFile so a failure part-way leaves the previous
//file intact rather than a truncated one, and with a UTF-8 byte order
//mark: without it Excel opens a .csv as the local 8-bit codepage and
//mangles any accented element label. Qt writes UTF-8 by default, so
//the bytes were already right -- the mark is what tells Excel so.
QSaveFile file(output);
if (!file.open(QIODevice::WriteOnly)) {
err << "Cannot open '" << output << "' for writing.\n";
return 1;
}
QTextStream fout(&file);
fout << csv;
file.close();
static const char utf8_bom[] = "\xEF\xBB\xBF";
file.write(utf8_bom, 3);
file.write(csv.toUtf8());
if (!file.commit()) {
err << "Cannot write '" << output << "': " << file.errorString() << "\n";
return 1;
}
out << "Exported " << rows << " conductor(s) -> " << output << "\n";
return 0;
}
+8 -1
View File
@@ -52,7 +52,14 @@ WiringListDialog::WiringListDialog(QETProject *project, QWidget *parent) :
"SELECT wire_number, from_element_label, from_terminal,"
" to_element_label, to_terminal, diagram_position"
" FROM wiring_list_view"
" ORDER BY diagram_position, wire_number"),
//Wire numbers are text, so a plain sort puts "10" before "9".
//Numeric ones first, ordered by value; anything non-numeric
//after, ordered as text. The trailing wire_number keeps ties
//stable.
" ORDER BY diagram_position,"
" CASE WHEN wire_number GLOB '[0-9]*' THEN 0 ELSE 1 END,"
" CAST(wire_number AS INTEGER),"
" wire_number"),
m_project->dataBase()->database());
model->setHeaderData(0, Qt::Horizontal, tr("Fil", "column title"));