mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-29 22:24:13 +02:00
a0d5c4fa9c
The project database -- behind parts lists, summary tables and the wiring list -- was filled by walking the built folios: every element and conductor object of every scene. Filling it from the document the project was just read from instead is what the database needs before a project could be opened without building every folio (qelectrotech-docker DB-FROM-XML-SCOPE.md). updateDB(document), called by readProjectXml(), fills diagram, diagram_info, element, element_info, terminal and conductor from the document, through the code the folios use: a BorderTitleBlock read from each folio's XML gives the title-block values and each element's grid cell, the embedded collection gives each definition, and the binders are shared with the live path. Shapes, texts and pictures still come from the folios (their boxes need fonts and pens). It falls back to the folios, saying why in the log, when the document does not carry what that needs: an item without a saved uuid (older files -- the folios derive them on load), a conductor naming its ends the older way, a %autonum folio number, a terminal showing its master's label, a missing or unbuildable definition. A symbol label computed from a formula is the one saved in the file, which QElectroTech writes as it computes it on every save. QET_DATABASE_FROM_FOLIOS=1 forces the folio path. tst_databasefromdocument saves every example once, then fills both ways and requires identical tables (24/24, filled from the document each time), and checks that an older file falls back with its reason. Red when the document path is made to write a wrong grid cell. Database phase of loading unchanged: industrial.qet 0.146 s vs 0.160 s, Polonez 0.040 s vs 0.038 s (median of 5). QETProject::projectWideProperties() is split out of updateDiagramsFolioData() so both fills use the same title-block context. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
220 lines
7.8 KiB
C++
220 lines
7.8 KiB
C++
/*
|
|
Copyright 2006-2026 QElectroTech Team
|
|
This file is part of QElectroTech.
|
|
|
|
QElectroTech is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
QElectroTech is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifndef PROJECTDATABASE_H
|
|
#define PROJECTDATABASE_H
|
|
|
|
#include <QObject>
|
|
#include <QSqlDatabase>
|
|
#include <QSqlQuery>
|
|
#include <QPointer>
|
|
#include <QFileDialog>
|
|
#include <QHash>
|
|
#include <QSet>
|
|
#include <QUuid>
|
|
|
|
class Element;
|
|
class QETProject;
|
|
class Diagram;
|
|
class Conductor;
|
|
class Terminal;
|
|
class QGraphicsItem;
|
|
class QDomDocument;
|
|
class BorderTitleBlock;
|
|
class DiagramContext;
|
|
class QDate;
|
|
|
|
/**
|
|
@brief The projectDataBase class
|
|
This class wraps a sqlite data base where you can find several things
|
|
about the content of a project.
|
|
*
|
|
@note this class is still in development.
|
|
*/
|
|
class projectDataBase : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
projectDataBase(QETProject *project, QObject *parent = nullptr);
|
|
virtual ~projectDataBase() override;
|
|
|
|
void updateDB();
|
|
/**
|
|
updateDB() for a project just read from @p document: the
|
|
diagram, element, terminal and conductor tables are filled
|
|
from the document when it carries everything they need (see
|
|
populateFromDocument()), from the built folios otherwise.
|
|
*/
|
|
void updateDB(const QDomDocument &document);
|
|
/**
|
|
Suppress the full rebuild performed by updateDB().
|
|
|
|
While blocked, updateDB() returns immediately instead of
|
|
repopulating every table. Meant for bulk operations -- notably
|
|
loading a project, where each table model re-queries the
|
|
database as it is built and would otherwise trigger one
|
|
complete rebuild of it. The caller unblocks and calls
|
|
updateDB() once when done; @see QETProject::readProjectXml().
|
|
*/
|
|
void setUpdateBlocked(bool blocked);
|
|
QETProject *project() const;
|
|
QSqlQuery newQuery(const QString &query = QString(), QString *error = nullptr);
|
|
static bool isReadOnlySelect(const QString &query, QString *error = nullptr);
|
|
|
|
/**
|
|
The most rows any caller reads out of one query result.
|
|
|
|
A SELECT is not bounded by how much data the project holds:
|
|
SQLite produces rows lazily, so a query that never stops
|
|
producing them makes the loop that reads them never stop
|
|
either. A recursive CTE does exactly that in one line, and
|
|
a <graphics_table>'s <query> is stored in the .qet and run
|
|
on load -- so the text can arrive from a file rather than
|
|
from the person at the keyboard, and opening that file is
|
|
the whole attack.
|
|
|
|
100000 is far above any real result: the largest table in
|
|
the shipped examples is 396 rows. It is a backstop, not a
|
|
page size -- a caller that hits it has almost certainly
|
|
been handed something it should not run to completion, and
|
|
says so rather than truncating quietly.
|
|
*/
|
|
static constexpr int MaxResultRows = 100000;
|
|
QSqlDatabase database() const {return m_data_base;}
|
|
int excludedConductorCount() const;
|
|
|
|
void addElement (Element *element);
|
|
void removeElement (Element *element);
|
|
void elementInfoChanged (Element *element);
|
|
void elementInfoChanged (QList<Element *> elements);
|
|
|
|
void addDiagram (Diagram *diagram);
|
|
void removeDiagram (Diagram *diagram);
|
|
void diagramInfoChanged (Diagram *diagram);
|
|
void diagramOrderChanged();
|
|
|
|
void addConductor (Conductor *conductor);
|
|
void removeConductor (Conductor *conductor);
|
|
void updateConductor (Conductor *conductor);
|
|
|
|
//Shapes, independent texts and images: the folio's drawing
|
|
//furniture. Anything else passed here is ignored.
|
|
void addDrawingItem (QGraphicsItem *item);
|
|
void removeDrawingItem (QGraphicsItem *item);
|
|
void itemGroupChanged (QGraphicsItem *item);
|
|
|
|
private slots:
|
|
//Refresh the sender()'s row after Conductor::setProperties().
|
|
void conductorPropertiesChanged();
|
|
//Queue the sender()'s drawing-item row for rewriting.
|
|
void drawingItemChanged();
|
|
void drawingItemDestroyed(QObject *object);
|
|
|
|
public:
|
|
|
|
signals:
|
|
void dataBaseUpdated();
|
|
|
|
private:
|
|
bool createDataBase();
|
|
void createElementNomenclatureView();
|
|
void createSummaryView();
|
|
void createWiringListView();
|
|
void createDrawingItemView();
|
|
void populateDiagramTable();
|
|
void populateElementTable();
|
|
void populateElementInfoTable();
|
|
void populateDiagramInfoTable();
|
|
void populateConductorTable();
|
|
void populateDrawingItemTables();
|
|
bool populateFromDocument(const QDomDocument &document, QString *why = nullptr);
|
|
bool writeDrawingItem(QObject *object);
|
|
void flushDrawingItems();
|
|
void forgetDrawingItem(QObject *object);
|
|
void bindConductorValues(QSqlQuery &query, Conductor *conductor, Diagram *diagram);
|
|
void watchConductor(Conductor *conductor);
|
|
void insertTerminal(Terminal *terminal);
|
|
void insertTerminal(const QString &uuid, const QString &element_uuid,
|
|
const QString &name);
|
|
void prepareQuery();
|
|
static QHash<QString, QString> elementInfoToString(
|
|
Element *elmt);
|
|
void bindDiagramInfoValues(QSqlQuery &query, Diagram *diagram);
|
|
static void bindDiagramInfoValues(QSqlQuery &query, const QUuid &diagram_uuid,
|
|
const BorderTitleBlock &border);
|
|
static void bindDiagramInfoValues(QSqlQuery &query, const QUuid &diagram_uuid,
|
|
const DiagramContext &infos, const QDate &date);
|
|
static void bindElementValues(QSqlQuery &query, Element *element, Diagram *diagram);
|
|
static void bindElementInfoValues(QSqlQuery &query, Element *element);
|
|
static void bindElementInfoValues(QSqlQuery &query, const QString &element_uuid,
|
|
const DiagramContext &informations,
|
|
const QString &label);
|
|
|
|
private:
|
|
QPointer<QETProject> m_project;
|
|
bool m_update_blocked = false;
|
|
//Starts true : the database is empty until the first rebuild.
|
|
//Set by every method of this class that writes rows, cleared by
|
|
//updateDB(). Callers reach the database from outside only through
|
|
//newQuery(), and every such call site reads.
|
|
bool m_content_changed = true;
|
|
QSqlDatabase m_data_base;
|
|
QSqlQuery m_insert_elements_query,
|
|
m_insert_element_info_query,
|
|
m_remove_element_query,
|
|
m_remove_element_info_query,
|
|
m_update_element_query,
|
|
m_insert_diagram_query,
|
|
m_remove_diagram_query,
|
|
m_insert_diagram_info_query,
|
|
m_update_diagram_info_query,
|
|
m_diagram_order_changed,
|
|
m_diagram_info_order_changed,
|
|
m_insert_terminal_query,
|
|
m_insert_conductor_query,
|
|
m_update_conductor_query,
|
|
m_remove_conductor_query,
|
|
m_cascade_remove_element_info_query,
|
|
m_cascade_remove_terminal_query,
|
|
m_cascade_remove_conductor_query,
|
|
m_cascade_remove_element_query,
|
|
m_insert_shape_query,
|
|
m_insert_independent_text_query,
|
|
m_insert_image_query;
|
|
|
|
//Which uuid's row each drawing item last wrote, and which item
|
|
//wrote each row. A pasted copy is added to the folio still
|
|
//carrying its source's uuid and renewed only afterwards, so two
|
|
//live items can briefly share one: the row belongs to whichever
|
|
//wrote it, and the other waits in m_dirty_drawing_items until its
|
|
//uuid is its own. @see writeDrawingItem().
|
|
QHash<QObject *, QUuid> m_drawing_item_row;
|
|
QHash<QUuid, QObject *> m_drawing_row_owner;
|
|
QSet<QObject *> m_dirty_drawing_items;
|
|
|
|
#ifdef QET_EXPORT_PROJECT_DB
|
|
public:
|
|
static void exportDb(projectDataBase *db,
|
|
QWidget *parent = nullptr,
|
|
const QString &caption = QString(),
|
|
const QString &dir = QString());
|
|
#endif
|
|
};
|
|
|
|
#endif // PROJECTDATABASE_H
|