mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-19 20:44:16 +02:00
Merge master into fix/joined-wire-uuid
The conflict was tests/qttest/CMakeLists.txt, where #1520 added tst_savedstamps at the place this branch adds tst_joinedwireuuid. Both are kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -847,13 +847,15 @@ bool projectDataBase::populateFromDocument(const QDomDocument &document, QString
|
||||
}
|
||||
}
|
||||
|
||||
query.prepare(QStringLiteral("INSERT INTO link (element_uuid, linked_uuid, group_index) "
|
||||
"VALUES (:element_uuid, :linked_uuid, :group_index)"));
|
||||
query.prepare(QStringLiteral("INSERT INTO link (element_uuid, linked_uuid, group_index, ord) "
|
||||
"VALUES (:element_uuid, :linked_uuid, :group_index, :ord)"));
|
||||
for (const DocumentElement &element : std::as_const(elements)) {
|
||||
int ord = 0;
|
||||
for (const auto &link : element.links) {
|
||||
query.bindValue(QStringLiteral(":element_uuid"), element.uuid);
|
||||
query.bindValue(QStringLiteral(":linked_uuid"), link.first);
|
||||
query.bindValue(QStringLiteral(":group_index"), link.second >= 0 ? QVariant(link.second) : QVariant());
|
||||
query.bindValue(QStringLiteral(":ord"), ord++);
|
||||
if (!query.exec()) {
|
||||
qDebug() << "projectDataBase::populateFromDocument link insert error : " << query.lastError();
|
||||
}
|
||||
@@ -1092,7 +1094,7 @@ QList<QUuid> projectDataBase::linkedSymbols(const QUuid &element) const
|
||||
{
|
||||
QList<QUuid> linked;
|
||||
QSqlQuery query(m_data_base);
|
||||
query.prepare(QStringLiteral("SELECT linked_uuid FROM link WHERE element_uuid = :uuid ORDER BY rowid"));
|
||||
query.prepare(QStringLiteral("SELECT linked_uuid FROM link WHERE element_uuid = :uuid ORDER BY ord, rowid"));
|
||||
query.bindValue(QStringLiteral(":uuid"), element.toString());
|
||||
if (query.exec()) {
|
||||
while (query.next())
|
||||
@@ -2602,12 +2604,14 @@ bool projectDataBase::createDataBase()
|
||||
|
||||
//Create the link table: one row per element and element it is
|
||||
//linked to -- a coil and its contacts, a pair of folio reports --
|
||||
//from each side, with the contact group the element saved for it.
|
||||
//from each side, with the contact group the element saved for it,
|
||||
//and its place (ord) in the order the element saves its links.
|
||||
const QString link_table(QStringLiteral(
|
||||
"CREATE TABLE link ("
|
||||
"element_uuid VARCHAR(50) NOT NULL, "
|
||||
"linked_uuid VARCHAR(50) NOT NULL, "
|
||||
"group_index INTEGER, "
|
||||
"ord INTEGER NOT NULL DEFAULT 0, "
|
||||
"PRIMARY KEY (element_uuid, linked_uuid), "
|
||||
"FOREIGN KEY (element_uuid) REFERENCES element (uuid))"));
|
||||
if (!query_.exec(link_table)) {
|
||||
@@ -3868,10 +3872,11 @@ QString projectDataBase::prefillReport() const
|
||||
void projectDataBase::populateLinkTable()
|
||||
{
|
||||
m_dirty_link_elements.clear();
|
||||
const QSet<QUuid> waiting = waitingSymbols();
|
||||
QSqlQuery query(m_data_base);
|
||||
query.exec(QStringLiteral("DELETE FROM link"));
|
||||
query.prepare(QStringLiteral("INSERT INTO link (element_uuid, linked_uuid, group_index) "
|
||||
"VALUES (:element_uuid, :linked_uuid, :group_index)"));
|
||||
query.prepare(QStringLiteral("INSERT INTO link (element_uuid, linked_uuid, group_index, ord) "
|
||||
"VALUES (:element_uuid, :linked_uuid, :group_index, :ord)"));
|
||||
|
||||
for (const auto &diagram : m_project->folios())
|
||||
{
|
||||
@@ -3885,23 +3890,7 @@ void projectDataBase::populateLinkTable()
|
||||
}
|
||||
const ElementProvider ep(diagram);
|
||||
for (const auto &elmt : ep.find(allElementTypes()))
|
||||
{
|
||||
QList<std::pair<QString, int>> rows;
|
||||
for (Element *linked : elmt->linkedElements())
|
||||
rows.append({linked->uuid().toString(), elmt->groupIndexForElement(linked)});
|
||||
//Partners on a folio not built, which it will be linked to
|
||||
for (const auto &waiting : elmt->waitingLinks())
|
||||
rows.append({waiting.first.toString(), waiting.second});
|
||||
for (const auto &row : std::as_const(rows))
|
||||
{
|
||||
query.bindValue(QStringLiteral(":element_uuid"), elmt->uuid().toString());
|
||||
query.bindValue(QStringLiteral(":linked_uuid"), row.first);
|
||||
query.bindValue(QStringLiteral(":group_index"), row.second >= 0 ? QVariant(row.second) : QVariant());
|
||||
if (!query.exec()) {
|
||||
qDebug() << "projectDataBase::populateLinkTable insert error : " << query.lastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
insertLinkRows(query, elmt, waiting);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3927,6 +3916,83 @@ void projectDataBase::queueLinks(Element *element)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::linkRowMismatches
|
||||
A test and debugging aid (QET_CHECK_LINK_ROWS): the placed
|
||||
symbols whose link rows are not the links they save, in order
|
||||
(Element::linksToSave(), insertLinkRows())
|
||||
@return one entry per such symbol: its uuid
|
||||
*/
|
||||
QStringList projectDataBase::linkRowMismatches()
|
||||
{
|
||||
flushLinks();
|
||||
const QSet<QUuid> waiting = waitingSymbols();
|
||||
QStringList mismatches;
|
||||
QSqlQuery query(m_data_base);
|
||||
query.prepare(QStringLiteral("SELECT linked_uuid, group_index FROM link "
|
||||
"WHERE element_uuid = :uuid ORDER BY ord, rowid"));
|
||||
for (auto it = m_placed_elements.cbegin() ; it != m_placed_elements.cend() ; ++it)
|
||||
{
|
||||
Element *element = it.value();
|
||||
if (!element) {
|
||||
continue;
|
||||
}
|
||||
QList<std::pair<QString, int>> expected;
|
||||
for (const Element::SavedLink &link : element->linksToSave(waiting))
|
||||
if (!link.built || m_placed_elements.contains(link.uuid, link.built))
|
||||
expected.append({link.uuid.toString(), link.group_index});
|
||||
QList<std::pair<QString, int>> rows;
|
||||
query.bindValue(QStringLiteral(":uuid"), element->uuid().toString());
|
||||
if (query.exec())
|
||||
while (query.next())
|
||||
rows.append({query.value(0).toString(),
|
||||
query.value(1).isNull() ? -1 : query.value(1).toInt()});
|
||||
if (rows != expected) {
|
||||
mismatches << element->uuid().toString();
|
||||
}
|
||||
}
|
||||
return mismatches;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::waitingSymbols
|
||||
@return the symbols on folios not built yet (lazy folios): partners a
|
||||
symbol keeps its saved links to until they are built
|
||||
*/
|
||||
QSet<QUuid> projectDataBase::waitingSymbols() const
|
||||
{
|
||||
return m_project && m_project->unloadedFolioCount() ? m_project->symbolsOnUnbuiltFolios()
|
||||
: QSet<QUuid>();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::insertLinkRows
|
||||
Write @p element's link rows with @p insert (prepared with :element_uuid,
|
||||
:linked_uuid, :group_index and :ord): its partners as it saves them
|
||||
(Element::linksToSave()), in that order, so the rows and the file say
|
||||
the same: @p waiting is the symbols on folios not built, as a save
|
||||
takes them (waitingSymbols()). A built partner the project no longer has (on a removed
|
||||
folio, linked still for the undo) gets no row.
|
||||
*/
|
||||
void projectDataBase::insertLinkRows(QSqlQuery &insert, Element *element,
|
||||
const QSet<QUuid> &waiting)
|
||||
{
|
||||
int ord = 0;
|
||||
for (const Element::SavedLink &link : element->linksToSave(waiting))
|
||||
{
|
||||
if (link.built && !m_placed_elements.contains(link.uuid, link.built)) {
|
||||
continue;
|
||||
}
|
||||
insert.bindValue(QStringLiteral(":element_uuid"), element->uuid().toString());
|
||||
insert.bindValue(QStringLiteral(":linked_uuid"), link.uuid.toString());
|
||||
insert.bindValue(QStringLiteral(":group_index"), link.group_index >= 0 ? QVariant(link.group_index) : QVariant());
|
||||
insert.bindValue(QStringLiteral(":ord"), ord++);
|
||||
if (!insert.exec()) {
|
||||
qDebug() << "projectDataBase::insertLinkRows insert error : " << insert.lastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::flushLinks
|
||||
Write the link rows of every element queued by linksChanged()
|
||||
@@ -3939,12 +4005,13 @@ void projectDataBase::flushLinks()
|
||||
|
||||
const auto dirty = m_dirty_link_elements;
|
||||
m_dirty_link_elements.clear();
|
||||
const QSet<QUuid> waiting = waitingSymbols();
|
||||
const bool own_transaction = m_data_base.transaction();
|
||||
QSqlQuery remove(m_data_base);
|
||||
remove.prepare(QStringLiteral("DELETE FROM link WHERE element_uuid = :uuid"));
|
||||
QSqlQuery insert(m_data_base);
|
||||
insert.prepare(QStringLiteral("INSERT INTO link (element_uuid, linked_uuid, group_index) "
|
||||
"VALUES (:element_uuid, :linked_uuid, :group_index)"));
|
||||
insert.prepare(QStringLiteral("INSERT INTO link (element_uuid, linked_uuid, group_index, ord) "
|
||||
"VALUES (:element_uuid, :linked_uuid, :group_index, :ord)"));
|
||||
for (const QPointer<Element> &element : dirty)
|
||||
{
|
||||
if (!element) {
|
||||
@@ -3960,32 +4027,7 @@ void projectDataBase::flushLinks()
|
||||
if (!m_placed_elements.contains(element->uuid(), element)) {
|
||||
continue;
|
||||
}
|
||||
for (Element *linked : element->linkedElements())
|
||||
{
|
||||
//A symbol on a removed folio stays linked, for the undo,
|
||||
//but the project no longer has it
|
||||
if (!m_placed_elements.contains(linked->uuid(), linked)) {
|
||||
continue;
|
||||
}
|
||||
const int group = element->groupIndexForElement(linked);
|
||||
insert.bindValue(QStringLiteral(":element_uuid"), element->uuid().toString());
|
||||
insert.bindValue(QStringLiteral(":linked_uuid"), linked->uuid().toString());
|
||||
insert.bindValue(QStringLiteral(":group_index"), group >= 0 ? QVariant(group) : QVariant());
|
||||
if (!insert.exec()) {
|
||||
qDebug() << "projectDataBase::flushLinks insert error : " << insert.lastError();
|
||||
}
|
||||
}
|
||||
//Partners on a folio not built (lazy folios), which it will
|
||||
//be linked to once that folio is
|
||||
for (const auto &waiting : element->waitingLinks())
|
||||
{
|
||||
insert.bindValue(QStringLiteral(":element_uuid"), element->uuid().toString());
|
||||
insert.bindValue(QStringLiteral(":linked_uuid"), waiting.first.toString());
|
||||
insert.bindValue(QStringLiteral(":group_index"), waiting.second >= 0 ? QVariant(waiting.second) : QVariant());
|
||||
if (!insert.exec()) {
|
||||
qDebug() << "projectDataBase::flushLinks insert error : " << insert.lastError();
|
||||
}
|
||||
}
|
||||
insertLinkRows(insert, element, waiting);
|
||||
}
|
||||
if (own_transaction) {
|
||||
m_data_base.commit();
|
||||
|
||||
@@ -154,6 +154,7 @@ class projectDataBase : public QObject
|
||||
void conductorPropertiesStored(Conductor *conductor, const ConductorProperties &properties);
|
||||
void conductorUuidChanged(Conductor *conductor, const QUuid &old_uuid);
|
||||
QStringList conductorPropertiesMismatches() const;
|
||||
QStringList linkRowMismatches();
|
||||
|
||||
//Fill the three stores from a project's document before its
|
||||
//folios are built, then, once
|
||||
@@ -253,6 +254,8 @@ class projectDataBase : public QObject
|
||||
void populateConductorTable();
|
||||
void populateLinkTable();
|
||||
void flushLinks();
|
||||
void insertLinkRows(QSqlQuery &insert, Element *element, const QSet<QUuid> &waiting);
|
||||
QSet<QUuid> waitingSymbols() const;
|
||||
void populateDrawingItemTables();
|
||||
bool populateFromDocument(const QDomDocument &document, QString *why = nullptr);
|
||||
bool writeDrawingItem(QObject *object);
|
||||
|
||||
@@ -2342,6 +2342,23 @@ bool Diagram::fromXml(QDomElement &document,
|
||||
<< "wire end(s) on a terminal that moved since the project was saved,"
|
||||
<< "matched to it by place";
|
||||
}
|
||||
//A copy of a symbol sharing its uuid with another (older versions'
|
||||
//copies, F100) gets its own, now that its wires are connected to
|
||||
//it: wires and links then name one symbol each
|
||||
//(QETProject::renewedSharedUuid(), only while the project opens)
|
||||
if (consider_informations && m_project) {
|
||||
const int folio_index = m_project->folioIndex(this);
|
||||
QHash<QUuid, int> ordinal;
|
||||
for (Element *element : std::as_const(added_elements)) {
|
||||
const QUuid shared = element->uuid();
|
||||
const QUuid renewed = m_project->renewedSharedUuid(folio_index, ordinal[shared]++,
|
||||
shared, uuid());
|
||||
if (!renewed.isNull()) {
|
||||
element->setUuid(renewed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (consider_informations && !m_wires_not_reconnected.isEmpty()) {
|
||||
qWarning().noquote() << "Diagram::fromXml():"
|
||||
<< m_wires_not_reconnected.size()
|
||||
|
||||
@@ -1437,32 +1437,11 @@ QDomElement Element::toXml(
|
||||
element.appendChild(inputs);
|
||||
|
||||
//if this element is linked to other elements,
|
||||
//save the uuid of each other elements
|
||||
//A partner on a folio not built yet (lazy folios), which this
|
||||
//symbol will be linked to, is saved too, in the order the symbol was
|
||||
//saved with: saving needs no partner built (stage D5a)
|
||||
//save the uuid of each other elements (linksToSave())
|
||||
QList<std::pair<QUuid, int>> links;
|
||||
if (keepsSavedLinks() && diagram() && diagram()->project()) {
|
||||
const QSet<QUuid> waiting = diagram()->project()->waitingLinkTargets();
|
||||
QSet<Element *> written;
|
||||
for (const auto &link_info : std::as_const(tmp_uuids_link)) {
|
||||
Element *linked = nullptr;
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
if (elmt->uuid() == link_info.uuid && !written.contains(elmt)) { linked = elmt; break; }
|
||||
if (linked) {
|
||||
written.insert(linked);
|
||||
links.append({linked->uuid(), m_group_index_map.value(linked, -1)});
|
||||
} else if (waiting.contains(link_info.uuid)) {
|
||||
links.append({link_info.uuid, link_info.group_index});
|
||||
}
|
||||
}
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
if (!written.contains(elmt))
|
||||
links.append({elmt->uuid(), m_group_index_map.value(elmt, -1)});
|
||||
} else {
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
links.append({elmt->uuid(), m_group_index_map.value(elmt, -1)});
|
||||
}
|
||||
for (const SavedLink &link : linksToSave(diagram() && diagram()->project()
|
||||
? diagram()->project()->waitingLinkTargets() : QSet<QUuid>()))
|
||||
links.append({link.uuid, link.group_index});
|
||||
if (!links.isEmpty()) {
|
||||
QDomElement links_uuids = document.createElement(QStringLiteral("links_uuids"));
|
||||
for (const auto &link : std::as_const(links)) {
|
||||
@@ -1869,6 +1848,45 @@ void Element::initLink(QETProject *prj)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::linksToSave
|
||||
The partners this symbol saves, in the order it saves them: the order
|
||||
it was saved with (tmp_uuids_link), then partners linked since. A
|
||||
partner on a folio not built yet (lazy folios), which this symbol will
|
||||
be linked to, is in the list too: saving needs no partner built (stage
|
||||
D5a). toXml() writes this list, and the project database's link rows
|
||||
are written from it, so the two are the same (QETZ-DB-FIRST stage 2a).
|
||||
@param waiting the symbols on folios not built: a saved partner among
|
||||
them is kept (QETProject::symbolsOnUnbuiltFolios())
|
||||
@return each partner's uuid, its contact group (-1 if none), and the
|
||||
partner itself when it is built (nullptr for one waiting)
|
||||
*/
|
||||
QList<Element::SavedLink> Element::linksToSave(const QSet<QUuid> &waiting) const
|
||||
{
|
||||
QList<SavedLink> links;
|
||||
if (keepsSavedLinks() && diagram() && diagram()->project()) {
|
||||
QSet<Element *> written;
|
||||
for (const auto &link_info : std::as_const(tmp_uuids_link)) {
|
||||
Element *linked = nullptr;
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
if (elmt->uuid() == link_info.uuid && !written.contains(elmt)) { linked = elmt; break; }
|
||||
if (linked) {
|
||||
written.insert(linked);
|
||||
links.append({linked->uuid(), m_group_index_map.value(linked, -1), linked});
|
||||
} else if (waiting.contains(link_info.uuid)) {
|
||||
links.append({link_info.uuid, link_info.group_index, nullptr});
|
||||
}
|
||||
}
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
if (!written.contains(elmt))
|
||||
links.append({elmt->uuid(), m_group_index_map.value(elmt, -1), elmt});
|
||||
} else {
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
links.append({elmt->uuid(), m_group_index_map.value(elmt, -1), elmt});
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::pendingLinks
|
||||
@return the uuids of the partners this symbol was saved linked to and
|
||||
|
||||
@@ -227,6 +227,13 @@ class Element : public QetGraphicsItem
|
||||
virtual void unlinkElement(Element *) {}
|
||||
virtual void initLink(QETProject *);
|
||||
QSet<QUuid> pendingLinks() const;
|
||||
/// A partner as the symbol saves it (linksToSave())
|
||||
struct SavedLink {
|
||||
QUuid uuid;
|
||||
int group_index = -1;
|
||||
Element *built = nullptr; ///< nullptr: on a folio not built yet
|
||||
};
|
||||
QList<SavedLink> linksToSave(const QSet<QUuid> &waiting) const;
|
||||
bool keepsSavedLinks() const {return !tmp_uuids_link.isEmpty();}
|
||||
QList<std::pair<QUuid, int>> waitingLinks() const;
|
||||
/**
|
||||
|
||||
+118
-24
@@ -299,6 +299,27 @@ QByteArray QETProject::containerPicture(const QString &file) const
|
||||
return m_container_pictures.value(file);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::renewedSharedUuid
|
||||
While the project opens: the uuid of the @p ordinal -th symbol carrying
|
||||
@p uuid on the folio at @p folio_index (in the file's order), when
|
||||
other symbols of the project carry the same uuid and this copy is not
|
||||
the one keeping it (readDiagramsXml()). Derived from the uuid and the
|
||||
folio's uuid, so the same file gives the same uuid on every open.
|
||||
@return a null uuid when this symbol keeps its uuid
|
||||
*/
|
||||
QUuid QETProject::renewedSharedUuid(int folio_index, int ordinal, const QUuid &uuid,
|
||||
const QUuid &folio_uuid)
|
||||
{
|
||||
const auto keeper = m_shared_uuid_keepers.constFind(uuid);
|
||||
if (keeper == m_shared_uuid_keepers.constEnd()
|
||||
|| (keeper->first == folio_index && keeper->second == ordinal)) {
|
||||
return QUuid();
|
||||
}
|
||||
return derivedItemUuid(QStringLiteral("element-copy"),
|
||||
uuid.toString() + QLatin1Char('\n') + folio_uuid.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::derivedItemUuid
|
||||
A uuid for an item of this project that was saved without one, the same
|
||||
@@ -474,6 +495,8 @@ QETProject::ProjectState QETProject::openFile(QFile *file)
|
||||
}
|
||||
QFileInfo fi(*file);
|
||||
setFilePath(fi.absoluteFilePath());
|
||||
//Saved again unchanged, the file keeps its saved date and path
|
||||
m_stamped_path = m_file_path;
|
||||
|
||||
//Extract the content of the xml. The raw bytes are kept : a project
|
||||
//file without a persisted uuid derives its uuid from them.
|
||||
@@ -1161,16 +1184,8 @@ void QETProject::setFilePath(const QString &filepath)
|
||||
setReadOnly(false);
|
||||
}
|
||||
|
||||
//title block variables should be updated after file save as dialog is confirmed, before file is saved.
|
||||
m_project_properties.addValue("saveddate", QLocale::system().toString(QDate::currentDate(), QLocale::ShortFormat));
|
||||
m_project_properties.addValue("saveddate-eu", QDate::currentDate().toString("dd-MM-yyyy"));
|
||||
m_project_properties.addValue("saveddate-us", QDate::currentDate().toString("yyyy-MM-dd"));
|
||||
m_project_properties.addValue("savedtime", QDateTime::currentDateTime().toString("HH:mm"));
|
||||
m_project_properties.addValue("savedfilename", QFileInfo(filePath()).completeBaseName());
|
||||
m_project_properties.addValue("savedfilepath", filePath());
|
||||
|
||||
|
||||
|
||||
//The saved date, time and path of the title block are set by
|
||||
//write(), when the project is saved (stampSaved())
|
||||
emit projectFilePathChanged(this, m_file_path);
|
||||
emit projectInformationsChanged(this);
|
||||
updateDiagramsFolioData();
|
||||
@@ -2636,6 +2651,16 @@ QDomDocument QETProject::toXml(QHash<int, QByteArray> *kept_folios, QStringList
|
||||
// Write the elements collection.
|
||||
project_root.appendChild(m_elements_collection->root().cloneNode(true));
|
||||
|
||||
//QET_CHECK_LINK_ROWS=1: say whether the project database's link rows
|
||||
//are the links each placed symbol saves, in its order, once the
|
||||
//folios are written. Builds nothing (lazy folios stay as they are):
|
||||
//a test and debugging aid; it changes nothing.
|
||||
if (qEnvironmentVariableIntValue("QET_CHECK_LINK_ROWS") == 1) {
|
||||
const QStringList links = m_data_base.linkRowMismatches();
|
||||
qWarning().noquote() << "link rows:" << links.size() << "differ"
|
||||
<< links.mid(0, 5).join(QStringLiteral(", "));
|
||||
}
|
||||
|
||||
m_waiting_link_targets.clear();
|
||||
return(xml_doc);
|
||||
}
|
||||
@@ -2801,6 +2826,33 @@ bool QETProject::changedOnDisk(QDateTime *when) const
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::stampSaved
|
||||
Set the title block variables of the save (saveddate, saveddate-eu,
|
||||
saveddate-us, savedtime, savedfilename, savedfilepath) to now and to
|
||||
the file being written, when there is something new to save: the
|
||||
project changed since it was opened or last saved, or it is written to
|
||||
another file. Otherwise they keep what the file holds, so saving an
|
||||
unchanged project gives an identical file (F124).
|
||||
@return true if they were set
|
||||
*/
|
||||
bool QETProject::stampSaved()
|
||||
{
|
||||
const bool changed = m_modified || m_undo_stack->index() != m_stamped_undo_index;
|
||||
if (!changed && m_file_path == m_stamped_path) {
|
||||
return false;
|
||||
}
|
||||
m_project_properties.addValue("saveddate", QLocale::system().toString(QDate::currentDate(), QLocale::ShortFormat));
|
||||
m_project_properties.addValue("saveddate-eu", QDate::currentDate().toString("dd-MM-yyyy"));
|
||||
m_project_properties.addValue("saveddate-us", QDate::currentDate().toString("yyyy-MM-dd"));
|
||||
m_project_properties.addValue("savedtime", QDateTime::currentDateTime().toString("HH:mm"));
|
||||
m_project_properties.addValue("savedfilename", QFileInfo(filePath()).completeBaseName());
|
||||
m_project_properties.addValue("savedfilepath", filePath());
|
||||
emit projectInformationsChanged(this);
|
||||
updateDiagramsFolioData();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::write
|
||||
Save the project in a file.
|
||||
@@ -2868,13 +2920,28 @@ QETResult QETProject::write(bool overwrite_changed)
|
||||
if (!PreviousVersions::keep(m_file_path, PreviousVersions::count(), &backup_error))
|
||||
qWarning().noquote() << "Previous version of" << m_file_path << "not kept:" << backup_error;
|
||||
|
||||
//The saved date, time and path go into the file being written, and
|
||||
//only when there is something new to save: an unchanged project
|
||||
//saves to an identical file (F124, a project kept in git). A
|
||||
//failed write puts the previous values back.
|
||||
const DiagramContext stamped_before = m_project_properties;
|
||||
const bool stamped = stampSaved();
|
||||
const auto failed_stamped = [&](const QString &error) {
|
||||
if (stamped) {
|
||||
m_project_properties = stamped_before;
|
||||
emit projectInformationsChanged(this);
|
||||
updateDiagramsFolioData();
|
||||
}
|
||||
return failed(error);
|
||||
};
|
||||
|
||||
QString error_message;
|
||||
if (isContainerPath(m_file_path))
|
||||
{
|
||||
//A container is written from the whole document: every folio
|
||||
//built (stage D4 writes it from the database)
|
||||
if (!writeContainerFile(m_file_path, &error_message))
|
||||
return(failed(error_message));
|
||||
return(failed_stamped(error_message));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2884,7 +2951,7 @@ QETResult QETProject::write(bool overwrite_changed)
|
||||
QDomDocument xml_project(toXml(&kept_folios));
|
||||
if (!QET::writeXmlText(spliceKeptFolios(xml_project.toString(4), kept_folios),
|
||||
m_file_path, &error_message))
|
||||
return(failed(error_message));
|
||||
return(failed_stamped(error_message));
|
||||
}
|
||||
|
||||
rememberDiskState();
|
||||
@@ -2905,17 +2972,8 @@ QETResult QETProject::write(bool overwrite_changed)
|
||||
}
|
||||
}
|
||||
|
||||
//title block variables should be updated after file save dialog is confirmed, before file is saved.
|
||||
m_project_properties.addValue("saveddate", QLocale::system().toString(QDate::currentDate(), QLocale::ShortFormat));
|
||||
m_project_properties.addValue("saveddate-us", QDate::currentDate().toString("yyyy-MM-dd"));
|
||||
m_project_properties.addValue("saveddate-eu", QDate::currentDate().toString("dd-MM-yyyy"));
|
||||
m_project_properties.addValue("savedtime", QDateTime::currentDateTime().toString("HH:mm"));
|
||||
m_project_properties.addValue("savedfilename", QFileInfo(filePath()).completeBaseName());
|
||||
m_project_properties.addValue("savedfilepath", filePath());
|
||||
|
||||
emit projectInformationsChanged(this);
|
||||
updateDiagramsFolioData();
|
||||
|
||||
m_stamped_path = m_file_path;
|
||||
m_stamped_undo_index = m_undo_stack->index();
|
||||
setModified(false);
|
||||
return(QETResult());
|
||||
}
|
||||
@@ -3637,6 +3695,41 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
}
|
||||
}
|
||||
|
||||
//Symbols sharing a uuid (copies made by older versions, F100): the
|
||||
//project database, links and wires name a symbol by its uuid, so
|
||||
//each copy but one gets its own (renewedSharedUuid()). The copy
|
||||
//that keeps it is the first one linked to another symbol (a
|
||||
//partner's link names the uuid), else the first. The folios with
|
||||
//a copy to renew are built now, also with lazy folios, so the
|
||||
//whole project has one uuid per symbol from the start.
|
||||
m_shared_uuid_keepers.clear();
|
||||
QSet<int> build_now;
|
||||
{
|
||||
QHash<QUuid, QList<std::tuple<int, int, bool>>> copies;
|
||||
for (int i = 0 ; i < diagram_nodes.length() ; ++i) {
|
||||
const QDomElement elements = diagram_nodes.at(i).toElement()
|
||||
.firstChildElement(QStringLiteral("elements"));
|
||||
QHash<QUuid, int> ordinal;
|
||||
for (QDomElement e = elements.firstChildElement(QStringLiteral("element"));
|
||||
!e.isNull() ; e = e.nextSiblingElement(QStringLiteral("element"))) {
|
||||
const QUuid uuid(e.attribute(QStringLiteral("uuid")));
|
||||
if (uuid.isNull()) continue;
|
||||
const bool linked = !e.firstChildElement(QStringLiteral("links_uuids"))
|
||||
.firstChildElement(QStringLiteral("link_uuid")).isNull();
|
||||
copies[uuid].append({i, ordinal[uuid]++, linked});
|
||||
}
|
||||
}
|
||||
for (auto it = copies.cbegin() ; it != copies.cend() ; ++it) {
|
||||
if (it.value().size() < 2) continue;
|
||||
auto keeper = it.value().first();
|
||||
for (const auto © : it.value())
|
||||
if (std::get<2>(copy)) { keeper = copy; break; }
|
||||
m_shared_uuid_keepers.insert(it.key(), {std::get<0>(keeper), std::get<1>(keeper)});
|
||||
for (const auto © : it.value())
|
||||
if (copy != keeper) build_now.insert(std::get<0>(copy));
|
||||
}
|
||||
}
|
||||
|
||||
if(dlgWaiting)
|
||||
dlgWaiting->setProgressBarRange(0, diagram_nodes.length()*3);
|
||||
|
||||
@@ -3690,7 +3783,7 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
connect(diagram, &Diagram::usedTitleBlockTemplateChanged,
|
||||
this, &QETProject::usedTitleBlockTemplateChanged);
|
||||
|
||||
m_deferring_folios = m_lazy_open;
|
||||
m_deferring_folios = m_lazy_open && !build_now.contains(i);
|
||||
diagram->initFromXml(diagram_xml_element);
|
||||
m_deferring_folios = false;
|
||||
if (!diagram->isLoaded() && !line_starts.isEmpty())
|
||||
@@ -3703,6 +3796,7 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
}
|
||||
}
|
||||
|
||||
m_shared_uuid_keepers.clear();
|
||||
updateDiagramsFolioData();
|
||||
|
||||
//Initialise links between elements in this project
|
||||
|
||||
+12
-1
@@ -123,6 +123,8 @@ class QETProject : public QObject
|
||||
projectDataBase *dataBase();
|
||||
QUuid uuid() const;
|
||||
QUuid derivedItemUuid(const QString &kind, const QString &key);
|
||||
QUuid renewedSharedUuid(int folio_index, int ordinal, const QUuid &uuid,
|
||||
const QUuid &folio_uuid);
|
||||
QByteArray containerPicture(const QString &file) const;
|
||||
ProjectState state() const;
|
||||
QString openError() const;
|
||||
@@ -441,6 +443,7 @@ class QETProject : public QObject
|
||||
}
|
||||
|
||||
private:
|
||||
bool stampSaved();
|
||||
void readProjectXml(QDomDocument &xml_project);
|
||||
void readDiagramsXml(QDomDocument &xml_project);
|
||||
void readElementsCollectionXml(QDomDocument &xml_project);
|
||||
@@ -570,6 +573,10 @@ class QETProject : public QObject
|
||||
bool m_kept_folios_trusted = false;
|
||||
/// Read from a .qet whose path nobody chose since: saved beside it
|
||||
bool m_opened_from_qet = false;
|
||||
/// The file the saved date and path were set for, and the undo
|
||||
/// index then: an unchanged project keeps them (stampSaved())
|
||||
QString m_stamped_path;
|
||||
int m_stamped_undo_index = 0;
|
||||
/// The project file as this QET last read or wrote it, to see
|
||||
/// whether something else changed it since (changedOnDisk())
|
||||
QString m_disk_path;
|
||||
@@ -610,7 +617,11 @@ class QETProject : public QObject
|
||||
int m_next_backup_slot = 0;
|
||||
QUuid m_uuid = QUuid::createUuid();
|
||||
QHash<QString, int> m_derived_uuid_keys;
|
||||
QSet<QUuid> m_saved_item_uuids; //symbol and wire uuids the file carries, see derivedItemUuid()
|
||||
QSet<QUuid> m_saved_item_uuids;
|
||||
/// While opening: per uuid carried by several symbols, the copy
|
||||
/// keeping it (folio index, ordinal on that folio), see
|
||||
/// renewedSharedUuid()
|
||||
QHash<QUuid, std::pair<int, int>> m_shared_uuid_keepers; //symbol and wire uuids the file carries, see derivedItemUuid()
|
||||
projectDataBase m_data_base;
|
||||
QVector<TerminalStrip *> m_terminal_strip_vector;
|
||||
QVector<Cable *> m_cables;
|
||||
|
||||
Reference in New Issue
Block a user