mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-28 21:34:12 +02:00
7cd04f2a14
Diagram::m_uuid was created in the constructor and never written, so a folio got a new uuid on every load. Inside a running instance that is enough (the project database keys on it), but nothing outside it could tell which folio is which: in the file, folios were only identified by their position. Motivation More and more .qet projects live in version control -- a Git repository on GitHub or GitLab, reviewed through pull requests, sometimes edited by several people -- or are synchronised through a cloud or key-value store. A .qet file is plain XML, so in principle it can be diffed, merged and split up, but only if the same folio can be recognised in two versions of the file. Today it cannot: - Inserting, deleting or reordering a folio shifts every following <diagram> element. A line-based diff, and GitHub's review view, then pair up unrelated folios and show far more change than was made. - A three-way merge of two branches that both touched the project has no way to match "folio 3" on one side with "folio 3" on the other if either side reordered folios. - Any tool that wants to say "folio X changed in this commit", keep per-folio history, lock a single folio, or store folios as separate objects has nothing stable to key on. The title and the folio number are user-editable and not unique. Element uuids are already persisted and used for cross-folio links, so the file format already relies on uuids for identity; the folio itself was the missing piece. A stable folio uuid is the prerequisite for later work towards better version control support: per-folio diffs and locks (check-out / check-in), and possibly storing a project as a directory with one file per folio. Change Write the uuid as an attribute of <diagram> when the whole content is saved, and restore it first thing when the project is loaded, before any item is created. Older versions ignore the attribute, so files stay readable in both directions. Folios without a uuid: why not a random one The obvious migration -- keep the random uuid created by the constructor and save it -- conflicts with #754 / #779: saving an unmodified project must give the same bytes every time. Every example project predates the attribute, so each load would invent different uuids and write them out. Measured on the 24 example projects (resaved 3-4x each from the same original, QT_HASH_SEED=0 so that QDom's attribute order is stable, isolated HOME per run): upstream master 23/24 byte-identical persist, random uuid 0/24 persist, derived uuid (this) 23/24 The remaining project, schema_indus.qet, differs only in element uuids, the known residual #779 leaves for elements; its folio uuid is stable. This is the same problem #779 solved for conductors by not writing an invented uuid back at all. That is not an option here: legacy folios would never get a persistent uuid, which is the whole point of the change. Instead, a folio without a uuid gets a name-based (version 5) uuid, derived only from data read from the file: QUuid::createUuidV5(<fixed QET folio namespace>, "legacy" + project title + position of the folio in the file + folio title) - The same input file always yields the same uuids, so resaving an unmodified legacy project stays reproducible. - The uuid is derived once, at load time, and saved from then on. After that it is read, never recomputed: renaming, reordering or editing the folio later does not change it. Renaming in the same session as the migration does not change it either, since it was derived from the title as loaded. - Two people opening the same legacy file on different branches get the same uuid for each folio, even if one of them reorders or renames folios before saving. With random uuids the two branches would disagree about every folio and a later merge could not match them. - The folio content is deliberately not part of the name: QDom keeps attributes in a hash whose iteration order changes between runs, so hashing the content would need a canonical form for no real gain. Folios are only guaranteed unique within their project. Two unrelated legacy projects with the same title and the same first folio title get the same uuid for that folio; anything keying folios globally has to combine the folio uuid with a project identifier. (The project uuid is not persisted yet; that is a separate change.) Duplicated uuids A hand-edited or merged file can contain the same uuid twice, e.g. a folio copied by duplicating its XML block. Since the uuid is used as a key, the second folio gets a derived uuid as well ("duplicate" + the clashing uuid + the same inputs as above), so this case is reproducible too. Should a derived uuid ever be taken already, which takes a hand-crafted file, the name is salted with a counter until it is free. The namespace uuid is fixed in the code and must never change, or every legacy folio would get a different uuid. Tests (Qt 6.4, offscreen, qelectrotech --resave / --set-titleblock) - 24 example projects, 3-4 resaves each from the same original: results above; all folio uuids identical across runs, no duplicates within any project. - Resaving an already migrated file is byte-identical to the first output. - Renaming a folio in a migrated file keeps its uuid. - Swapping two <diagram> blocks in a migrated file: each uuid moves with its folio. - Migrating and renaming in the same run (--set-titleblock title=... on a legacy file) gives the same uuids as a plain resave. - A file with a duplicated uuid: the second folio gets a new uuid, the same one on every run. - A migrated file opened with upstream master loads normally; the attribute is ignored and dropped on save. Refs #754, #779 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDyt4txaott5JyPNGQaeVp