mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-01 07:14:14 +02:00
Generate cabinet placement thumbnails from manufacturer/reference info
Discussion #602. Right-click a selection holding an element with both a manufacturer and a manufacturer reference: "Générer une vignette d'armoire" adds a thumbnail element for each such device to a "Cabinet thumbnails" folder of the project's embedded collection. The thumbnail is a 120x30 frame whose dynamic text shows %{manufacturer} / %{manufacturer_reference}; both values are also in the definition's element information, so it shows them when placed. A device already filed there is skipped, so running it again, or on several copies of one device, adds nothing. Revives #641, closed 2026-09-10 only to clear a review backlog. Changed from it: the frame and text are placed around the hotspot (they were drawn half outside the element), the frame is 120 wide instead of 60 (device names wrapped out of it), the file name goes through QET::stringToFileName() (a '/' in a reference made a folder), the version and font come from QetVersion and QETApp, and the action is left out of the menu when no selected element qualifies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+180
-1
@@ -45,13 +45,20 @@
|
||||
#include "ElementsCollection/xmlelementcollection.h"
|
||||
#include "NameList/nameslist.h"
|
||||
#include "elementdialog.h"
|
||||
#include "qetapp.h"
|
||||
#include "qetgraphicsitem/element.h"
|
||||
#include "qetinformation.h"
|
||||
#include "qetversion.h"
|
||||
#include <QApplication>
|
||||
#include <QDropEvent>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QUuid>
|
||||
#include <algorithm>
|
||||
|
||||
static bool hasCabinetInfo(const DiagramContext &infos);
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param diagram Schema a afficher ; si diagram vaut 0, un nouveau Diagram est utilise
|
||||
@@ -103,6 +110,10 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) :
|
||||
m_create_template = new QAction(tr("Créer un template", "context menu action"), this);
|
||||
connect(m_create_template, &QAction::triggered, this, &DiagramView::createTemplateFromSelection);
|
||||
|
||||
//Setup the action to generate cabinet placement thumbnails (discussion #602)
|
||||
m_generate_cabinet_thumbnail = new QAction(tr("Générer une vignette d'armoire", "context menu action"), this);
|
||||
connect(m_generate_cabinet_thumbnail, &QAction::triggered, this, &DiagramView::generateCabinetThumbnails);
|
||||
|
||||
//Filled each time the context menu opens, see updateFolioReportMenu()
|
||||
m_folio_report_menu = new QMenu(tr("Renvoi de folio"), this);
|
||||
|
||||
@@ -1765,7 +1776,8 @@ QList<QAction *> DiagramView::contextMenuActions() const
|
||||
QList<QAction *> list;
|
||||
if (QETDiagramEditor *qde = diagramEditor())
|
||||
{
|
||||
if (m_diagram->selectedItems().isEmpty())
|
||||
const QList<QGraphicsItem *> selected_items = m_diagram->selectedItems();
|
||||
if (selected_items.isEmpty())
|
||||
{
|
||||
//Drawing comes first. The row and column actions change
|
||||
//the folio's layout and are rarely wanted, so they sit one
|
||||
@@ -1786,6 +1798,15 @@ QList<QAction *> DiagramView::contextMenuActions() const
|
||||
list << m_multi_paste;
|
||||
list << m_separators.at(0);
|
||||
list << m_create_template; // Add the create template action
|
||||
//Disabled, and so left out below, unless a selected element
|
||||
//has both a manufacturer and a manufacturer reference.
|
||||
m_generate_cabinet_thumbnail->setEnabled(std::any_of(
|
||||
selected_items.cbegin(), selected_items.cend(),
|
||||
[](QGraphicsItem *qgi) {
|
||||
const Element *element = qgraphicsitem_cast<Element *>(qgi);
|
||||
return element && hasCabinetInfo(element->elementInformations());
|
||||
}));
|
||||
list << m_generate_cabinet_thumbnail;
|
||||
list << qde->m_conductor_reset;
|
||||
list << m_separators.at(1);
|
||||
list << qde->m_selection_actions_group.actions();
|
||||
@@ -2073,6 +2094,164 @@ void DiagramView::createTemplateFromSelection()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief hasCabinetInfo
|
||||
@return true if @a infos has both a manufacturer and a manufacturer
|
||||
reference, the two values a cabinet thumbnail shows.
|
||||
*/
|
||||
static bool hasCabinetInfo(const DiagramContext &infos)
|
||||
{
|
||||
return !infos[QETInformation::ELMT_MANUFACTURER].toString().trimmed().isEmpty()
|
||||
&& !infos[QETInformation::ELMT_MANUFACTURER_REF].toString().trimmed().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief cabinetThumbnailDefinition
|
||||
@return the definition of a thumbnail element, a 120x30 frame showing
|
||||
the manufacturer and the manufacturer reference in a dynamic text.
|
||||
The two values are also stored in the definition's element
|
||||
information, so the thumbnail shows them as soon as it is placed.
|
||||
*/
|
||||
static QDomElement cabinetThumbnailDefinition(QDomDocument &doc,
|
||||
const QString &display_name,
|
||||
const QString &manufacturer,
|
||||
const QString &reference)
|
||||
{
|
||||
QDomElement definition = doc.createElement(QStringLiteral("definition"));
|
||||
definition.setAttribute(QStringLiteral("version"), QetVersion::currentVersion().toString());
|
||||
definition.setAttribute(QStringLiteral("type"), QStringLiteral("element"));
|
||||
definition.setAttribute(QStringLiteral("link_type"), QStringLiteral("thumbnail"));
|
||||
definition.setAttribute(QStringLiteral("width"), 120);
|
||||
definition.setAttribute(QStringLiteral("height"), 30);
|
||||
definition.setAttribute(QStringLiteral("hotspot_x"), 60);
|
||||
definition.setAttribute(QStringLiteral("hotspot_y"), 15);
|
||||
doc.appendChild(definition);
|
||||
|
||||
QDomElement uuid = doc.createElement(QStringLiteral("uuid"));
|
||||
uuid.setAttribute(QStringLiteral("uuid"), QUuid::createUuid().toString());
|
||||
definition.appendChild(uuid);
|
||||
|
||||
NamesList names;
|
||||
names.addName(QStringLiteral("en"), display_name);
|
||||
definition.appendChild(names.toXml(doc));
|
||||
|
||||
QDomElement informations = doc.createElement(QStringLiteral("elementInformations"));
|
||||
DiagramContext infos;
|
||||
infos.addValue(QETInformation::ELMT_MANUFACTURER, manufacturer);
|
||||
infos.addValue(QETInformation::ELMT_MANUFACTURER_REF, reference);
|
||||
infos.toXml(informations, QStringLiteral("elementInformation"));
|
||||
definition.appendChild(informations);
|
||||
|
||||
QDomElement description = doc.createElement(QStringLiteral("description"));
|
||||
|
||||
QDomElement rect = doc.createElement(QStringLiteral("rect"));
|
||||
rect.setAttribute(QStringLiteral("x"), -60);
|
||||
rect.setAttribute(QStringLiteral("y"), -15);
|
||||
rect.setAttribute(QStringLiteral("width"), 120);
|
||||
rect.setAttribute(QStringLiteral("height"), 30);
|
||||
rect.setAttribute(QStringLiteral("rx"), 0);
|
||||
rect.setAttribute(QStringLiteral("ry"), 0);
|
||||
rect.setAttribute(QStringLiteral("style"),
|
||||
QStringLiteral("line-style:normal;line-weight:normal;filling:none;color:black"));
|
||||
rect.setAttribute(QStringLiteral("antialias"), QStringLiteral("false"));
|
||||
description.appendChild(rect);
|
||||
|
||||
QDomElement text = doc.createElement(QStringLiteral("dynamic_text"));
|
||||
text.setAttribute(QStringLiteral("x"), -57);
|
||||
text.setAttribute(QStringLiteral("y"), -14);
|
||||
text.setAttribute(QStringLiteral("z"), 1);
|
||||
text.setAttribute(QStringLiteral("text_width"), 114);
|
||||
text.setAttribute(QStringLiteral("Halignment"), QStringLiteral("AlignLeft"));
|
||||
text.setAttribute(QStringLiteral("Valignment"), QStringLiteral("AlignTop"));
|
||||
text.setAttribute(QStringLiteral("frame"), QStringLiteral("false"));
|
||||
text.setAttribute(QStringLiteral("rotation"), 0);
|
||||
text.setAttribute(QStringLiteral("keep_visual_rotation"), QStringLiteral("false"));
|
||||
text.setAttribute(QStringLiteral("text_from"), QStringLiteral("CompositeText"));
|
||||
text.setAttribute(QStringLiteral("uuid"), QUuid::createUuid().toString());
|
||||
text.setAttribute(QStringLiteral("font"), QETApp::dynamicTextsItemFont(7).toString());
|
||||
|
||||
QDomElement text_cache = doc.createElement(QStringLiteral("text"));
|
||||
text_cache.appendChild(doc.createTextNode(manufacturer + QLatin1Char('\n') + reference));
|
||||
text.appendChild(text_cache);
|
||||
|
||||
QDomElement composite_text = doc.createElement(QStringLiteral("composite_text"));
|
||||
composite_text.appendChild(doc.createTextNode(QStringLiteral("%{manufacturer}\n%{manufacturer_reference}")));
|
||||
text.appendChild(composite_text);
|
||||
|
||||
description.appendChild(text);
|
||||
definition.appendChild(description);
|
||||
return definition;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::generateCabinetThumbnails
|
||||
Context menu action (discussion #602). For every selected element with
|
||||
both a manufacturer and a manufacturer reference, add a thumbnail
|
||||
element showing them to the folder "Cabinet thumbnails" of this
|
||||
project's embedded collection, from where it can be placed on a
|
||||
cabinet layout folio like any other element. A device that already
|
||||
has a thumbnail there is skipped, so placing it several times does
|
||||
not pile up copies.
|
||||
*/
|
||||
void DiagramView::generateCabinetThumbnails()
|
||||
{
|
||||
QETProject *project = m_diagram->project();
|
||||
if (!project || project->isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
XmlElementCollection *collection = project->embeddedElementCollection();
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString dir_name = QStringLiteral("Cabinet thumbnails");
|
||||
const QString dir_path = QStringLiteral("import/") + dir_name;
|
||||
if (!collection->exist(dir_path))
|
||||
{
|
||||
NamesList dir_names;
|
||||
dir_names.addName(QStringLiteral("en"), dir_name);
|
||||
dir_names.addName(QStringLiteral("fr"), tr("Vignettes d'armoire"));
|
||||
if (!collection->createDir(QStringLiteral("import"), dir_name, dir_names)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList existing = collection->elementsNames(collection->directory(dir_path));
|
||||
int created = 0;
|
||||
const QList<QGraphicsItem *> selected_items = m_diagram->selectedItems();
|
||||
for (QGraphicsItem *qgi : selected_items)
|
||||
{
|
||||
const Element *element = qgraphicsitem_cast<Element *>(qgi);
|
||||
if (!element || !hasCabinetInfo(element->elementInformations())) {
|
||||
continue;
|
||||
}
|
||||
const DiagramContext infos = element->elementInformations();
|
||||
const QString manufacturer = infos[QETInformation::ELMT_MANUFACTURER].toString().trimmed();
|
||||
const QString reference = infos[QETInformation::ELMT_MANUFACTURER_REF].toString().trimmed();
|
||||
|
||||
//The display name keeps the values as typed; the file name
|
||||
//cannot hold characters such as '/', which would be read as
|
||||
//a folder.
|
||||
const QString display_name = manufacturer + QLatin1Char(' ') + reference;
|
||||
const QString file_name = QET::stringToFileName(display_name) + QStringLiteral(".elmt");
|
||||
if (existing.contains(file_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QDomDocument doc;
|
||||
const QDomElement definition = cabinetThumbnailDefinition(doc, display_name, manufacturer, reference);
|
||||
if (collection->addElementDefinition(dir_path, file_name, definition))
|
||||
{
|
||||
existing << file_name;
|
||||
++created;
|
||||
}
|
||||
}
|
||||
|
||||
if (created) {
|
||||
project->setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return l'editeur de schemas parent ou 0
|
||||
*/
|
||||
|
||||
@@ -58,6 +58,7 @@ class DiagramView : public PaletteGraphicsView
|
||||
QAction *m_paste_here = nullptr;
|
||||
QAction *m_multi_paste = nullptr;
|
||||
QAction *m_create_template = nullptr;
|
||||
QAction *m_generate_cabinet_thumbnail = nullptr;
|
||||
QMenu *m_folio_report_menu = nullptr;
|
||||
QPoint m_paste_here_pos;
|
||||
QPoint m_press_pos;
|
||||
@@ -197,5 +198,6 @@ class DiagramView : public PaletteGraphicsView
|
||||
void adjustGridToZoom();
|
||||
void applyReadOnly();
|
||||
void createTemplateFromSelection();
|
||||
void generateCabinetThumbnails();
|
||||
};
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user