Files
qelectrotech-source-mirror/sources/factory/elementpicturefactory.h
T
ispyisail 43d27a9563 Add "Reload element drawings" to refresh placed elements (#802)
A placed element is drawn once from its definition at construction --
buildFromXml() only turns terminal/input/dynamic_text tags into live
child objects, every other primitive (line, rect, ellipse, polygon,
arc, text) is pre-rendered into a QPicture by ElementPictureFactory,
cached forever under the element's uuid with no invalidation path
anywhere in the codebase. Edit and save a symbol's drawing and every
already-placed instance keeps showing the old one until the project
is closed and reopened.

Fix, scoped to what is safe to do without ever risking a conductor or
a dynamic text's per-instance state:

- ElementPictureFactory::dropCache(location) forgets the cached
  drawing for one location, so the next fetch rebuilds it from the
  definition's current content.
- Element::reloadPicture() re-fetches and repaints one instance.
- Projet > "Recharger les dessins des éléments": walks every diagram,
  drops each distinct location's cache once, then reloads every placed
  instance.

Deliberately does not touch terminals or dynamic texts -- a definition
whose terminal positions moved still needs the existing remove-and-
reinsert workflow, since terminals are what conductors are attached to
and a wrong guess there would silently misconnect wires.

Verified: build clean, ctest 6/6. Triggered the new action on a real,
densely-wired project (76 elements) via exact keyboard-menu navigation
cross-checked against the menu's own addAction order -- ran to
completion, correct confirmation dialog, no crash, diagram unchanged
and uncorrupted afterward. Could not complete a live edit-and-watch-
it-update trace: opening the element editor on a selected item via
GUI automation was unreliable in this environment (same class of
friction as PR #888), and this sandbox has no file-based (common://)
element to mutate on disk as a shortcut -- every example project
embeds its elements. The mechanism itself is traced correct:
ElementsLocation::xml() for an embed:// location reads the project's
live in-memory collection DOM on every call, so a dropped cache
rebuilds from whatever was most recently saved.

Refs #802 (own analysis comment, 2026-08-31).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 16:24:44 +12:00

117 lines
3.6 KiB
C++

/*
Copyright 2006-2026 The 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 ELEMENTPICTUREFACTORY_H
#define ELEMENTPICTUREFACTORY_H
#include <QMutex>
#include <QSharedPointer>
#include <QHash>
class ElementsLocation;
class QPicture;
class QUuid;
class QDomElement;
class QPainter;
class QGraphicsSimpleTextItem;
/**
@brief The ElementPictureFactory class
This class is singleton factory, use
to create and get the picture use by elements
*/
class ElementPictureFactory
{
public :
struct primitives
{
QList<QLineF> m_lines;
QList<QRectF> m_rectangles;
QList<QRectF> m_circles;
QList<QVector<QPointF>> m_polygons;
QList<QVector<qreal>> m_arcs;
QList<QGraphicsSimpleTextItem*> m_texts;
};
/**
@brief instance
@return The instance of the factory
*/
static ElementPictureFactory* instance()
{
static QMutex mutex;
if (!m_factory)
{
mutex.lock();
if (!m_factory) {
m_factory = new ElementPictureFactory();
}
mutex.unlock();
}
return m_factory;
}
/**
@brief dropInstance
Drop the instance of factory
*/
static void dropInstance()
{
static QMutex mutex;
if (m_factory)
{
mutex.lock();
delete m_factory;
m_factory = nullptr;
mutex.unlock();
}
}
void getPictures(const ElementsLocation &location, QPicture &picture, QPicture &low_picture);
QPixmap pixmap(const ElementsLocation &location);
ElementPictureFactory::primitives getPrimitives(const ElementsLocation &location);
void dropCache(const ElementsLocation &location);
private:
ElementPictureFactory() {}
ElementPictureFactory (const ElementPictureFactory &);
ElementPictureFactory operator= (const ElementPictureFactory &);
~ElementPictureFactory();
static QUuid cacheKey(const ElementsLocation &location);
bool build(const ElementsLocation &location, QPicture *picture=nullptr, QPicture *low_picture=nullptr);
void parseElement(const QDomElement &dom, QPainter &painter, primitives &prim) const;
void parseLine (const QDomElement &dom, QPainter &painter, primitives &prim) const;
void parseRect (const QDomElement &dom, QPainter &painter, primitives &prim) const;
void parseEllipse(const QDomElement &dom, QPainter &painter, primitives &prim) const;
void parseCircle (const QDomElement &dom, QPainter &painter, primitives &prim) const;
void parseArc (const QDomElement &dom, QPainter &painter, primitives &prim) const;
void parsePolygon(const QDomElement &dom, QPainter &painter, primitives &prim) const;
void parseText (const QDomElement &dom, QPainter &painter, primitives &prim) const;
void parsePlcTable(const QDomElement &dom, const QDomElement &plc_data, QPainter &painter) const;
void setPainterStyle(const QDomElement &dom, QPainter &painter) const;
QHash<QUuid, QPicture> m_pictures_H;
QHash<QUuid, QPicture> m_low_pictures_H;
QHash<QUuid, QPixmap> m_pixmap_H;
QHash<QUuid, primitives> m_primitives_H;
static ElementPictureFactory* m_factory;
};
#endif // ELEMENTPICTUREFACTORY_H