Compare commits

...

9 Commits

Author SHA1 Message Date
Laurent Trinques bfe2aa26a0 Merge pull request #786 from ispyisail/fix/remove-dead-exclude-bom-clause
Remove dead exclude_from_bom clause from ElementQueryWidget
2026-08-25 06:52:29 +02:00
Laurent Trinques 4bde81937d Merge pull request #789 from ispyisail/fix/removediagram-safe-teardown
Fix segfault when a project is destroyed with a diagram still pending deleteLater()
2026-08-25 06:50:50 +02:00
Laurent Trinques 91116f7044 Merge pull request #784 from plc-user/master
fix problem with PDF-links in files with brackets in name
2026-08-25 06:47:35 +02:00
Laurent Trinques 8246c8aaba Merge pull request #790 from cezlom/pt_BR-translation-update
Complete the Brazilian Portuguese translation
2026-08-25 06:12:34 +02:00
Cezar Machado 8ca62c4a17 Fix remaining degree sign mistranslations in pt_BR (º → °)
Follow-up to the review of #790: four pre-existing messages whose source
is the DEGREE SIGN (U+00B0) were translated with the MASCULINE ORDINAL
INDICATOR (U+00BA) — GeneralConfigurationPage, IndiTextPropertiesWidget,
ReplaceConductorDialog and TextEditor. They render as an ordinal in the
rotation spin box suffixes.

Also fixes punctuation in the two SelectAutonumW help texts: a stray
space in "N ° página" / "n ° da página" and two unbalanced quotes.

Sources, comments, message count and ordering are untouched (2850
messages, 0 unfinished); .qm regenerated with lrelease.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N9qWZfNpKZqrAzUE2QB3TJ
2026-08-25 02:06:35 +00:00
Cezar Machado 0394503c0b Complete the Brazilian Portuguese translation
Finish the 364 messages still marked unfinished in lang/qet_pt_BR.ts,
bringing pt_BR from 87.2% to 100% of the 2850 messages. Of those, 228
were empty and are translated here; the remaining 136 carried Linguist
suggestions that were reviewed, 14 of them corrected. Several contexts
were previously untranslated in full: ContactGroupSelectionDialog,
PlcLinkWidget, TerminalNumberingDialog, ShortcutsConfigPage,
BackupDialog, DiagnosticsReportDialog, GuidesPropertiesWidget,
PdfPagesDialog and EdzArchive.

Terminology follows what the file already established: "borne" ->
"terminal", "bornier" -> "régua de terminais", "folio" -> "página",
"cartouche" -> "bloco de legenda", "schéma" -> "esquema",
"maître/esclave" -> "mestre/escravo", "pivoter" -> "girar". PLC terms
use the Brazilian abbreviation CLP, and NO/NC contacts use NA/NF.

Notable fixes among the reviewed suggestions: "Annuler" read "Desfazer"
(undo) where it is a dialog button next to OK, and the degree symbol
used U+00BA MASCULINE ORDINAL INDICATOR instead of U+00B0 DEGREE SIGN.

Only <translation> elements are touched; sources, locations and
comments are unchanged. lang/qet_pt_BR.qm is regenerated with lrelease.
2026-08-24 21:44:16 +00:00
ispyisail e5935c75d1 Fix segfault when a project is destroyed with a diagram still pending deleteLater()
QETProject::removeDiagram() detaches a diagram from m_diagrams_list and
schedules it via deleteLater(), but that deferred delete only runs on
a future event-loop iteration. If ~QETProject() runs first (e.g. a
CLI/headless caller with no event loop, or a project closed
immediately after removeDiagram()), the diagram is still a QObject
child of the project and gets destroyed later by QObject's own
automatic child cleanup -- which runs after m_data_base has already
been torn down as a plain C++ member. Diagram::~Diagram() calls back
into dataBase()->removeElement() for each of its elements, so that
ordering is a use-after-free (SIGSEGV in QSqlResult::exec()).

Delete any such still-parented diagrams synchronously in ~QETProject()
while m_data_base is still alive, before the base QObject destructor
runs. Any deleteLater() event that does eventually fire afterward is a
safe no-op on an already-deleted QObject.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 06:59:02 +12:00
plc-user 2e49f4588a fix problem with PDF-links in files with brackets in name 2026-08-24 18:24:30 +02:00
ispyisail ccf545d30c Remove dead exclude_from_bom clause from ElementQueryWidget's query builder
ElementQueryWidget::queryStr() reads FROM element_nomenclature_view, and that
view already excludes flagged elements in its own WHERE clause (see
createElementNomenclatureView() in projectdatabase.cpp). This widget then
added a second condition on top: "exclude_from_bom IS NULL OR
exclude_from_bom != '1'" -- but nothing anywhere ever writes the literal
string "1" to this key (the only writer stores "true"/"false"), so the
clause was true for every row that could possibly reach this point and did
nothing.

Confirmed dead three separate ways while reviewing qelectrotech#765: reading
the value only ever comes back "true" or "false" (never "1"), an
exclude_from_bom="1" element still appeared in --export-bom output on a test
fixture, and the surrounding filter_ construction shows this AND'd clause
cannot change the query's result set regardless of what filter_ already
holds. Confirmed it a fourth way once already, by initially misreading this
same clause as evidence the feature was broken -- it was reading the WHERE
without the FROM three lines above, which is exactly the trap being removed
here for the next reader.

ElementQueryWidget backs the BOM export dialog and the diagram table
properties widget; neither has a headless CLI equivalent, so this could not
be verified end-to-end through --export-bom the way the case-insensitivity
fix could. Verified instead: the file compiles clean, and a
load/resave/--export-bom smoke test on examples/tremie_vibrante.qet shows no
change in app behaviour (98 components, matching the pre-change baseline --
expected, since --export-bom does not go through this widget at all).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 22:28:00 +12:00
5 changed files with 440 additions and 384 deletions
BIN
View File
Binary file not shown.
+411 -379
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -378,10 +378,10 @@ QString ElementQueryWidget::queryStr() const
where.clear();
}
QString exclude_condition = "(exclude_from_bom IS NULL OR exclude_from_bom != '1')";
filter_ += " AND " + exclude_condition;
// -------------------------------------------------------------
// exclude_from_bom is already filtered by element_nomenclature_view
// (see createElementNomenclatureView() in projectdatabase.cpp); this
// widget's query reads FROM that view, so a flagged element never
// reaches this point in the first place.
if (where.isEmpty() && !filter_.isEmpty()) {
filter_.remove(0, 4); //Remove the first " AND" of filter.
+1 -1
View File
@@ -228,7 +228,7 @@ void convertUriToGoTo(const QString &pdfPath)
// Find closing ')' of the URI value
int uriStart = found + sUri.size();
int closeParen = data.indexOf(')', uriStart);
int closeParen = data.indexOf(")\n", uriStart);
if (closeParen == -1) {
// Malformed — copy rest verbatim
out.append(data.mid(found));
+24
View File
@@ -174,6 +174,30 @@ QETProject::~QETProject()
delete diagram;
m_diagrams_list.removeOne(diagram);
}
//A diagram can be detached from this project (detachDiagram(), used by
//both removeDiagram() and RemoveDiagramCommand::redo()) and scheduled
//for deferred deletion via deleteLater(), without that deletion having
//actually run yet -- deleteLater() only fires on the next event-loop
//iteration, and nothing guarantees one runs before this destructor
//does. Such a diagram is no longer in m_diagrams_list (so the loop
//above never touches it) but is still a QObject child of this project
//(Diagram's constructor passes `project` straight to QGraphicsScene's
//parent argument). Left alone, it is destroyed later by QObject's own
//automatic child cleanup in ~QObject(), which runs AFTER m_data_base
//(a plain value member, destroyed by ordinary C++ member teardown)
//has already been destroyed -- and Diagram's destructor calls back
//into dataBase()->removeElement() for each of its elements, so that
//ordering is a use-after-free (confirmed by crash: SIGSEGV in
//QSqlResult::exec(), called from Diagram::~Diagram() by way of
//Diagram::removeItem(), by way of QObjectPrivate::deleteChildren()).
//Delete any such stragglers now, synchronously, while m_data_base is
//still alive. The deleteLater() event, if it is ever processed
//afterward, is a safe no-op on an already-deleted QObject.
const auto orphaned_diagrams = findChildren<Diagram *>(QString(), Qt::FindDirectChildrenOnly);
for (Diagram *diagram : orphaned_diagrams) {
delete diagram;
}
}
/**