From 9078e4e3216e590f994f2b83d40283741e121b63 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Mon, 12 Oct 2026 14:20:17 +1300 Subject: [PATCH] Answer scripts from the folio asked for, without building every folio (stage D5) The scripting API (scripts and the assistant's live mode) reached a folio through diagrams(), which builds every folio, for every call. A folio's own data -- count, title, uuid, title block, border, wire defaults -- now comes from folios(), built or not; a call reading or changing a folio's items builds that folio, as showing it does (built()); selecting a symbol by uuid builds the folio the project database places it on. Search and replace and the continuity check still build every folio. DiagramContent worked out one wire of each potential when made, which follows potentials through folio reports and built the folios at the other end, for every caller; it is now worked out when first asked (Search and replace asks; a merge asks both sides, as before). tst_lazyfolios: on a .qetz, a script reads every folio's title, uuid and border building none (fails with diagrams()), and the symbols and wires of the folio with the most links to other folios as when built, building that folio only (27 before potentials were lazy). ctest 96/96 but modal_quit_regression in both modes: a race in that test (gdb interrupts the main thread inside malloc while the folio view repaints during the dialog, master too), 2 of 23 runs here, 0 of 10 on master, passing alone. 342 corpus projects save the same in all four arms, and export the same wiring list and wire numbers lazily. Co-Authored-By: Claude Opus 5.5 --- .../ui/searchandreplacewidget.cpp | 2 +- sources/diagramcontent.cpp | 39 ++-- sources/diagramcontent.h | 9 +- sources/scripting/qetscriptapi.cpp | 169 ++++++++++-------- sources/scripting/qetscriptapi.h | 2 + tests/qttest/lazy_folios_probe.cpp | 29 +++ 6 files changed, 164 insertions(+), 86 deletions(-) diff --git a/sources/SearchAndReplace/ui/searchandreplacewidget.cpp b/sources/SearchAndReplace/ui/searchandreplacewidget.cpp index 3a0e656ef..929710662 100644 --- a/sources/SearchAndReplace/ui/searchandreplacewidget.cpp +++ b/sources/SearchAndReplace/ui/searchandreplacewidget.cpp @@ -307,7 +307,7 @@ void SearchAndReplaceWidget::fillItemsList() m_indi_text_qtwi->sortChildren(0, Qt::AscendingOrder); - for (Conductor *c : dc.m_potential_conductors) + for (Conductor *c : dc.potentialConductors()) { QTreeWidgetItem *qtwi = new QTreeWidgetItem(m_conductor_qtwi); qtwi->setText(0, c->properties().text); diff --git a/sources/diagramcontent.cpp b/sources/diagramcontent.cpp index fc54e83c9..af6d66dbe 100644 --- a/sources/diagramcontent.cpp +++ b/sources/diagramcontent.cpp @@ -79,13 +79,7 @@ DiagramContent::DiagramContent(Diagram *diagram, bool selected) : m_other_conductors << c; } - if (m_potential_conductors.isEmpty()) { - m_potential_conductors << c; - } else { - if (!potentialIsManaged(c->relatedPotentialConductors(true).values())) { - m_potential_conductors << c; - } - } + m_potential_candidates << c; break; } case DiagramImageItem::Type: { m_images << qgraphicsitem_cast(item); break;} @@ -379,12 +373,14 @@ DiagramContent &DiagramContent::operator+=(const DiagramContent &other) if(!m_selected_items.contains(qgi)) m_selected_items << qgi; - for (Conductor *c : other.m_potential_conductors) + QList potentials = potentialConductors(); + for (Conductor *c : other.potentialConductors()) { QList c_list = c->relatedPotentialConductors(true).values(); c_list << c; if (!potentialIsManaged(c_list)) { - m_potential_conductors << c; + potentials << c; + m_potential_conductors = potentials; } } @@ -402,17 +398,40 @@ DiagramContent &DiagramContent::operator+=(const DiagramContent &other) */ bool DiagramContent::potentialIsManaged(QList conductors) { + const QList potentials = potentialConductors(); bool b = false; for (Conductor *c : conductors) { - if (m_potential_conductors.contains(c)) + if (potentials.contains(c)) b = true; } return b; } +/** + @brief DiagramContent::potentialConductors + @return one wire of each potential of the wires of this content, worked + out the first time it is asked (see m_potential_conductors) +*/ +QList DiagramContent::potentialConductors() const +{ + if (!m_potential_conductors) { + QList potentials; + for (Conductor *c : m_potential_candidates) { + bool managed = false; + if (!potentials.isEmpty()) + for (Conductor *related : c->relatedPotentialConductors(true)) + if (potentials.contains(related)) { managed = true; break; } + if (!managed) + potentials << c; + } + m_potential_conductors = potentials; + } + return *m_potential_conductors; +} + /** @brief DiagramContent::hasTextEditing @return true if handle a text currently in editing interaction diff --git a/sources/diagramcontent.h b/sources/diagramcontent.h index 92d7c1caf..0afcf4516 100644 --- a/sources/diagramcontent.h +++ b/sources/diagramcontent.h @@ -19,6 +19,7 @@ #define DIAGRAM_CONTENT_H #include +#include #include #include "../qetgraphicsitem/terminalelement.h" @@ -77,7 +78,6 @@ class DiagramContent QList m_conductors_to_update; QList m_conductors_to_move; QList m_other_conductors; - QList m_potential_conductors; QSet m_element_texts; QSet m_texts_groups; QList m_selected_items; @@ -89,6 +89,7 @@ class DiagramContent QList selectedTexts() const; QList selectedTextsGroup() const; QList conductors(int = AnyConductor) const; + QList potentialConductors() const; bool hasDeletableItems() const; bool hasCopiableItems() const; QList items(int = All) const; @@ -103,6 +104,12 @@ class DiagramContent private: int removePinnedGroups(); + /// The wires potentialConductors() is made from, in order + QList m_potential_candidates; + /// One wire of each potential, worked out when first asked: + /// following a potential goes through folio reports to other + /// folios, building those not built yet (QET_LAZY_FOLIOS) + mutable std::optional> m_potential_conductors; }; QDebug &operator<<(QDebug, DiagramContent &); #endif diff --git a/sources/scripting/qetscriptapi.cpp b/sources/scripting/qetscriptapi.cpp index be97fc618..953e355b8 100644 --- a/sources/scripting/qetscriptapi.cpp +++ b/sources/scripting/qetscriptapi.cpp @@ -126,7 +126,7 @@ QString QetScriptApi::filePath() const int QetScriptApi::folioCount() const { - return m_project ? m_project->diagrams().count() : 0; + return m_project ? m_project->folios().count() : 0; } /** @@ -183,7 +183,7 @@ QStringList QetScriptApi::signatures() int QetScriptApi::currentFolio() const { if (!m_project) return -1; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (m_view && m_view->diagram()) { return diagrams.indexOf(m_view->diagram()); } @@ -193,7 +193,7 @@ int QetScriptApi::currentFolio() const QString QetScriptApi::folioTitle(int index) const { if (!m_project) return QString(); - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (index < 0 || index >= diagrams.count()) return QString(); return diagrams.at(index)->title(); } @@ -207,7 +207,7 @@ QString QetScriptApi::folioTitle(int index) const QString QetScriptApi::folioUuid(int index) const { if (!m_project) return QString(); - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (index < 0 || index >= diagrams.count()) return QString(); return diagrams.at(index)->uuid().toString(); } @@ -222,7 +222,7 @@ int QetScriptApi::folioIndex(const QString &uuid) const if (!m_project) return -1; const QUuid wanted(uuid); if (wanted.isNull()) return -1; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); for (int i = 0 ; i < diagrams.count() ; ++i) { if (diagrams.at(i)->uuid() == wanted) return i; } @@ -232,18 +232,18 @@ int QetScriptApi::folioIndex(const QString &uuid) const int QetScriptApi::elementCount(int folioIndex) const { if (!m_project) return 0; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return 0; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); return content.m_elements.count(); } int QetScriptApi::conductorCount(int folioIndex) const { if (!m_project) return 0; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return 0; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); return content.conductors(DiagramContent::AnyConductor).count(); } @@ -462,6 +462,19 @@ void QetScriptApi::setLive(QStringList *log) m_live_log = log; } +/** + @brief QetScriptApi::built + @return @p folio, built if it was not yet (QET_LAZY_FOLIOS), as showing + it builds it: what a call reading or changing its items needs. A + folio's own data (title block, border, wire defaults) needs no build. +*/ +Diagram *QetScriptApi::built(Diagram *folio) const +{ + if (folio && m_project) + m_project->buildFolioToShow(folio); + return folio; +} + /** @brief QetScriptApi::findElement @param folioIndex @@ -472,9 +485,9 @@ void QetScriptApi::setLive(QStringList *log) Element *QetScriptApi::findElement(int folioIndex, const QString &elementUuid) const { if (!m_project) return nullptr; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return nullptr; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); for (Element *elmt : std::as_const(content.m_elements)) { if (elmt->uuid().toString() == elementUuid) return elmt; @@ -705,9 +718,9 @@ QString QetScriptApi::addElement(int folioIndex, const QString &locationPath, do log(QStringLiteral("qet.addElement: project is read-only")); return QString(); } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return QString(); - Diagram *diagram = diagrams.at(folioIndex); + Diagram *diagram = built(diagrams.at(folioIndex)); // ElementsLocation::setPath() forces ANY path to embed:// as soon as a // non-null project is given, common://custom:// included -- passing @@ -817,7 +830,7 @@ bool QetScriptApi::deleteElement(int folioIndex, const QString &elementUuid) } Element *element = findElement(folioIndex, elementUuid); if (!element) return false; - Diagram *diagram = m_project->diagrams().at(folioIndex); + Diagram *diagram = built(m_project->folios().at(folioIndex)); DiagramContent content; content.m_elements << element; @@ -906,9 +919,9 @@ QStringList QetScriptApi::elementUuids(int folioIndex) const { QStringList uuids; if (!m_project) return uuids; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return uuids; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); for (Element *elmt : std::as_const(content.m_elements)) { uuids << elmt->uuid().toString(); } @@ -1077,7 +1090,7 @@ bool QetScriptApi::addConductor(int folioIndex, return false; } - Diagram *diagram = m_project->diagrams().at(folioIndex); + Diagram *diagram = built(m_project->folios().at(folioIndex)); ConductorCreator creator(diagram, terminals); Q_UNUSED(creator) @@ -1110,10 +1123,10 @@ QStringList QetScriptApi::conductors(int folioIndex) const { QStringList list; if (!m_project) return list; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return list; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); const QList all = content.conductors(DiagramContent::AnyConductor); for (Conductor *c : all) { @@ -1132,10 +1145,10 @@ QStringList QetScriptApi::conductorUuids(int folioIndex) const { QStringList list; if (!m_project) return list; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return list; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); for (Conductor *c : content.conductors(DiagramContent::AnyConductor)) list << c->uuid().toString(); return list; @@ -1152,12 +1165,12 @@ QStringList QetScriptApi::conductorUuids(int folioIndex) const QStringList QetScriptApi::conductorEnds(int folioIndex, const QString &uuid) const { if (!m_project) return {}; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return {}; const QUuid wanted(uuid); if (wanted.isNull()) return {}; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); for (Conductor *c : content.conductors(DiagramContent::AnyConductor)) if (c->uuid() == wanted) return {describeEnd(c->terminal1), describeEnd(c->terminal2)}; @@ -1787,18 +1800,18 @@ QList sortedByPosition(const QSet &items) QList QetScriptApi::sortedTexts(int folioIndex) const { if (!m_project) return {}; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return {}; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); return sortedByPosition(content.m_text_fields); } QList QetScriptApi::sortedShapes(int folioIndex) const { if (!m_project) return {}; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return {}; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); return sortedByPosition(content.m_shapes); } @@ -1843,9 +1856,9 @@ int QetScriptApi::addText(int folioIndex, const QString &text, double x, double log(QStringLiteral("qet.addText: project is read-only")); return -1; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return -1; - Diagram *diagram = diagrams.at(folioIndex); + Diagram *diagram = built(diagrams.at(folioIndex)); auto *item = new IndependentTextItem(); item->setPlainText(text); @@ -1929,7 +1942,7 @@ bool QetScriptApi::deleteText(int folioIndex, int textIndex) } IndependentTextItem *item = findText(folioIndex, textIndex, QStringLiteral("deleteText")); if (!item) return false; - Diagram *diagram = m_project->diagrams().at(folioIndex); + Diagram *diagram = built(m_project->folios().at(folioIndex)); DiagramContent content; content.m_text_fields << item; @@ -1969,7 +1982,7 @@ int QetScriptApi::addShape(int folioIndex, const QString &type, log(QStringLiteral("qet.addShape: project is read-only")); return -1; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return -1; QetShapeItem::ShapeType shape_type; @@ -1984,7 +1997,7 @@ int QetScriptApi::addShape(int folioIndex, const QString &type, return -1; } - Diagram *diagram = diagrams.at(folioIndex); + Diagram *diagram = built(diagrams.at(folioIndex)); auto *shape = new QetShapeItem(QPointF(x1, y1), QPointF(x2, y2), shape_type); diagram->undoStack().push(new AddGraphicsObjectCommand(shape, diagram, QPointF(0, 0))); return sortedShapes(folioIndex).indexOf(shape); @@ -2116,7 +2129,7 @@ bool QetScriptApi::deleteShape(int folioIndex, int shapeIndex) .arg(folioIndex).arg(list.count()).arg(shapeIndex)); return false; } - Diagram *diagram = m_project->diagrams().at(folioIndex); + Diagram *diagram = built(m_project->folios().at(folioIndex)); DiagramContent content; content.m_shapes << list.at(shapeIndex); @@ -2223,7 +2236,7 @@ int QetScriptApi::addPolygon(int folioIndex, const QVariantList &points, bool cl log(QStringLiteral("qet.addPolygon: project is read-only")); return -1; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return -1; if (points.count() < 2) { log(QStringLiteral("qet.addPolygon: at least 2 points are required, got %1") @@ -2237,7 +2250,7 @@ int QetScriptApi::addPolygon(int folioIndex, const QVariantList &points, bool cl return -1; } - Diagram *diagram = diagrams.at(folioIndex); + Diagram *diagram = built(diagrams.at(folioIndex)); auto *shape = new QetShapeItem(poly.first(), poly.last(), QetShapeItem::Polygon); shape->setPolygon(poly); shape->setClosed(closed); @@ -2321,7 +2334,7 @@ int QetScriptApi::addPath(int folioIndex, const QVariantList &nodes, bool closed log(QStringLiteral("qet.addPath: project is read-only")); return -1; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return -1; if (nodes.count() < 2) { log(QStringLiteral("qet.addPath: at least 2 nodes are required, got %1").arg(nodes.count())); @@ -2338,7 +2351,7 @@ int QetScriptApi::addPath(int folioIndex, const QVariantList &nodes, bool closed path_nodes << node; } - Diagram *diagram = diagrams.at(folioIndex); + Diagram *diagram = built(diagrams.at(folioIndex)); auto *shape = new QetShapeItem(path_nodes.first().anchor, path_nodes.last().anchor, QetShapeItem::Path); shape->setPathNodes(path_nodes); @@ -2582,7 +2595,7 @@ bool QetScriptApi::deleteConductor(int folioIndex, const QString &elementUuid, i } Conductor *conductor = findConductor(folioIndex, elementUuid, terminalIndex, caller); if (!conductor) return false; - Diagram *diagram = m_project->diagrams().at(folioIndex); + Diagram *diagram = built(m_project->folios().at(folioIndex)); DiagramContent content; content.m_conductors_to_move << conductor; @@ -2603,10 +2616,10 @@ bool QetScriptApi::removeFolio(int folioIndex) log(QStringLiteral("qet.removeFolio: project is read-only")); return false; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; m_project->undoStack()->push(new RemoveDiagramCommand(m_project, diagrams.at(folioIndex))); - return m_project->diagrams().count() == diagrams.count() - 1; + return m_project->folios().count() == diagrams.count() - 1; } namespace { @@ -2640,7 +2653,7 @@ const QStringList &titleBlockFieldNames() QString QetScriptApi::folioProperty(int folioIndex, const QString &property) const { if (!m_project) return QString(); - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return QString(); Diagram *diagram = diagrams.at(folioIndex); if (property == QLatin1String("template")) @@ -2665,7 +2678,7 @@ bool QetScriptApi::setFolioProperty(int folioIndex, const QString &property, con log(QStringLiteral("qet.setFolioProperty: project is read-only")); return false; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; Diagram *diagram = diagrams.at(folioIndex); @@ -2958,9 +2971,9 @@ bool QetScriptApi::sortTerminalStrip(int stripIndex) QList QetScriptApi::sortedTables(int folioIndex) const { if (!m_project) return {}; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return {}; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); return sortedByPosition(content.m_tables); } @@ -3020,7 +3033,7 @@ int QetScriptApi::addTable(int folioIndex, const QString &kind, const QString &n log(QStringLiteral("qet.%1: project is read-only").arg(caller)); return -1; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) { log(QStringLiteral("qet.%1: no folio at index %2").arg(caller).arg(folioIndex)); return -1; @@ -3089,7 +3102,7 @@ int QetScriptApi::addTable(int folioIndex, const QString &kind, const QString &n dialog.setAddNewTableToNewDiagram(false); const QList before = sortedTables(folioIndex); - QetGraphicsTableFactory::create(diagrams.at(folioIndex), &dialog); + QetGraphicsTableFactory::create(built(diagrams.at(folioIndex)), &dialog); const QList after = sortedTables(folioIndex); for (QetGraphicsTableItem *t : after) { if (!before.contains(t)) return after.indexOf(t); @@ -3105,9 +3118,9 @@ bool QetScriptApi::deleteTable(int folioIndex, int tableIndex) log(QStringLiteral("qet.deleteTable: project is read-only")); return false; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; - Diagram *diagram = diagrams.at(folioIndex); + Diagram *diagram = built(diagrams.at(folioIndex)); const QList all = sortedTables(folioIndex); if (tableIndex < 0 || tableIndex >= all.count()) { @@ -3381,7 +3394,7 @@ bool QetScriptApi::useConductorAutoNum(int folioIndex, const QString &name) log(QStringLiteral("qet.useConductorAutoNum: project is read-only")); return false; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; if (!name.isEmpty() && !m_project->conductorAutoNum().contains(name)) { log(QStringLiteral("qet.useConductorAutoNum: no conductor auto-numbering named '%1'").arg(name)); @@ -3395,9 +3408,9 @@ bool QetScriptApi::useConductorAutoNum(int folioIndex, const QString &name) QList QetScriptApi::sortedImages(int folioIndex) const { if (!m_project) return {}; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return {}; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); return sortedByPosition(content.m_images); } @@ -3491,7 +3504,7 @@ int QetScriptApi::addImage(int folioIndex, const QString &filePath, double x, do log(QStringLiteral("qet.addImage: project is read-only")); return -1; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return -1; // Same checks as a picture dropped on a folio: a regular file of at @@ -3503,7 +3516,7 @@ int QetScriptApi::addImage(int folioIndex, const QString &filePath, double x, do return -1; } - Diagram *diagram = diagrams.at(folioIndex); + Diagram *diagram = built(diagrams.at(folioIndex)); auto *item = new DiagramImageItem(QPixmap::fromImage(image)); diagram->undoStack().push(new AddGraphicsObjectCommand(item, diagram, QPointF(x, y))); return sortedImages(folioIndex).indexOf(item); @@ -3619,7 +3632,7 @@ bool QetScriptApi::deleteImage(int folioIndex, int imageIndex) .arg(folioIndex).arg(list.count()).arg(imageIndex)); return false; } - Diagram *diagram = m_project->diagrams().at(folioIndex); + Diagram *diagram = built(m_project->folios().at(folioIndex)); DiagramContent content; content.m_images << list.at(imageIndex); diagram->undoStack().push(new DeleteQGraphicsItemCommand(diagram, content)); @@ -3675,7 +3688,7 @@ int QetScriptApi::addPdfPage(int folioIndex, const QString &pdfPath, int pageNum log(QStringLiteral("qet.addPdfPage: project is read-only")); return -1; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return -1; if (dpi <= 0) { log(QStringLiteral("qet.addPdfPage: dpi must be positive, got %1").arg(dpi)); @@ -3724,7 +3737,7 @@ int QetScriptApi::addPdfPage(int folioIndex, const QString &pdfPath, int pageNum painter.drawImage(0, 0, rendered); painter.end(); - Diagram *diagram = diagrams.at(folioIndex); + Diagram *diagram = built(diagrams.at(folioIndex)); auto *item = new DiagramImageItem(QPixmap::fromImage(background)); diagram->undoStack().push(new AddGraphicsObjectCommand(item, diagram, QPointF(x, y))); return sortedImages(folioIndex).indexOf(item); @@ -3948,7 +3961,7 @@ bool QetScriptApi::deleteElementText(int folioIndex, const QString &elementUuid, DynamicElementTextItem *t = findElementText(folioIndex, elementUuid, textIndex, QStringLiteral("deleteElementText")); if (!t) return false; - Diagram *diagram = m_project->diagrams().at(folioIndex); + Diagram *diagram = built(m_project->folios().at(folioIndex)); DiagramContent content; content.m_element_texts << t; diagram->undoStack().push(new DeleteQGraphicsItemCommand(diagram, content)); @@ -4178,7 +4191,7 @@ QStringList QetScriptApi::duplicateElements(int fromFolioIndex, const QStringLis log(QStringLiteral("qet.%1: project is read-only").arg(caller)); return created; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (fromFolioIndex < 0 || fromFolioIndex >= diagrams.count() || toFolioIndex < 0 || toFolioIndex >= diagrams.count()) { log(QStringLiteral("qet.%1: folio index out of range").arg(caller)); @@ -4188,8 +4201,8 @@ QStringList QetScriptApi::duplicateElements(int fromFolioIndex, const QStringLis log(QStringLiteral("qet.%1: no elements named").arg(caller)); return created; } - Diagram *source = diagrams.at(fromFolioIndex); - Diagram *target = diagrams.at(toFolioIndex); + Diagram *source = built(diagrams.at(fromFolioIndex)); + Diagram *target = built(diagrams.at(toFolioIndex)); QList chosen; for (const QString &uuid : elementUuids) { @@ -4273,7 +4286,7 @@ const QStringList &folioBorderNames() QString QetScriptApi::folioBorder(int folioIndex, const QString &property) const { if (!m_project) return QString(); - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return QString(); const BorderProperties b = diagrams.at(folioIndex)->border_and_titleblock.exportBorder(); if (property == QLatin1String("columns")) return QString::number(b.columns_count); @@ -4412,7 +4425,7 @@ bool QetScriptApi::setFolioBorder(int folioIndex, const QString &property, const .arg(caller, property, folioBorderNames().join(QStringLiteral(", ")))); return false; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; Diagram *diagram = diagrams.at(folioIndex); @@ -4498,7 +4511,7 @@ QString QetScriptApi::conductorDefault(int folioIndex, const QString &property) if (folioIndex == -1) { p = m_project->defaultConductorProperties(); } else { - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return QString(); p = diagrams.at(folioIndex)->defaultConductorProperties; } @@ -4524,7 +4537,7 @@ bool QetScriptApi::setConductorDefault(int folioIndex, const QString &property, } Diagram *diagram = nullptr; if (folioIndex != -1) { - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; diagram = diagrams.at(folioIndex); } @@ -4633,12 +4646,12 @@ QVariantMap QetScriptApi::terminalPosition(int folioIndex, const QString &elemen QVariantList QetScriptApi::conductorPath(int folioIndex, const QString &conductorUuid) const { if (!m_project) return {}; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return {}; const QUuid wanted(conductorUuid); if (wanted.isNull()) return {}; - DiagramContent content(diagrams.at(folioIndex), false); + DiagramContent content(built(diagrams.at(folioIndex)), false); for (Conductor *c : content.conductors(DiagramContent::AnyConductor)) { if (c->uuid() != wanted) continue; QVariantList points; @@ -4673,14 +4686,14 @@ int QetScriptApi::insertFolio(int position) log(QStringLiteral("qet.insertFolio: project is read-only")); return -1; } - if (position < 0 || position > m_project->diagrams().count()) { + if (position < 0 || position > m_project->folios().count()) { log(QStringLiteral("qet.insertFolio: position %1 is outside 0..%2") - .arg(position).arg(m_project->diagrams().count())); + .arg(position).arg(m_project->folios().count())); return -1; } Diagram *diagram = m_project->addNewDiagram(position); if (!diagram) return -1; - return m_project->diagrams().indexOf(diagram); + return m_project->folios().indexOf(diagram); } /** @@ -4760,7 +4773,7 @@ int QetScriptApi::addFolio() } Diagram *diagram = m_project->addNewDiagram(); if (!diagram) return -1; - return m_project->diagrams().indexOf(diagram); + return m_project->folios().indexOf(diagram); } bool QetScriptApi::setFolioTitle(int folioIndex, const QString &title) @@ -4770,7 +4783,7 @@ bool QetScriptApi::setFolioTitle(int folioIndex, const QString &title) log(QStringLiteral("qet.setFolioTitle: project is read-only")); return false; } - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; Diagram *diagram = diagrams.at(folioIndex); @@ -5202,7 +5215,15 @@ QVariantList QetScriptApi::checkContinuity(int folioIndex) bool QetScriptApi::selectElement(const QString &elementUuid) { if (!m_project) return false; - for (Diagram *diagram : m_project->diagrams()) { + //The folio the project database places it on, built; every folio + //when it places it on none + QList folios; + const QSet on = m_project->dataBase()->folioUuidsOfElements({QUuid(elementUuid)}); + for (Diagram *diagram : m_project->folios()) + if (on.contains(diagram->uuid())) folios << built(diagram); + if (folios.isEmpty()) + folios = m_project->diagrams(); + for (Diagram *diagram : std::as_const(folios)) { DiagramContent content(diagram, false); for (Element *elmt : std::as_const(content.m_elements)) { if (elmt->uuid().toString() == elementUuid) { @@ -5218,7 +5239,7 @@ QStringList QetScriptApi::selectedElements(int folioIndex) const { QStringList list; if (!m_project) return list; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return list; for (QGraphicsItem *item : diagrams.at(folioIndex)->selectedItems()) { if (item->type() == Element::Type) { @@ -5232,7 +5253,7 @@ QStringList QetScriptApi::selectedElements(int folioIndex) const void QetScriptApi::deselectAll(int folioIndex) { if (!m_project) return; - const QList diagrams = m_project->diagrams(); + const QList diagrams = m_project->folios(); if (folioIndex < 0 || folioIndex >= diagrams.count()) return; diagrams.at(folioIndex)->clearSelection(); } diff --git a/sources/scripting/qetscriptapi.h b/sources/scripting/qetscriptapi.h index f6b8b0c0e..87f30aca5 100644 --- a/sources/scripting/qetscriptapi.h +++ b/sources/scripting/qetscriptapi.h @@ -25,6 +25,7 @@ #include class QETProject; +class Diagram; class DiagramView; class Element; class Terminal; @@ -642,6 +643,7 @@ class QetScriptApi : public QObject private: bool runFlag(const QString &flag, const QStringList &args); + Diagram *built(Diagram *folio) const; Element *findElement(int folioIndex, const QString &elementUuid) const; Terminal *findTerminal(int folioIndex, const QString &elementUuid, int terminalIndex, const QString &caller); diff --git a/tests/qttest/lazy_folios_probe.cpp b/tests/qttest/lazy_folios_probe.cpp index 4c1a24e96..39b69751b 100644 --- a/tests/qttest/lazy_folios_probe.cpp +++ b/tests/qttest/lazy_folios_probe.cpp @@ -30,6 +30,7 @@ #include "../../sources/ui/elementpropertieswidget.h" #include "../../sources/conductorautonumerotation.h" #include "../../sources/conductornumexport.h" +#include "../../sources/scripting/qetscriptapi.h" #include "../../sources/wiringlistexport.h" #include "../../sources/ui/terminalnumberingdialog.h" #include "../../sources/diagramcontent.h" @@ -800,6 +801,34 @@ int main(int argc, char **argv) check(listed.unloadedFolioCount() > 0, "listing the tables does not build every folio"); } + //A script (and the assistant's live mode) asking about the + //folios and one folio's items: that folio built, no other (D5) + { + QETProject scripted(zipped); + const int unbuilt = scripted.unloadedFolioCount(); + QetScriptApi api(&scripted), usual_api(&eager); + check(api.folioCount() == usual_api.folioCount(), "a script counts the folios as when built"); + for (int i = 0 ; i < folios.size() ; ++i) { + check(api.folioTitle(i) == usual_api.folioTitle(i) && api.folioUuid(i) == usual_api.folioUuid(i) + && api.folioBorder(i, "columns") == usual_api.folioBorder(i, "columns"), + "a script reads a folio's own data as when built"); + } + check(scripted.unloadedFolioCount() == unbuilt, "reading the folios' own data builds none"); + //The folio with the most links to other folios + const int target = busiest; + check(!scripted.folios().at(target)->isLoaded(), "a folio not built"); + QStringList lazy_uuids = api.elementUuids(target), usual_uuids = usual_api.elementUuids(target); + lazy_uuids.sort(); usual_uuids.sort(); + check(lazy_uuids == usual_uuids, "a script lists a folio's symbols as when built"); + QStringList lazy_wires = api.conductors(target), usual_wires = usual_api.conductors(target); + lazy_wires.sort(); usual_wires.sort(); + check(lazy_wires == usual_wires, "a script lists a folio's wires as when built"); + check(scripted.folios().at(target)->isLoaded(), "the folio a script reads is built"); + std::printf(".qetz script on folio %d: %d folios built\n", target + 1, + unbuilt - scripted.unloadedFolioCount()); + check(unbuilt - scripted.unloadedFolioCount() == 1, "a script reading one folio builds that folio only"); + } + //The wire numbers and wiring list exports, and the terminal //numbering dialog: as when built, building only the folios //holding a terminal (D5)