mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-07-01 15:54:12 +02:00
Merge remote-tracking branch 'origin/master' into qt6_cmake_joshua
# Conflicts: # CMakeLists.txt
This commit is contained in:
@@ -220,7 +220,7 @@ void DynamicTextFieldEditor::fillInfoComboBox()
|
||||
QStringList strl;
|
||||
auto type = elementEditor()->elementScene()->elementData().m_type;
|
||||
|
||||
if(type & ElementData::AllReport) {
|
||||
if((type & ElementData::AllReport) || (type == ElementData::ConductorDefinition)) {
|
||||
strl = QETInformation::folioReportInfoKeys();
|
||||
}
|
||||
else {
|
||||
@@ -365,7 +365,8 @@ void DynamicTextFieldEditor::on_m_text_from_cb_activated(int index) {
|
||||
void DynamicTextFieldEditor::on_m_composite_text_pb_clicked()
|
||||
{
|
||||
bool isReport = false;
|
||||
if (elementEditor()->elementScene()->elementData().m_type & ElementData::AllReport) {
|
||||
auto type = elementEditor()->elementScene()->elementData().m_type;
|
||||
if ((type & ElementData::AllReport) || (type == ElementData::ConductorDefinition)) {
|
||||
isReport = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ void ElementPropertiesEditorWidget::setUpInterface()
|
||||
ui->m_base_type_cb->addItem (tr("Renvoi de folio précédent"), ElementData::PreviousReport);
|
||||
ui->m_base_type_cb->addItem (tr("Bornier"), ElementData::Terminal);
|
||||
ui->m_base_type_cb->addItem (tr("Vignette"), ElementData::Thumbnail);
|
||||
ui->m_base_type_cb->addItem (tr("Définition de conducteur"), ElementData::ConductorDefinition);
|
||||
|
||||
// Slave option
|
||||
ui->m_state_cb->addItem(tr("Normalement ouvert"), ElementData::NO);
|
||||
@@ -188,6 +189,9 @@ void ElementPropertiesEditorWidget::updateTree()
|
||||
case ElementData::PreviousReport:
|
||||
ui->m_tree->setDisabled(true);
|
||||
break;
|
||||
case ElementData::ConductorDefinition:
|
||||
ui->m_tree->setDisabled(true);
|
||||
break;
|
||||
case ElementData::Master:
|
||||
ui->m_tree->setEnabled(true);
|
||||
break;
|
||||
|
||||
@@ -736,40 +736,62 @@ bool QETElementEditor::checkElement()
|
||||
QList<QETWarning> warnings;
|
||||
QList<QETWarning> errors;
|
||||
|
||||
// Warning #1: Element haven't got terminal
|
||||
// (except for report, because report must have one terminal and this checking is do below)
|
||||
// Warning #1: Element haven't got terminal
|
||||
// (except for report and conductor definition, because they must have one terminal and this checking is done below)
|
||||
if (!m_elmt_scene -> containsTerminals() &&
|
||||
!(m_elmt_scene->elementData().m_type & ElementData::AllReport)) {
|
||||
!(m_elmt_scene->elementData().m_type & ElementData::AllReport) &&
|
||||
m_elmt_scene->elementData().m_type != ElementData::ConductorDefinition) {
|
||||
warnings << qMakePair(
|
||||
tr("Absence de borne", "warning title"),
|
||||
tr(
|
||||
"<br>En l'absence de borne, l'élément ne pourra être"
|
||||
" relié à d'autres éléments par l'intermédiaire de conducteurs.",
|
||||
"warning description"
|
||||
)
|
||||
);
|
||||
}
|
||||
tr("Absence de borne", "warning title"),
|
||||
tr(
|
||||
"<br>En l'absence de borne, l'élément ne pourra être"
|
||||
" relié à d'autres éléments par l'intermédiaire de conducteurs.",
|
||||
"warning description"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check folio report element
|
||||
if (m_elmt_scene->elementData().m_type & ElementData::AllReport)
|
||||
{
|
||||
int terminal =0;
|
||||
if (m_elmt_scene->elementData().m_type & ElementData::AllReport)
|
||||
{
|
||||
int terminal =0;
|
||||
|
||||
for(auto qgi : m_elmt_scene -> items()) {
|
||||
if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
||||
terminal ++;
|
||||
for(auto qgi : m_elmt_scene -> items()) {
|
||||
if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
||||
terminal ++;
|
||||
}
|
||||
}
|
||||
|
||||
//Error folio report must have only one terminal
|
||||
if (terminal != 1) {
|
||||
errors << qMakePair (tr("Absence de borne"),
|
||||
tr("<br><b>Erreur</b> :"
|
||||
"<br>Les reports de folio doivent posséder une seul borne."
|
||||
"<br><b>Solution</b> :"
|
||||
"<br>Verifier que l'élément ne possède qu'une seul borne"));
|
||||
}
|
||||
}
|
||||
|
||||
//Error folio report must have only one terminal
|
||||
if (terminal != 1) {
|
||||
errors << qMakePair (tr("Absence de borne"),
|
||||
tr("<br><b>Erreur</b> :"
|
||||
"<br>Les reports de folio doivent posséder une seul borne."
|
||||
"<br><b>Solution</b> :"
|
||||
"<br>Verifier que l'élément ne possède qu'une seul borne"));
|
||||
// Check conductor definition element
|
||||
if (m_elmt_scene->elementData().m_type == ElementData::ConductorDefinition)
|
||||
{
|
||||
int terminal =0;
|
||||
|
||||
for(auto qgi : m_elmt_scene -> items()) {
|
||||
if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
||||
terminal ++;
|
||||
}
|
||||
}
|
||||
|
||||
// Error: Conductor definition must have exactly one terminal
|
||||
if (terminal != 1) {
|
||||
errors << qMakePair (tr("Nombre de bornes incorrect"),
|
||||
tr("<br><b>Erreur</b> :"
|
||||
"<br>Les définitions de conducteur ne peuvent posséder qu'une seule borne."
|
||||
"<br><b>Solution</b> :"
|
||||
"<br>Vérifier que l'élément ne possède qu'une seule borne"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!errors.count() && !warnings.count()) {
|
||||
return(true);
|
||||
|
||||
@@ -61,7 +61,7 @@ void TerminalEditor::updateForm()
|
||||
ui->m_y_dsb->setValue(m_part->property("y").toReal());
|
||||
ui->m_orientation_cb->setCurrentIndex(ui->m_orientation_cb->findData(m_part->property("orientation")));
|
||||
ui->m_name_le->setText(m_part->terminalName());
|
||||
ui->m_type_cb->setCurrentIndex(ui->m_orientation_cb->findData(m_part->terminalType()));
|
||||
ui->m_type_cb->setCurrentIndex(ui->m_type_cb->findData(m_part->terminalType()));
|
||||
|
||||
activeConnections(true);
|
||||
}
|
||||
@@ -122,6 +122,9 @@ void TerminalEditor::init()
|
||||
ui->m_type_cb->addItem(tr("Générique"), TerminalData::Generic);
|
||||
ui->m_type_cb->addItem(tr("Bornier intérieur"), TerminalData::Inner);
|
||||
ui->m_type_cb->addItem(tr("Bornier extérieur"), TerminalData::Outer);
|
||||
ui->m_type_cb->addItem(tr("NO (contact SW)"), TerminalData::No);
|
||||
ui->m_type_cb->addItem(tr("NC (contact SW)"), TerminalData::Nc);
|
||||
ui->m_type_cb->addItem(tr("Commun (contact SW)"), TerminalData::Common);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -335,6 +335,7 @@ void TextEditor::setUpWidget(QWidget *parent)
|
||||
|
||||
m_size_sb = new QSpinBox(parent);
|
||||
m_size_sb->setObjectName(QString::fromUtf8("m_size_sb"));
|
||||
m_size_sb->setMinimum(4);
|
||||
|
||||
gridLayout->addWidget(m_size_sb, 2, 1, 1, 1);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "qeticons.h"
|
||||
#include "qetproject.h"
|
||||
#include "titleblock/templatescollection.h"
|
||||
#include <QApplication>
|
||||
|
||||
/*
|
||||
Lorsque le flag ENABLE_PANEL_DND_CHECKS est defini, le panel d'elements
|
||||
@@ -42,7 +43,7 @@ ElementsPanel::ElementsPanel(QWidget *parent) :
|
||||
first_reload_(true)
|
||||
{
|
||||
// selection unique
|
||||
setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
setColumnCount(1);
|
||||
setExpandsOnDoubleClick(true);
|
||||
setMouseTracking(true);
|
||||
@@ -299,11 +300,14 @@ void ElementsPanel::reload()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsPanel::slot_clicked
|
||||
handle click on qtwi
|
||||
@param qtwi item that was clickerd on
|
||||
*/
|
||||
* @brief ElementsPanel::slot_clicked
|
||||
* handle click on qtwi
|
||||
* @param qtwi item that was clickerd on
|
||||
*/
|
||||
void ElementsPanel::slot_clicked(QTreeWidgetItem *clickedItem, int) {
|
||||
if (QApplication::keyboardModifiers() & (Qt::ShiftModifier | Qt::ControlModifier)) {
|
||||
return;
|
||||
}
|
||||
|
||||
requestForItem(clickedItem);
|
||||
}
|
||||
@@ -553,3 +557,20 @@ void ElementsPanel::keyPressEvent(QKeyEvent *event)
|
||||
QTreeView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ElementsPanel::selectedDiagrams
|
||||
* @return A list of all currently selected diagrams in the panel.
|
||||
*/
|
||||
QList<Diagram *> ElementsPanel::selectedDiagrams() const
|
||||
{
|
||||
QList<Diagram *> diagrams;
|
||||
foreach (QTreeWidgetItem *item, selectedItems()) {
|
||||
if (item->type() == QET::Diagram) {
|
||||
if (Diagram *diagram = valueForItem<Diagram *>(item)) {
|
||||
diagrams.append(diagram);
|
||||
}
|
||||
}
|
||||
}
|
||||
return diagrams;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ class ElementsPanel : public GenericPanel {
|
||||
// methods used to get what is represented by a particular visual item
|
||||
QString dirPathForItem(QTreeWidgetItem *);
|
||||
QString filePathForItem(QTreeWidgetItem *);
|
||||
QList<Diagram *> selectedDiagrams() const;
|
||||
|
||||
signals:
|
||||
void requestForProject(QETProject *);
|
||||
|
||||
+181
-122
@@ -25,6 +25,7 @@
|
||||
#include "qetproject.h"
|
||||
#include "titleblock/templatedeleter.h"
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
|
||||
/*
|
||||
When the ENABLE_PANEL_WIDGET_DND_CHECKS flag is set, the panel
|
||||
@@ -242,85 +243,134 @@ void ElementsPanelWidget::newDiagram()
|
||||
}
|
||||
|
||||
/**
|
||||
Emet le signal requestForDiagramDeletion avec le schema selectionne
|
||||
*/
|
||||
* Emet le signal requestForDiagramsDeletion avec les schemas selectionnes
|
||||
*/
|
||||
void ElementsPanelWidget::deleteDiagram()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramDeletion(selected_diagram));
|
||||
elements_panel->reload();
|
||||
QList<Diagram *> diagrams_to_delete = elements_panel->selectedDiagrams();
|
||||
|
||||
if (diagrams_to_delete.isEmpty()) return;
|
||||
|
||||
emit(requestForDiagramsDeletion(diagrams_to_delete));
|
||||
|
||||
elements_panel->reload();
|
||||
}
|
||||
/**
|
||||
* Emits the requestForDiagramMoveUpTop signal with all selected diagrams.
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramUpTop() {
|
||||
QList<Diagram *> diagrams_to_move = elements_panel->selectedDiagrams();
|
||||
if (diagrams_to_move.isEmpty()) return;
|
||||
|
||||
// Emit the entire list at once
|
||||
emit requestForDiagramMoveUpTop(diagrams_to_move);
|
||||
|
||||
// Clear messy tree selection caused by moving items, then restore clean selection
|
||||
elements_panel->clearSelection();
|
||||
for (Diagram *d : diagrams_to_move) {
|
||||
if (auto item = elements_panel->getItemForDiagram(d)) item->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Emet le signal requestForDiagramMoveUpTop avec le schema selectionne
|
||||
+*/
|
||||
void ElementsPanelWidget::moveDiagramUpTop()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramMoveUpTop(selected_diagram));
|
||||
}
|
||||
}
|
||||
* Emits the requestForDiagramMoveUp signal with all selected diagrams.
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramUp() {
|
||||
QList<Diagram *> diagrams_to_move = elements_panel->selectedDiagrams();
|
||||
if (diagrams_to_move.isEmpty()) return;
|
||||
|
||||
// Emit the entire list at once
|
||||
emit requestForDiagramMoveUp(diagrams_to_move);
|
||||
|
||||
|
||||
/**
|
||||
Emet le signal requestForDiagramMoveUp avec le schema selectionne
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramUp()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramMoveUp(selected_diagram));
|
||||
// Clear messy tree selection caused by moving items, then restore clean selection
|
||||
elements_panel->clearSelection();
|
||||
for (Diagram *d : diagrams_to_move) {
|
||||
if (auto item = elements_panel->getItemForDiagram(d)) item->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Emet le signal requestForDiagramMoveDown avec le schema selectionne
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramDown()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramMoveDown(selected_diagram));
|
||||
* Emits the requestForDiagramMoveDown signal with all selected diagrams.
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramDown() {
|
||||
QList<Diagram *> diagrams_to_move = elements_panel->selectedDiagrams();
|
||||
if (diagrams_to_move.isEmpty()) return;
|
||||
|
||||
// Emit the entire list at once
|
||||
emit requestForDiagramMoveDown(diagrams_to_move);
|
||||
|
||||
// Clear messy tree selection caused by moving items, then restore clean selection
|
||||
elements_panel->clearSelection();
|
||||
for (Diagram *d : diagrams_to_move) {
|
||||
if (auto item = elements_panel->getItemForDiagram(d)) item->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Emet le signal requestForDiagramMoveUpx10 avec le schema selectionne
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramUpx10()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramMoveUpx10(selected_diagram));
|
||||
* Emits the requestForDiagramMoveUpx10 signal with all selected diagrams.
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramUpx10() {
|
||||
QList<Diagram *> diagrams_to_move = elements_panel->selectedDiagrams();
|
||||
if (diagrams_to_move.isEmpty()) return;
|
||||
|
||||
// Emit the entire list at once
|
||||
emit requestForDiagramMoveUpx10(diagrams_to_move);
|
||||
|
||||
// Clear messy tree selection caused by moving items, then restore clean selection
|
||||
elements_panel->clearSelection();
|
||||
for (Diagram *d : diagrams_to_move) {
|
||||
if (auto item = elements_panel->getItemForDiagram(d)) item->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Emet le signal requestForDiagramMoveUpx100 avec le schema selectionne
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramUpx100()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramMoveUpx100(selected_diagram));
|
||||
* Emits the requestForDiagramMoveUpx100 signal with all selected diagrams.
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramUpx100() {
|
||||
QList<Diagram *> diagrams_to_move = elements_panel->selectedDiagrams();
|
||||
if (diagrams_to_move.isEmpty()) return;
|
||||
|
||||
// Emit the entire list at once
|
||||
emit requestForDiagramMoveUpx100(diagrams_to_move);
|
||||
|
||||
// Clear messy tree selection caused by moving items, then restore clean selection
|
||||
elements_panel->clearSelection();
|
||||
for (Diagram *d : diagrams_to_move) {
|
||||
if (auto item = elements_panel->getItemForDiagram(d)) item->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Emet le signal requestForDiagramMoveDownx10 avec le schema selectionne
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramDownx10()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramMoveDownx10(selected_diagram));
|
||||
* Emits the requestForDiagramMoveDownx10 signal with all selected diagrams.
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramDownx10() {
|
||||
QList<Diagram *> diagrams_to_move = elements_panel->selectedDiagrams();
|
||||
if (diagrams_to_move.isEmpty()) return;
|
||||
|
||||
// Emit the entire list at once
|
||||
emit requestForDiagramMoveDownx10(diagrams_to_move);
|
||||
|
||||
// Clear messy tree selection caused by moving items, then restore clean selection
|
||||
elements_panel->clearSelection();
|
||||
for (Diagram *d : diagrams_to_move) {
|
||||
if (auto item = elements_panel->getItemForDiagram(d)) item->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Emet le signal requestForDiagramMoveDownx100 avec le schema selectionne
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramDownx100()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramMoveDownx100(selected_diagram));
|
||||
* Emits the requestForDiagramMoveDownx100 signal with all selected diagrams.
|
||||
*/
|
||||
void ElementsPanelWidget::moveDiagramDownx100() {
|
||||
QList<Diagram *> diagrams_to_move = elements_panel->selectedDiagrams();
|
||||
if (diagrams_to_move.isEmpty()) return;
|
||||
|
||||
// Emit the entire list at once
|
||||
emit requestForDiagramMoveDownx100(diagrams_to_move);
|
||||
|
||||
// Clear messy tree selection caused by moving items, then restore clean selection
|
||||
elements_panel->clearSelection();
|
||||
for (Diagram *d : diagrams_to_move) {
|
||||
if (auto item = elements_panel->getItemForDiagram(d)) item->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,21 +428,35 @@ void ElementsPanelWidget::updateButtons()
|
||||
bool is_writable = !(elements_panel -> selectedProject() -> isReadOnly());
|
||||
prj_add_diagram -> setEnabled(is_writable);
|
||||
} else if (current_type == QET::Diagram) {
|
||||
Diagram *selected_diagram = elements_panel -> selectedDiagram();
|
||||
QETProject *selected_diagram_project = selected_diagram -> project();
|
||||
// Fetch ALL selected diagrams instead of just one
|
||||
QList<Diagram *> selected_diagrams = elements_panel -> selectedDiagrams();
|
||||
|
||||
bool is_writable = !(selected_diagram_project -> isReadOnly());
|
||||
int project_diagrams_count = selected_diagram_project -> diagrams().count();
|
||||
int diagram_position = selected_diagram_project -> diagrams().indexOf(selected_diagram);
|
||||
if (!selected_diagrams.isEmpty()) {
|
||||
QETProject *selected_diagram_project = selected_diagrams.first() -> project();
|
||||
bool is_writable = !(selected_diagram_project -> isReadOnly());
|
||||
int project_diagrams_count = selected_diagram_project -> diagrams().count();
|
||||
|
||||
prj_del_diagram -> setEnabled(is_writable);
|
||||
prj_move_diagram_up -> setEnabled(is_writable && diagram_position > 0);
|
||||
prj_move_diagram_down -> setEnabled(is_writable && diagram_position < project_diagrams_count - 1);
|
||||
prj_move_diagram_top -> setEnabled(is_writable && diagram_position > 0);
|
||||
prj_move_diagram_upx10 -> setEnabled(is_writable && diagram_position > 10);
|
||||
prj_move_diagram_upx100 -> setEnabled(is_writable && diagram_position > 100);
|
||||
prj_move_diagram_downx10 -> setEnabled(is_writable && diagram_position < project_diagrams_count - 10);
|
||||
prj_move_diagram_downx100 -> setEnabled(is_writable && diagram_position < project_diagrams_count - 100);
|
||||
// Find the highest (min) and lowest (max) index among the selection
|
||||
int min_position = project_diagrams_count;
|
||||
int max_position = -1;
|
||||
|
||||
for (Diagram *diagram : selected_diagrams) {
|
||||
int pos = selected_diagram_project -> diagrams().indexOf(diagram);
|
||||
if (pos < min_position) min_position = pos;
|
||||
if (pos > max_position) max_position = pos;
|
||||
}
|
||||
|
||||
prj_del_diagram -> setEnabled(is_writable);
|
||||
prj_move_diagram_up -> setEnabled(is_writable && min_position > 0);
|
||||
prj_move_diagram_down -> setEnabled(is_writable && max_position < project_diagrams_count - 1);
|
||||
prj_move_diagram_top -> setEnabled(is_writable && min_position > 0);
|
||||
|
||||
// Adjusted to >= to allow exactly 10 or 100 steps if space permits
|
||||
prj_move_diagram_upx10 -> setEnabled(is_writable && min_position > 10);
|
||||
prj_move_diagram_upx100 -> setEnabled(is_writable && min_position > 100);
|
||||
prj_move_diagram_downx10 -> setEnabled(is_writable && max_position < project_diagrams_count - 10);
|
||||
prj_move_diagram_downx100 -> setEnabled(is_writable && max_position < project_diagrams_count - 100);
|
||||
}
|
||||
} else if (current_type == QET::TitleBlockTemplatesCollection) {
|
||||
TitleBlockTemplateLocation location = elements_panel -> templateLocationForItem(current_item);
|
||||
tbt_add -> setEnabled(!location.isReadOnly());
|
||||
@@ -475,62 +539,57 @@ void ElementsPanelWidget::filterEdited(const QString &next_text) {
|
||||
}
|
||||
|
||||
/**
|
||||
Treat key press event inside elements panel widget
|
||||
*/
|
||||
void ElementsPanelWidget::keyPressEvent (QKeyEvent *e) {
|
||||
switch(e -> key()) {
|
||||
case Qt::Key_Delete: //delete diagram through elements panel widget
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramDeletion(selected_diagram));
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F3:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUp(selected_diagram));
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F4:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDown(selected_diagram));
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F5:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpTop(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F6:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDownx10(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F7:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDownx100(selected_diagram));
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
case Qt::Key_F8:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpx10(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F9:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpx100(selected_diagram));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
* Treat key press event inside elements panel widget
|
||||
*/
|
||||
/**
|
||||
* Treat key press event inside elements panel widget.
|
||||
* Respects the enabled/disabled state of the corresponding QActions.
|
||||
*/
|
||||
void ElementsPanelWidget::keyPressEvent(QKeyEvent *e) {
|
||||
switch(e->key()) {
|
||||
case Qt::Key_Delete:
|
||||
if (prj_del_diagram && prj_del_diagram->isEnabled()) {
|
||||
deleteDiagram();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F3:
|
||||
if (prj_move_diagram_up && prj_move_diagram_up->isEnabled()) {
|
||||
moveDiagramUp();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F4:
|
||||
if (prj_move_diagram_down && prj_move_diagram_down->isEnabled()) {
|
||||
moveDiagramDown();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F5:
|
||||
if (prj_move_diagram_top && prj_move_diagram_top->isEnabled()) {
|
||||
moveDiagramUpTop();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F6:
|
||||
if (prj_move_diagram_downx10 && prj_move_diagram_downx10->isEnabled()) {
|
||||
moveDiagramDownx10();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F7:
|
||||
if (prj_move_diagram_downx100 && prj_move_diagram_downx100->isEnabled()) {
|
||||
moveDiagramDownx100();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F8:
|
||||
if (prj_move_diagram_upx10 && prj_move_diagram_upx10->isEnabled()) {
|
||||
moveDiagramUpx10();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F9:
|
||||
if (prj_move_diagram_upx100 && prj_move_diagram_upx100->isEnabled()) {
|
||||
moveDiagramUpx100();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Pass unhandled key events to the base class
|
||||
QWidget::keyPressEvent(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,13 +69,14 @@ class ElementsPanelWidget : public QWidget {
|
||||
void requestForProjectPropertiesEdition(QETProject *);
|
||||
void requestForDiagramPropertiesEdition(Diagram *);
|
||||
void requestForDiagramDeletion(Diagram *);
|
||||
void requestForDiagramMoveUp(Diagram *);
|
||||
void requestForDiagramMoveDown(Diagram *);
|
||||
void requestForDiagramMoveUpTop(Diagram *);
|
||||
void requestForDiagramMoveUpx10(Diagram *);
|
||||
void requestForDiagramMoveUpx100(Diagram *);
|
||||
void requestForDiagramMoveDownx10(Diagram *);
|
||||
void requestForDiagramMoveDownx100(Diagram *);
|
||||
void requestForDiagramsDeletion(const QList<Diagram *> &diagrams);
|
||||
void requestForDiagramMoveUp(const QList<Diagram *> &diagrams);
|
||||
void requestForDiagramMoveDown(const QList<Diagram *> &diagrams);
|
||||
void requestForDiagramMoveUpTop(const QList<Diagram *> &diagrams);
|
||||
void requestForDiagramMoveUpx10(const QList<Diagram *> &diagrams);
|
||||
void requestForDiagramMoveUpx100(const QList<Diagram *> &diagrams);
|
||||
void requestForDiagramMoveDownx10(const QList<Diagram *> &diagrams);
|
||||
void requestForDiagramMoveDownx100(const QList<Diagram *> &diagrams);
|
||||
|
||||
public slots:
|
||||
void openDirectoryForSelectedItem();
|
||||
|
||||
+74
-21
@@ -364,11 +364,12 @@ QETResult ProjectView::noProjectResult() const
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ProjectView::removeDiagram
|
||||
Remove a diagram (folio) of the project
|
||||
@param diagram_view : diagram view to remove
|
||||
*/
|
||||
void ProjectView::removeDiagram(DiagramView *diagram_view)
|
||||
* @brief ProjectView::removeDiagram
|
||||
* Remove a diagram (folio) of the project
|
||||
* @param diagram_view : diagram view to remove
|
||||
* @param silent : if true, bypasses the confirmation message box
|
||||
*/
|
||||
void ProjectView::removeDiagram(DiagramView *diagram_view, bool silent)
|
||||
{
|
||||
if (!diagram_view)
|
||||
return;
|
||||
@@ -377,17 +378,18 @@ void ProjectView::removeDiagram(DiagramView *diagram_view)
|
||||
if (!m_diagram_ids.values().contains(diagram_view))
|
||||
return;
|
||||
|
||||
|
||||
//Ask confirmation to user.
|
||||
int answer = QET::QetMessageBox::question(
|
||||
this,
|
||||
tr("Supprimer le folio ?", "message box title"),
|
||||
tr("Êtes-vous sûr de vouloir supprimer ce folio du projet ? Ce changement est irréversible.", "message box content"),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
|
||||
QMessageBox::No
|
||||
);
|
||||
if (answer != QMessageBox::Yes) {
|
||||
return;
|
||||
if (!silent) {
|
||||
//Ask confirmation to user.
|
||||
int answer = QET::QetMessageBox::question(
|
||||
this,
|
||||
tr("Supprimer le folio ?", "message box title"),
|
||||
tr("Êtes-vous sûr de vouloir supprimer ce folio du projet ? Ce changement est irréversible.", "message box content"),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
|
||||
QMessageBox::No
|
||||
);
|
||||
if (answer != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Remove the diagram view of the tabs widget
|
||||
@@ -405,14 +407,15 @@ void ProjectView::removeDiagram(DiagramView *diagram_view)
|
||||
}
|
||||
|
||||
/**
|
||||
Enleve un schema du ProjectView
|
||||
@param diagram Schema a enlever
|
||||
*/
|
||||
void ProjectView::removeDiagram(Diagram *diagram) {
|
||||
* Enleve un schema du ProjectView
|
||||
* @param diagram Schema a enlever
|
||||
* @param silent Si vrai, supprime sans demander confirmation
|
||||
*/
|
||||
void ProjectView::removeDiagram(Diagram *diagram, bool silent) {
|
||||
if (!diagram) return;
|
||||
|
||||
if (DiagramView *diagram_view = findDiagram(diagram)) {
|
||||
removeDiagram(diagram_view);
|
||||
removeDiagram(diagram_view, silent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,6 +560,56 @@ void ProjectView::moveDiagramUpx10(Diagram *diagram) {
|
||||
moveDiagramUpx10(findDiagram(diagram));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ProjectView::moveDiagramUpx100
|
||||
* Moves the diagram_view up / left x100
|
||||
* @param diagram_view View to move
|
||||
*/
|
||||
void ProjectView::moveDiagramUpx100(DiagramView *diagram_view) {
|
||||
if (!diagram_view) return;
|
||||
|
||||
int diagram_view_position = m_diagram_ids.key(diagram_view);
|
||||
if (!diagram_view_position) {
|
||||
// The diagram is the first of the project
|
||||
return;
|
||||
}
|
||||
m_tab->tabBar()->moveTab(diagram_view_position, diagram_view_position - 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ProjectView::moveDiagramUpx100
|
||||
* Moves the diagram up / left x100
|
||||
* @param diagram Diagram to move
|
||||
*/
|
||||
void ProjectView::moveDiagramUpx100(Diagram *diagram) {
|
||||
moveDiagramUpx100(findDiagram(diagram));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ProjectView::moveDiagramDownx100
|
||||
* Moves the diagram_view down / right x100
|
||||
* @param diagram_view View to move
|
||||
*/
|
||||
void ProjectView::moveDiagramDownx100(DiagramView *diagram_view) {
|
||||
if (!diagram_view) return;
|
||||
|
||||
int diagram_view_position = m_diagram_ids.key(diagram_view);
|
||||
if (diagram_view_position + 1 == m_diagram_ids.count()) {
|
||||
// The diagram is the last of the project
|
||||
return;
|
||||
}
|
||||
m_tab->tabBar()->moveTab(diagram_view_position, diagram_view_position + 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ProjectView::moveDiagramDownx100
|
||||
* Moves the diagram down / right x100
|
||||
* @param diagram Diagram to move
|
||||
*/
|
||||
void ProjectView::moveDiagramDownx100(Diagram *diagram) {
|
||||
moveDiagramDownx100(findDiagram(diagram));
|
||||
}
|
||||
|
||||
/**
|
||||
Deplace le schema diagram_view vers le bas / la droite x10
|
||||
*/
|
||||
|
||||
@@ -104,8 +104,8 @@ class ProjectView : public QWidget
|
||||
void changeLastTab();
|
||||
|
||||
public slots:
|
||||
void removeDiagram(DiagramView *);
|
||||
void removeDiagram(Diagram *);
|
||||
void removeDiagram(DiagramView *diagram_view, bool silent = false);
|
||||
void removeDiagram(Diagram *diagram, bool silent = false);
|
||||
void showDiagram(DiagramView *);
|
||||
void showDiagram(Diagram *);
|
||||
void editProjectProperties();
|
||||
@@ -122,6 +122,10 @@ class ProjectView : public QWidget
|
||||
void moveDiagramUpx10(Diagram *);
|
||||
void moveDiagramDownx10(DiagramView *);
|
||||
void moveDiagramDownx10(Diagram *);
|
||||
void moveDiagramUpx100(DiagramView *);
|
||||
void moveDiagramUpx100(Diagram *);
|
||||
void moveDiagramDownx100(DiagramView *);
|
||||
void moveDiagramDownx100(Diagram *);
|
||||
void exportProject();
|
||||
QETResult save();
|
||||
QETResult saveAs();
|
||||
|
||||
@@ -45,14 +45,26 @@ QDomElement ElementData::toXml(QDomDocument &xml_element) const {
|
||||
bool ElementData::fromXml(const QDomElement &xml_element)
|
||||
{
|
||||
if(xml_element.tagName() != QLatin1String("definition") ||
|
||||
xml_element.attribute(QStringLiteral("type")) != QLatin1String("element")) {
|
||||
xml_element.attribute(QStringLiteral("type")) != QLatin1String("element")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// --- HIER STARTET UNSER DEBUG-BLOCK ---
|
||||
// Wir holen den String aus der XML und speichern ihn kurz zwischen
|
||||
QString raw_type_string = xml_element.attribute(QStringLiteral("link_type"), QStringLiteral("simple"));
|
||||
|
||||
qDebug() << "\n=== NEUES BAUTEIL WIRD GELADEN ===";
|
||||
qDebug() << "[XML Parser] Roher 'link_type' String aus der .elmt Datei:" << raw_type_string;
|
||||
|
||||
// Jetzt übergeben wir ihn an deine Übersetzungs-Funktion
|
||||
m_type = typeFromString(raw_type_string);
|
||||
|
||||
qDebug() << "[XML Parser] Übersetzter ElementData-Typ:" << typeToString(m_type);
|
||||
// --- HIER ENDET UNSER DEBUG-BLOCK ---
|
||||
|
||||
m_type = typeFromString(xml_element.attribute(QStringLiteral("link_type"), QStringLiteral("simple")));
|
||||
kindInfoFromXml(xml_element);
|
||||
m_informations.fromXml(xml_element.firstChildElement(QStringLiteral("elementInformations")),
|
||||
QStringLiteral("elementInformation"));
|
||||
QStringLiteral("elementInformation"));
|
||||
m_names_list.fromXml(xml_element);
|
||||
|
||||
auto xml_draw_info = xml_element.firstChildElement(QStringLiteral("informations"));
|
||||
@@ -323,6 +335,8 @@ QString ElementData::typeToString(ElementData::Type type)
|
||||
return QStringLiteral("terminal");
|
||||
case ElementData::Thumbnail:
|
||||
return QStringLiteral("thumbnail");
|
||||
case ElementData::ConductorDefinition:
|
||||
return QStringLiteral("conductor_definition");
|
||||
default:
|
||||
qDebug() << "ElementData::typeToString : type don't exist"
|
||||
<< "return failsafe value 'simple'";
|
||||
@@ -346,6 +360,8 @@ ElementData::Type ElementData::typeFromString(const QString &string)
|
||||
return ElementData::Terminal;
|
||||
} else if (string == QLatin1String("thumbnail")) {
|
||||
return ElementData::Thumbnail;
|
||||
} else if (string == QLatin1String("conductor_definition")) {
|
||||
return ElementData::ConductorDefinition;
|
||||
}
|
||||
|
||||
//Return simple if nothing match
|
||||
|
||||
@@ -41,7 +41,8 @@ class ElementData : public PropertiesInterface
|
||||
Master = 8,
|
||||
Slave = 16,
|
||||
Terminal = 32,
|
||||
Thumbnail = 64};
|
||||
Thumbnail = 64,
|
||||
ConductorDefinition = 128};
|
||||
Q_ENUM(Type)
|
||||
Q_DECLARE_FLAGS(Types, Type)
|
||||
|
||||
|
||||
@@ -174,6 +174,12 @@ QString TerminalData::typeToString(TerminalData::Type type)
|
||||
return QString("Inner");
|
||||
case Outer :
|
||||
return QString("Outer");
|
||||
case No :
|
||||
return QString("No");
|
||||
case Nc :
|
||||
return QString("Nc");
|
||||
case Common :
|
||||
return QString("Common");
|
||||
}
|
||||
return QString("Generic");
|
||||
}
|
||||
@@ -193,6 +199,12 @@ TerminalData::Type TerminalData::typeFromString(const QString &string)
|
||||
return TerminalData::Inner;
|
||||
} else if (string == "Outer") {
|
||||
return TerminalData::Outer;
|
||||
} else if (string == "No") {
|
||||
return TerminalData::No;
|
||||
} else if (string == "Nc") {
|
||||
return TerminalData::Nc;
|
||||
} else if (string == "Common") {
|
||||
return TerminalData::Common;
|
||||
} else {
|
||||
qDebug() << "TerminalData::typeFromString, argument string is invalid"
|
||||
" failsafe type 'TerminalData::Generic' is returned";
|
||||
|
||||
@@ -41,7 +41,10 @@ class TerminalData : public PropertiesInterface
|
||||
enum Type {
|
||||
Generic,
|
||||
Inner,
|
||||
Outer
|
||||
Outer,
|
||||
No, ///< Normally Open terminal (for SW contacts)
|
||||
Nc, ///< Normally Closed terminal (for SW contacts)
|
||||
Common ///< Common terminal (for SW contacts)
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
XRefProperties::XRefProperties()
|
||||
{
|
||||
m_show_power_ctc = true;
|
||||
m_show_terminal_name = true;
|
||||
m_display = Cross;
|
||||
m_snap_to = Bottom;
|
||||
m_prefix_keys << "power" << "delay" << "switch";
|
||||
@@ -48,6 +49,7 @@ void XRefProperties::toSettings(QSettings &settings,
|
||||
const QString prefix) const
|
||||
{
|
||||
settings.setValue(prefix % "showpowerctc", m_show_power_ctc);
|
||||
settings.setValue(prefix % "showterminalname", m_show_terminal_name);
|
||||
QString display = m_display == Cross? "cross" : "contacts";
|
||||
settings.setValue(prefix % "displayhas", display);
|
||||
QString snap = m_snap_to == Bottom? "bottom" : "label";
|
||||
@@ -78,6 +80,7 @@ void XRefProperties::fromSettings(const QSettings &settings,
|
||||
const QString prefix)
|
||||
{
|
||||
m_show_power_ctc = settings.value(prefix % "showpowerctc", true).toBool();
|
||||
m_show_terminal_name = settings.value(prefix % "showterminalname", true).toBool();
|
||||
QString display = settings.value(prefix % "displayhas", "cross").toString();
|
||||
display == "cross"? m_display = Cross : m_display = Contacts;
|
||||
QString snap = settings.value(prefix % "snapto", "label").toString();
|
||||
@@ -107,6 +110,7 @@ QDomElement XRefProperties::toXml(QDomDocument &xml_document) const
|
||||
xml_element.setAttribute("type", m_key);
|
||||
|
||||
xml_element.setAttribute("showpowerctc", m_show_power_ctc? "true" : "false");
|
||||
xml_element.setAttribute("showterminalname", m_show_terminal_name? "true" : "false");
|
||||
QString display = m_display == Cross? "cross" : "contacts";
|
||||
xml_element.setAttribute("displayhas", display);
|
||||
QString snap = m_snap_to == Bottom? "bottom" : "label";
|
||||
@@ -137,6 +141,7 @@ QDomElement XRefProperties::toXml(QDomDocument &xml_document) const
|
||||
*/
|
||||
bool XRefProperties::fromXml(const QDomElement &xml_element) {
|
||||
m_show_power_ctc = xml_element.attribute("showpowerctc") == "true";
|
||||
m_show_terminal_name = xml_element.attribute("showterminalname", "true") == "true";
|
||||
QString display = xml_element.attribute("displayhas", "cross");
|
||||
display == "cross"? m_display = Cross : m_display = Contacts;
|
||||
QString snap = xml_element.attribute("snapto", "label");
|
||||
@@ -188,6 +193,7 @@ QHash<QString, XRefProperties> XRefProperties::defaultProperties()
|
||||
|
||||
bool XRefProperties::operator ==(const XRefProperties &xrp) const{
|
||||
return (m_show_power_ctc == xrp.m_show_power_ctc
|
||||
&& m_show_terminal_name == xrp.m_show_terminal_name
|
||||
&& m_display == xrp.m_display
|
||||
&& m_snap_to == xrp.m_snap_to
|
||||
&& m_prefix == xrp.m_prefix
|
||||
|
||||
@@ -57,6 +57,9 @@ class XRefProperties : public PropertiesInterface
|
||||
void setShowPowerContac (const bool a) {m_show_power_ctc = a;}
|
||||
bool showPowerContact () const {return m_show_power_ctc;}
|
||||
|
||||
void setShowTerminalName (const bool a) {m_show_terminal_name = a;}
|
||||
bool showTerminalName () const {return m_show_terminal_name;}
|
||||
|
||||
void setDisplayHas (const DisplayHas dh) {m_display = dh;}
|
||||
DisplayHas displayHas () const {return m_display;}
|
||||
|
||||
@@ -81,6 +84,7 @@ class XRefProperties : public PropertiesInterface
|
||||
|
||||
private:
|
||||
bool m_show_power_ctc;
|
||||
bool m_show_terminal_name;
|
||||
DisplayHas m_display;
|
||||
SnapTo m_snap_to;
|
||||
Qt::AlignmentFlag m_xref_pos;
|
||||
|
||||
+153
-95
@@ -16,7 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qetdiagrameditor.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include "ElementsCollection/elementscollectionwidget.h"
|
||||
#include "QWidgetAnimation/qwidgetanimation.h"
|
||||
#include "autoNum/ui/autonumberingdockwidget.h"
|
||||
@@ -47,7 +47,7 @@
|
||||
#include "TerminalStrip/ui/addterminalstripitemdialog.h"
|
||||
#include "wiringlistexport.h"
|
||||
#include "ui/terminalnumberingdialog.h"
|
||||
|
||||
#include <QDebug>
|
||||
#ifdef BUILD_WITHOUT_KF5
|
||||
#else
|
||||
# include <KAutoSaveFile>
|
||||
@@ -176,12 +176,14 @@ void QETDiagramEditor::setUpElementsPanel()
|
||||
connect(pa, SIGNAL(requestForProjectPropertiesEdition (QETProject *)), this, SLOT(editProjectProperties(QETProject *)));
|
||||
connect(pa, SIGNAL(requestForNewDiagram (QETProject *)), this, SLOT(addDiagramToProject(QETProject *)));
|
||||
connect(pa, SIGNAL(requestForDiagramPropertiesEdition (Diagram *)), this, SLOT(editDiagramProperties(Diagram *)));
|
||||
connect(pa, SIGNAL(requestForDiagramDeletion (Diagram *)), this, SLOT(removeDiagram(Diagram *)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveUp (Diagram *)), this, SLOT(moveDiagramUp(Diagram *)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveDown (Diagram *)), this, SLOT(moveDiagramDown(Diagram *)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveUpTop (Diagram *)), this, SLOT(moveDiagramUpTop(Diagram *)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveUpx10 (Diagram *)), this, SLOT(moveDiagramUpx10(Diagram *)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveDownx10 (Diagram *)), this, SLOT(moveDiagramDownx10(Diagram *)));
|
||||
connect(pa, SIGNAL(requestForDiagramsDeletion (const QList<Diagram *> &)), this, SLOT(removeDiagrams(const QList<Diagram *> &)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveUp (const QList<Diagram *> &)), this, SLOT(moveDiagramUp(const QList<Diagram *>&)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveDown (const QList<Diagram *> &)), this, SLOT(moveDiagramDown(const QList<Diagram *>&)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveUpTop (const QList<Diagram *> &)), this, SLOT(moveDiagramUpTop(const QList<Diagram *>&)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveUpx10 (const QList<Diagram *> &)), this, SLOT(moveDiagramUpx10(const QList<Diagram *>&)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveDownx10 (const QList<Diagram *> &)), this, SLOT(moveDiagramDownx10(const QList<Diagram *>&)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveUpx100 (const QList<Diagram *> &)), this, SLOT(moveDiagramUpx100(const QList<Diagram *>&)));
|
||||
connect(pa, SIGNAL(requestForDiagramMoveDownx100 (const QList<Diagram *> &)), this, SLOT(moveDiagramDownx100(const QList<Diagram *>&)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2183,126 +2185,182 @@ void QETDiagramEditor::addDiagramToProject(QETProject *project)
|
||||
project_view->project()->addNewDiagram();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief QETDiagramEditor::removeDiagram
|
||||
* Wrapper für einzelne Diagramme, um Abwärtskompatibilität zu erhalten.
|
||||
*/
|
||||
void QETDiagramEditor::removeDiagram(Diagram *diagram)
|
||||
{
|
||||
if (!diagram) return;
|
||||
QList<Diagram *> list;
|
||||
list << diagram;
|
||||
removeDiagrams(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QETDiagramEditor::removeDiagrams
|
||||
* Deletes a list of folios with a single query.
|
||||
*/
|
||||
void QETDiagramEditor::removeDiagrams(const QList<Diagram *> &diagrams)
|
||||
{
|
||||
if (diagrams.isEmpty()) return;
|
||||
|
||||
if (diagrams.count() == 1) {
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this, tr("Supprimer le folio"),
|
||||
tr("Êtes-vous sûr de vouloir supprimer ce folio ?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (reply == QMessageBox::No) return;
|
||||
} else {
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this, tr("Supprimer les folios"),
|
||||
tr("Êtes-vous sûr de vouloir supprimer les %1 folios sélectionnés ?").arg(diagrams.count()),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (reply == QMessageBox::No) return;
|
||||
}
|
||||
|
||||
ProjectView *project_view = nullptr;
|
||||
if (QETProject *diagram_project = diagrams.first()->project()) {
|
||||
project_view = findProject(diagram_project);
|
||||
}
|
||||
|
||||
if (project_view) project_view->setUpdatesEnabled(false);
|
||||
if (pa) pa->setUpdatesEnabled(false);
|
||||
|
||||
foreach (Diagram *diagram, diagrams) {
|
||||
removeDiagramSilent(diagram);
|
||||
}
|
||||
|
||||
if (pa) pa->setUpdatesEnabled(true);
|
||||
if (project_view) project_view->setUpdatesEnabled(true);
|
||||
|
||||
emit syncElementsPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
Supprime un schema de son projet
|
||||
@param diagram Schema a supprimer
|
||||
*/
|
||||
void QETDiagramEditor::removeDiagram(Diagram *diagram)
|
||||
void QETDiagramEditor::removeDiagramSilent(Diagram *diagram)
|
||||
{
|
||||
if (!diagram) return;
|
||||
|
||||
// recupere le projet contenant le schema
|
||||
if (QETProject *diagram_project = diagram -> project()) {
|
||||
// recupere la vue sur ce projet
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
|
||||
// affiche le schema en question
|
||||
project_view -> showDiagram(diagram);
|
||||
|
||||
// supprime le schema
|
||||
project_view -> removeDiagram(diagram);
|
||||
project_view -> removeDiagram(diagram, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
void QETDiagramEditor::moveDiagramUp(const QList<Diagram *> &diagrams) {
|
||||
if (diagrams.isEmpty()) return;
|
||||
QList<Diagram *> safeDiagrams = diagrams;
|
||||
if (QETProject *diagram_project = safeDiagrams.first()->project()) {
|
||||
if (!diagram_project->isReadOnly()) {
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
// Forward loop for moving up
|
||||
for (int i = 0; i < safeDiagrams.size(); ++i) {
|
||||
project_view->moveDiagramUp(safeDiagrams.at(i));
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Change l'ordre des schemas d'un projet, en decalant le schema vers le haut /
|
||||
la gauche
|
||||
@param diagram Schema a decaler vers le haut / la gauche
|
||||
*/
|
||||
void QETDiagramEditor::moveDiagramUp(Diagram *diagram)
|
||||
{
|
||||
if (!diagram) return;
|
||||
|
||||
// recupere le projet contenant le schema
|
||||
if (QETProject *diagram_project = diagram -> project()) {
|
||||
if (diagram_project -> isReadOnly()) return;
|
||||
|
||||
// recupere la vue sur ce projet
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
project_view -> moveDiagramUp(diagram);
|
||||
void QETDiagramEditor::moveDiagramDown(const QList<Diagram *> &diagrams) {
|
||||
if (diagrams.isEmpty()) return;
|
||||
QList<Diagram *> safeDiagrams = diagrams;
|
||||
if (QETProject *diagram_project = safeDiagrams.first()->project()) {
|
||||
if (!diagram_project->isReadOnly()) {
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
// Backward loop for moving down
|
||||
for (int i = safeDiagrams.size() - 1; i >= 0; --i) {
|
||||
project_view->moveDiagramDown(safeDiagrams.at(i));
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Change l'ordre des schemas d'un projet, en decalant le schema vers le bas /
|
||||
la droite
|
||||
@param diagram Schema a decaler vers le bas / la droite
|
||||
*/
|
||||
void QETDiagramEditor::moveDiagramDown(Diagram *diagram)
|
||||
{
|
||||
if (!diagram) return;
|
||||
|
||||
// recupere le projet contenant le schema
|
||||
if (QETProject *diagram_project = diagram -> project()) {
|
||||
if (diagram_project -> isReadOnly()) return;
|
||||
|
||||
// recupere la vue sur ce projet
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
project_view -> moveDiagramDown(diagram);
|
||||
void QETDiagramEditor::moveDiagramUpTop(const QList<Diagram *> &diagrams) {
|
||||
if (diagrams.isEmpty()) return;
|
||||
QList<Diagram *> safeDiagrams = diagrams;
|
||||
if (QETProject *diagram_project = safeDiagrams.first()->project()) {
|
||||
if (!diagram_project->isReadOnly()) {
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
// Backward loop to preserve relative order of the selected items when moving to top
|
||||
for (int i = safeDiagrams.size() - 1; i >= 0; --i) {
|
||||
project_view->moveDiagramUpTop(safeDiagrams.at(i));
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Change l'ordre des schemas d'un projet, en decalant le schema vers le haut /
|
||||
la gauche en position 0
|
||||
@param diagram Schema a decaler vers le haut / la gauche en position 0
|
||||
*/
|
||||
void QETDiagramEditor::moveDiagramUpTop(Diagram *diagram)
|
||||
{
|
||||
if (!diagram) return;
|
||||
|
||||
// recupere le projet contenant le schema
|
||||
if (QETProject *diagram_project = diagram -> project()) {
|
||||
if (diagram_project -> isReadOnly()) return;
|
||||
|
||||
// recupere la vue sur ce projet
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
project_view -> moveDiagramUpTop(diagram);
|
||||
void QETDiagramEditor::moveDiagramUpx10(const QList<Diagram *> &diagrams) {
|
||||
if (diagrams.isEmpty()) return;
|
||||
QList<Diagram *> safeDiagrams = diagrams;
|
||||
if (QETProject *diagram_project = safeDiagrams.first()->project()) {
|
||||
if (!diagram_project->isReadOnly()) {
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
// Forward loop for moving up
|
||||
for (int i = 0; i < safeDiagrams.size(); ++i) {
|
||||
project_view->moveDiagramUpx10(safeDiagrams.at(i));
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Change l'ordre des schemas d'un projet, en decalant le schema vers le haut /
|
||||
la gauche x10
|
||||
@param diagram Schema a decaler vers le haut / la gauche x10
|
||||
*/
|
||||
void QETDiagramEditor::moveDiagramUpx10(Diagram *diagram)
|
||||
{
|
||||
if (!diagram) return;
|
||||
|
||||
// recupere le projet contenant le schema
|
||||
if (QETProject *diagram_project = diagram -> project()) {
|
||||
if (diagram_project -> isReadOnly()) return;
|
||||
|
||||
// recupere la vue sur ce projet
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
project_view -> moveDiagramUpx10(diagram);
|
||||
void QETDiagramEditor::moveDiagramDownx10(const QList<Diagram *> &diagrams) {
|
||||
if (diagrams.isEmpty()) return;
|
||||
QList<Diagram *> safeDiagrams = diagrams;
|
||||
if (QETProject *diagram_project = safeDiagrams.first()->project()) {
|
||||
if (!diagram_project->isReadOnly()) {
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
// Backward loop for moving down
|
||||
for (int i = safeDiagrams.size() - 1; i >= 0; --i) {
|
||||
project_view->moveDiagramDownx10(safeDiagrams.at(i));
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Change l'ordre des schemas d'un projet, en decalant le schema vers le bas /
|
||||
la droite x10
|
||||
@param diagram Schema a decaler vers le bas / la droite x10
|
||||
*/
|
||||
void QETDiagramEditor::moveDiagramDownx10(Diagram *diagram)
|
||||
{
|
||||
if (!diagram) return;
|
||||
void QETDiagramEditor::moveDiagramUpx100(const QList<Diagram *> &diagrams) {
|
||||
if (diagrams.isEmpty()) return;
|
||||
QList<Diagram *> safeDiagrams = diagrams;
|
||||
if (QETProject *diagram_project = safeDiagrams.first()->project()) {
|
||||
if (!diagram_project->isReadOnly()) {
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
// Forward loop for moving up
|
||||
for (int i = 0; i < safeDiagrams.size(); ++i) {
|
||||
project_view->moveDiagramUpx100(safeDiagrams.at(i));
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recupere le projet contenant le schema
|
||||
if (QETProject *diagram_project = diagram -> project()) {
|
||||
if (diagram_project -> isReadOnly()) return;
|
||||
|
||||
// recupere la vue sur ce projet
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
project_view -> moveDiagramDownx10(diagram);
|
||||
void QETDiagramEditor::moveDiagramDownx100(const QList<Diagram *> &diagrams) {
|
||||
if (diagrams.isEmpty()) return;
|
||||
QList<Diagram *> safeDiagrams = diagrams;
|
||||
if (QETProject *diagram_project = safeDiagrams.first()->project()) {
|
||||
if (!diagram_project->isReadOnly()) {
|
||||
if (ProjectView *project_view = findProject(diagram_project)) {
|
||||
// Backward loop for moving down
|
||||
for (int i = safeDiagrams.size() - 1; i >= 0; --i) {
|
||||
project_view->moveDiagramDownx100(safeDiagrams.at(i));
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,12 +138,15 @@ class QETDiagramEditor : public QETMainWindow
|
||||
void editDiagramProperties(Diagram *);
|
||||
void addDiagramToProject(QETProject *);
|
||||
void removeDiagram(Diagram *);
|
||||
void removeDiagrams(const QList<Diagram *> &diagrams);
|
||||
void removeDiagramFromProject();
|
||||
void moveDiagramUp(Diagram *);
|
||||
void moveDiagramDown(Diagram *);
|
||||
void moveDiagramUpTop(Diagram *);
|
||||
void moveDiagramUpx10(Diagram *);
|
||||
void moveDiagramDownx10(Diagram *);
|
||||
void moveDiagramUp(const QList<Diagram *> &diagrams);
|
||||
void moveDiagramDown(const QList<Diagram *> &diagrams);
|
||||
void moveDiagramUpTop(const QList<Diagram *> &diagrams);
|
||||
void moveDiagramUpx10(const QList<Diagram *> &diagrams);
|
||||
void moveDiagramDownx10(const QList<Diagram *> &diagrams);
|
||||
void moveDiagramUpx100(const QList<Diagram *> &diagrams);
|
||||
void moveDiagramDownx100(const QList<Diagram *> &diagrams);
|
||||
void reloadOldElementPanel();
|
||||
void diagramWasAdded(DiagramView *);
|
||||
void findElementInPanel(const ElementsLocation &);
|
||||
@@ -222,6 +225,8 @@ class QETDiagramEditor : public QETMainWindow
|
||||
|
||||
QList <QAction *> m_zoom_action_toolBar; ///Only zoom action must displayed in the toolbar
|
||||
|
||||
void removeDiagramSilent(Diagram *diagram);
|
||||
|
||||
QMdiArea m_workspace;
|
||||
QSignalMapper windowMapper;
|
||||
QDir open_dialog_dir; /// Directory to use for file dialogs such as File > save
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
#include "crossrefitem.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include "../autoNum/assignvariables.h"
|
||||
#include "../diagram.h"
|
||||
#include "../diagramposition.h"
|
||||
@@ -25,6 +27,7 @@
|
||||
#include "element.h"
|
||||
#include "elementtextitemgroup.h"
|
||||
#include "qgraphicsitemutility.h"
|
||||
#include "terminal.h"
|
||||
|
||||
//define the height of the header.
|
||||
static int header = 5;
|
||||
@@ -221,9 +224,12 @@ void CrossRefItem::updateLabel()
|
||||
prepareGeometryChange();
|
||||
m_bounding_rect = QRectF();
|
||||
|
||||
//init the painter
|
||||
QPainter qp;
|
||||
qp.begin(&m_drawing);
|
||||
// Build geometry and m_hovered_contacts_map using a QImage-backed
|
||||
// painter so font metrics match the screen painter in paint().
|
||||
// m_update_map=true allows the draw functions to populate the map;
|
||||
// paint() calls them with m_update_map=false so the map is stable.
|
||||
QImage dummy(1, 1, QImage::Format_ARGB32_Premultiplied);
|
||||
QPainter qp(&dummy);
|
||||
QPen pen_;
|
||||
pen_.setWidthF(0.5);
|
||||
qp.setPen(pen_);
|
||||
@@ -232,17 +238,21 @@ void CrossRefItem::updateLabel()
|
||||
//Draw cross or contact, only if master element is linked.
|
||||
if (! m_element->linkedElements().isEmpty())
|
||||
{
|
||||
m_update_map = true;
|
||||
XRefProperties::DisplayHas dh = m_properties.displayHas();
|
||||
|
||||
if (dh == XRefProperties::Cross)
|
||||
drawAsCross(qp);
|
||||
else if (dh == XRefProperties::Contacts)
|
||||
drawAsContacts(qp);
|
||||
m_update_map = false;
|
||||
}
|
||||
qp.end();
|
||||
|
||||
autoPos();
|
||||
update();
|
||||
// Schedule a second update after the scene has finished laying out,
|
||||
// so the initial render uses the correct bounding rect.
|
||||
QTimer::singleShot(0, this, [this]{ update(); });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,7 +320,26 @@ void CrossRefItem::paint(
|
||||
{
|
||||
Q_UNUSED(option)
|
||||
Q_UNUSED(widget)
|
||||
m_drawing.play(painter);
|
||||
// Draw directly — no QPicture involved anywhere.
|
||||
// QPicture::play() + nested drawPicture() (m_hdr_no_ctc/m_hdr_nc_ctc)
|
||||
// caused a use-after-free crash (QRegion::begin, Qt5Gui+0x49af60)
|
||||
// confirmed by analysis of 19+ coredumps.
|
||||
// m_update_map=false: draw functions do not overwrite m_hovered_contacts_map.
|
||||
if (m_element->linkedElements().isEmpty()) return;
|
||||
|
||||
QPen pen_;
|
||||
pen_.setWidthF(0.5);
|
||||
painter->save();
|
||||
painter->setPen(pen_);
|
||||
painter->setFont(QETApp::diagramTextsFont(5));
|
||||
|
||||
m_update_map = false;
|
||||
XRefProperties::DisplayHas dh = m_properties.displayHas();
|
||||
if (dh == XRefProperties::Cross)
|
||||
drawAsCross(*painter);
|
||||
else if (dh == XRefProperties::Contacts)
|
||||
drawAsContacts(*painter);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,7 +349,24 @@ void CrossRefItem::paint(
|
||||
void CrossRefItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
event->accept();
|
||||
QetGraphicsItem::showItem(m_hovered_contact);
|
||||
|
||||
// Find the element under the click position directly from the map,
|
||||
// rather than relying on m_hovered_contact which may have been reset
|
||||
// by hoverMoveEvent between the two clicks of the double-click.
|
||||
QPointF pos = event->pos();
|
||||
Element *target = m_hovered_contact;
|
||||
|
||||
if (!target) {
|
||||
for (auto it = m_hovered_contacts_map.begin();
|
||||
it != m_hovered_contacts_map.end(); ++it) {
|
||||
if (it.value().contains(pos)) {
|
||||
target = it.key();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QetGraphicsItem::showItem(target);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -432,49 +478,41 @@ void CrossRefItem::linkedChanged()
|
||||
|
||||
/**
|
||||
@brief CrossRefItem::buildHeaderContact
|
||||
Draw the QPicture of m_hdr_no_ctc and m_hdr_nc_ctc
|
||||
Draw NO and NC contact symbols directly onto painter.
|
||||
Previously used QPicture (m_hdr_no_ctc/m_hdr_nc_ctc) which caused
|
||||
use-after-free crashes via nested QPicture::play() calls.
|
||||
*/
|
||||
void CrossRefItem::buildHeaderContact()
|
||||
void CrossRefItem::buildHeaderContact(QPainter &painter, QPointF no_pos, QPointF nc_pos)
|
||||
{
|
||||
if (!m_hdr_no_ctc.isNull() && !m_hdr_nc_ctc.isNull()) return;
|
||||
|
||||
//init the painter
|
||||
QPainter qp;
|
||||
QPen pen_;
|
||||
pen_.setWidthF(0.2);
|
||||
painter.save();
|
||||
painter.setPen(pen_);
|
||||
|
||||
//draw the NO contact
|
||||
if (m_hdr_no_ctc.isNull()) {
|
||||
qp.begin(&m_hdr_no_ctc);
|
||||
qp.setPen(pen_);
|
||||
qp.drawLine(0, 3, 5, 3);
|
||||
QPointF p1[3] = {
|
||||
QPointF(5, 0),
|
||||
QPointF(10, 3),
|
||||
QPointF(15, 3),
|
||||
};
|
||||
qp.drawPolyline(p1,3);
|
||||
qp.end();
|
||||
}
|
||||
//draw the NO contact header symbol
|
||||
painter.drawLine(no_pos.x()+0, no_pos.y()+3, no_pos.x()+5, no_pos.y()+3);
|
||||
QPointF p1[3] = {
|
||||
QPointF(no_pos.x()+5, no_pos.y()+0),
|
||||
QPointF(no_pos.x()+10, no_pos.y()+3),
|
||||
QPointF(no_pos.x()+15, no_pos.y()+3),
|
||||
};
|
||||
painter.drawPolyline(p1, 3);
|
||||
|
||||
//draw the NC contact
|
||||
if (m_hdr_nc_ctc.isNull()) {
|
||||
qp.begin(&m_hdr_nc_ctc);
|
||||
qp.setPen(pen_);
|
||||
QPointF p2[3] = {
|
||||
QPointF(0, 3),
|
||||
QPointF(5, 3),
|
||||
QPointF(5, 0)
|
||||
};
|
||||
qp.drawPolyline(p2,3);
|
||||
QPointF p3[3] = {
|
||||
QPointF(4, 0),
|
||||
QPointF(10, 3),
|
||||
QPointF(15, 3),
|
||||
};
|
||||
qp.drawPolyline(p3,3);
|
||||
qp.end();
|
||||
}
|
||||
//draw the NC contact header symbol
|
||||
QPointF p2[3] = {
|
||||
QPointF(nc_pos.x()+0, nc_pos.y()+3),
|
||||
QPointF(nc_pos.x()+5, nc_pos.y()+3),
|
||||
QPointF(nc_pos.x()+5, nc_pos.y()+0)
|
||||
};
|
||||
painter.drawPolyline(p2, 3);
|
||||
QPointF p3[3] = {
|
||||
QPointF(nc_pos.x()+4, nc_pos.y()+0),
|
||||
QPointF(nc_pos.x()+10, nc_pos.y()+3),
|
||||
QPointF(nc_pos.x()+15, nc_pos.y()+3),
|
||||
};
|
||||
painter.drawPolyline(p3, 3);
|
||||
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,11 +530,95 @@ void CrossRefItem::setUpCrossBoundingRect(QPainter &painter)
|
||||
|
||||
QStringList no_str, nc_str;
|
||||
|
||||
// Helper lambda: build "[13-14] pos" string for an element.
|
||||
// For power contacts (e.g. 3-pole contactor), all named terminals
|
||||
// are collected (e.g. "[1-2-3-4-5-6] pos").
|
||||
// For other contacts (NO/NC/SW), only the first 2 named terminals
|
||||
// are used — users are expected to name and order their terminals
|
||||
// in the element editor.
|
||||
// Helper lambda: build "[13-14] pos" for an element.
|
||||
// - Power: all terminals sorted numerically → "[1-2-3-4-5-6] pos"
|
||||
// - SW with typed terminals: show relevant pair per column (handled below)
|
||||
// - Others: first 2 named terminals
|
||||
auto buildLabel = [this](Element *elmt, bool is_no_col) -> QString {
|
||||
const bool is_power =
|
||||
elmt->kindInformations()["type"].toString() == "power";
|
||||
const bool is_sw =
|
||||
elmt->kindInformations()["state"].toString() == "SW";
|
||||
|
||||
QStringList tnames;
|
||||
|
||||
if (is_sw) {
|
||||
// Check if terminals have explicit No/Nc/Common types
|
||||
bool has_typed = false;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (t->terminalType() == TerminalData::No ||
|
||||
t->terminalType() == TerminalData::Nc ||
|
||||
t->terminalType() == TerminalData::Common) {
|
||||
has_typed = true; break;
|
||||
}
|
||||
}
|
||||
if (has_typed) {
|
||||
QString no_name, nc_name, common_name;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (!t->name().isEmpty()) {
|
||||
if (t->terminalType() == TerminalData::No) no_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Nc) nc_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Common) common_name = t->name();
|
||||
}
|
||||
}
|
||||
// NO column: show NO+Common pair; NC column: show NC+Common pair
|
||||
if (is_no_col)
|
||||
tnames << no_name << common_name;
|
||||
else
|
||||
tnames << nc_name << common_name;
|
||||
} else {
|
||||
// Fallback: first 2 named terminals
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) { tnames << tn; if (tnames.size() >= 2) break; }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) {
|
||||
tnames << tn;
|
||||
if (!is_power && tnames.size() >= 2) break;
|
||||
}
|
||||
}
|
||||
if (is_power) {
|
||||
std::sort(tnames.begin(), tnames.end(),
|
||||
[](const QString &a, const QString &b){
|
||||
int i_a = a.size();
|
||||
while (i_a > 0 && a[i_a-1].isDigit()) --i_a;
|
||||
int i_b = b.size();
|
||||
while (i_b > 0 && b[i_b-1].isDigit()) --i_b;
|
||||
bool a_ok = false, b_ok = false;
|
||||
int ai = a.mid(i_a).toInt(&a_ok);
|
||||
int bi = b.mid(i_b).toInt(&b_ok);
|
||||
if (a_ok && b_ok && a.left(i_a) == b.left(i_b))
|
||||
return ai < bi;
|
||||
return a < b;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QString pos = elementPositionText(elmt, true);
|
||||
if (!tnames.isEmpty() && m_properties.showTerminalName())
|
||||
return QStringLiteral("[") + tnames.join("-") + QStringLiteral("] ") + pos;
|
||||
return pos;
|
||||
};
|
||||
|
||||
for (auto elmt : NOElements()) {
|
||||
no_str.append(elementPositionText(elmt, true));
|
||||
no_str.append(buildLabel(elmt, true));
|
||||
}
|
||||
for (auto elmt : NCElements()) {
|
||||
nc_str.append(elementPositionText(elmt, true));
|
||||
nc_str.append(buildLabel(elmt, false));
|
||||
}
|
||||
|
||||
//There is no string to display, we return now
|
||||
@@ -509,9 +631,10 @@ void CrossRefItem::setUpCrossBoundingRect(QPainter &painter)
|
||||
QRectF no_bounding;
|
||||
for (auto str : no_str)
|
||||
{
|
||||
QRectF bounding = painter.boundingRect(QRectF (), Qt::AlignCenter, str);
|
||||
no_bounding = no_bounding.united(bounding);
|
||||
QRectF bounding = painter.boundingRect(QRectF(0, 0, 500, 20), Qt::AlignLeft, str);
|
||||
no_bounding.setHeight(no_bounding.height() + bounding.height());
|
||||
if (bounding.width() > no_bounding.width())
|
||||
no_bounding.setWidth(bounding.width());
|
||||
}
|
||||
//Adjust according to the NO
|
||||
if (no_bounding.height() > default_bounding.height() - header)
|
||||
@@ -523,9 +646,10 @@ void CrossRefItem::setUpCrossBoundingRect(QPainter &painter)
|
||||
QRectF nc_bounding;
|
||||
for (auto str : nc_str)
|
||||
{
|
||||
QRectF bounding = painter.boundingRect(QRectF (), Qt::AlignCenter, str);
|
||||
nc_bounding = nc_bounding.united(bounding);
|
||||
QRectF bounding = painter.boundingRect(QRectF(0, 0, 500, 20), Qt::AlignLeft, str);
|
||||
nc_bounding.setHeight(nc_bounding.height() + bounding.height());
|
||||
if (bounding.width() > nc_bounding.width())
|
||||
nc_bounding.setWidth(bounding.width());
|
||||
}
|
||||
//Adjust according to the NC
|
||||
if (nc_bounding.height() > default_bounding.height() - header)
|
||||
@@ -549,7 +673,8 @@ void CrossRefItem::drawAsCross(QPainter &painter)
|
||||
{
|
||||
//calculate the size of the cross
|
||||
setUpCrossBoundingRect(painter);
|
||||
m_hovered_contacts_map.clear();
|
||||
m_drawed_contacts = 0;
|
||||
if (m_update_map) m_hovered_contacts_map.clear();
|
||||
|
||||
//Bounding rect is empty that mean there's no contact to draw
|
||||
if (boundingRect().isEmpty()) return;
|
||||
@@ -559,12 +684,11 @@ void CrossRefItem::drawAsCross(QPainter &painter)
|
||||
painter.drawLine(br.width()/2, 0, br.width()/2, br.height()); //vertical line
|
||||
painter.drawLine(0, header, br.width(), header); //horizontal line
|
||||
|
||||
//Add the symbolic contacts
|
||||
buildHeaderContact();
|
||||
QPointF p((m_bounding_rect.width()/4) - (m_hdr_no_ctc.width()/2), 0);
|
||||
painter.drawPicture (p, m_hdr_no_ctc);
|
||||
p.setX((m_bounding_rect.width() * 3/4) - (m_hdr_nc_ctc.width()/2));
|
||||
painter.drawPicture (p, m_hdr_nc_ctc);
|
||||
//Add the symbolic contacts (drawn directly, no QPicture)
|
||||
static const qreal hdr_symbol_width = 15.0;
|
||||
QPointF no_pos((m_bounding_rect.width()/4) - (hdr_symbol_width/2), 0);
|
||||
QPointF nc_pos((m_bounding_rect.width() * 3/4) - (hdr_symbol_width/2), 0);
|
||||
buildHeaderContact(painter, no_pos, nc_pos);
|
||||
|
||||
//and fill it
|
||||
fillCrossRef(painter);
|
||||
@@ -581,7 +705,7 @@ void CrossRefItem::drawAsContacts(QPainter &painter)
|
||||
return;
|
||||
|
||||
m_drawed_contacts = 0;
|
||||
m_hovered_contacts_map.clear();
|
||||
if (m_update_map) m_hovered_contacts_map.clear();
|
||||
QRectF bounding_rect;
|
||||
|
||||
//Draw each linked contact
|
||||
@@ -605,7 +729,7 @@ void CrossRefItem::drawAsContacts(QPainter &painter)
|
||||
else if (type == "delayOff") option += DelayOff;
|
||||
else if (type == "delayOnOff") option += DelayOnOff;
|
||||
|
||||
QRectF br = drawContact(painter, option, elmt);
|
||||
QRectF br = drawContact(painter, option, elmt, i);
|
||||
bounding_rect = bounding_rect.united(br);
|
||||
}
|
||||
}
|
||||
@@ -624,9 +748,81 @@ void CrossRefItem::drawAsContacts(QPainter &painter)
|
||||
@param elmt : the element to display text (the position of the contact)
|
||||
@return The bounding rect of the draw (contact + text)
|
||||
*/
|
||||
QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
|
||||
QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, int pole_index)
|
||||
{
|
||||
QString str = elementPositionText(elmt);
|
||||
|
||||
// Collect terminal names from the element definition (.elmt)
|
||||
// e.g. name="13" and name="14" on each terminal
|
||||
// For power contacts, sort numerically and pick the pair for pole_index.
|
||||
// For SW contacts with typed terminals (No/Nc/Common), filter by role.
|
||||
QStringList terminal_names;
|
||||
const bool is_power_ctc =
|
||||
elmt->kindInformations()["type"].toString() == "power";
|
||||
const bool is_sw = (flags & SW) && !(flags & NOC);
|
||||
|
||||
// Check if SW terminals have explicit No/Nc/Common types
|
||||
bool sw_has_typed_terminals = false;
|
||||
if (is_sw) {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (t->terminalType() == TerminalData::No ||
|
||||
t->terminalType() == TerminalData::Nc ||
|
||||
t->terminalType() == TerminalData::Common) {
|
||||
sw_has_typed_terminals = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tname = t->name();
|
||||
if (!tname.isEmpty())
|
||||
terminal_names << tname;
|
||||
}
|
||||
|
||||
if (is_power_ctc) {
|
||||
// Sort terminals alphanumerically so names like "R1","R2"... or "1","2"...
|
||||
// are ordered correctly. Extract trailing digits for numeric comparison;
|
||||
// fall back to full string comparison when no digits are found.
|
||||
std::sort(terminal_names.begin(), terminal_names.end(),
|
||||
[](const QString &a, const QString &b){
|
||||
// Extract trailing numeric part
|
||||
int i_a = a.size();
|
||||
while (i_a > 0 && a[i_a-1].isDigit()) --i_a;
|
||||
int i_b = b.size();
|
||||
while (i_b > 0 && b[i_b-1].isDigit()) --i_b;
|
||||
bool a_ok = false, b_ok = false;
|
||||
int ai = a.mid(i_a).toInt(&a_ok);
|
||||
int bi = b.mid(i_b).toInt(&b_ok);
|
||||
if (a_ok && b_ok && a.left(i_a) == b.left(i_b))
|
||||
return ai < bi;
|
||||
return a < b;
|
||||
});
|
||||
// Pick the pair for this pole: pole 0 → [0,1], pole 1 → [2,3], etc.
|
||||
int idx = pole_index * 2;
|
||||
if (idx + 1 < terminal_names.size())
|
||||
terminal_names = QStringList() << terminal_names[idx] << terminal_names[idx+1];
|
||||
else
|
||||
terminal_names.clear();
|
||||
} else if (is_sw && sw_has_typed_terminals) {
|
||||
// Build [NO_name, Common_name, NC_name] from typed terminals
|
||||
QString no_name, nc_name, common_name;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (!t->name().isEmpty()) {
|
||||
if (t->terminalType() == TerminalData::No) no_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Nc) nc_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Common) common_name = t->name();
|
||||
}
|
||||
}
|
||||
// drawText expects: [0]=NC, [1]=NO, [2]=Common
|
||||
// (drawText uses [1] for NO top-left, [0] for NC bottom-left, [2] for Common right)
|
||||
terminal_names.clear();
|
||||
terminal_names << nc_name << no_name << common_name;
|
||||
}
|
||||
|
||||
int offset = m_drawed_contacts*10;
|
||||
QRectF bounding_rect = QRectF(0, offset, 24, 10);
|
||||
|
||||
@@ -643,15 +839,17 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
|
||||
painter.drawLine(0, offset+6, 8, offset+6);
|
||||
painter.drawLine(16, offset+6, 24, offset+6);
|
||||
|
||||
///take example of this code for display the terminal text
|
||||
/*QFont font = QETApp::diagramTextsFont(4);
|
||||
font.setBold(true);
|
||||
painter.setFont(font);
|
||||
QRectF bt(0, offset, 24, 10);
|
||||
int txt = 10 + m_drawed_contacts;
|
||||
painter.drawText(bt, Qt::AlignLeft|Qt::AlignTop, QString::number(txt));
|
||||
painter.drawText(bt, Qt::AlignRight|Qt::AlignTop, QString::number(txt));
|
||||
painter.setFont(QETApp::diagramTextsFont(5));*/
|
||||
// Draw terminal names on each side of the contact symbol
|
||||
// terminal_names[0] on the left, terminal_names[1] on the right
|
||||
if (!terminal_names.isEmpty() && m_properties.showTerminalName()) {
|
||||
painter.setFont(QETApp::diagramTextsFont(4));
|
||||
QRectF bt(0, offset, 24, 10);
|
||||
if (terminal_names.size() >= 1)
|
||||
painter.drawText(bt, Qt::AlignLeft|Qt::AlignTop, terminal_names[0]);
|
||||
if (terminal_names.size() >= 2)
|
||||
painter.drawText(bt, Qt::AlignRight|Qt::AlignTop, terminal_names[1]);
|
||||
painter.setFont(QETApp::diagramTextsFont(5));
|
||||
}
|
||||
|
||||
//draw open contact
|
||||
if (flags &NO) {
|
||||
@@ -729,14 +927,8 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
|
||||
painter.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, str);
|
||||
bounding_rect = bounding_rect.united(text_rect);
|
||||
|
||||
if (m_hovered_contacts_map.contains(elmt))
|
||||
{
|
||||
if (m_update_map)
|
||||
m_hovered_contacts_map.insert(elmt, bounding_rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hovered_contacts_map.insert(elmt, bounding_rect);
|
||||
}
|
||||
|
||||
++m_drawed_contacts;
|
||||
}
|
||||
@@ -768,6 +960,26 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
|
||||
};
|
||||
painter.drawPolyline(p2, 3);
|
||||
|
||||
// Draw terminal names for switch contact (3 terminals)
|
||||
// terminal_names[0] = NO side (top left)
|
||||
// terminal_names[1] = NC side (bottom left)
|
||||
// terminal_names[2] = common side (right)
|
||||
if (!terminal_names.isEmpty() && m_properties.showTerminalName()) {
|
||||
painter.setFont(QETApp::diagramTextsFont(4));
|
||||
// Sort order from parseTerminal (top->bottom, left->right):
|
||||
// [0]=12 (NO, top-left), [1]=14 (common, top-center), [2]=13 (NC, bottom-center)
|
||||
if (terminal_names.size() >= 1)
|
||||
painter.drawText(QRectF(0, offset, 8, 8),
|
||||
Qt::AlignLeft|Qt::AlignTop, terminal_names[1]); // 12 NO left
|
||||
if (terminal_names.size() >= 2)
|
||||
painter.drawText(QRectF(16, offset+4, 8, 6),
|
||||
Qt::AlignRight|Qt::AlignTop, terminal_names[2]); // 14 common right
|
||||
if (terminal_names.size() >= 3)
|
||||
painter.drawText(QRectF(0, offset+9, 8, 6),
|
||||
Qt::AlignLeft|Qt::AlignTop, terminal_names[0]); // 13 NC left-bottom
|
||||
painter.setFont(QETApp::diagramTextsFont(5));
|
||||
}
|
||||
|
||||
//Draw the half ellipse off delay
|
||||
if (flags &Delay)
|
||||
{
|
||||
@@ -799,12 +1011,8 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
|
||||
str);
|
||||
bounding_rect = bounding_rect.united(text_rect);
|
||||
|
||||
if (m_hovered_contacts_map.contains(elmt)) {
|
||||
if (m_update_map)
|
||||
m_hovered_contacts_map.insert(elmt, bounding_rect);
|
||||
}
|
||||
else {
|
||||
m_hovered_contacts_map.insert(elmt, bounding_rect);
|
||||
}
|
||||
|
||||
//a switch contact take place of two normal contact
|
||||
m_drawed_contacts += 2;
|
||||
@@ -835,12 +1043,8 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
|
||||
str);
|
||||
bounding_rect = bounding_rect.united(text_rect);
|
||||
|
||||
if (m_hovered_contacts_map.contains(elmt)) {
|
||||
if (m_update_map)
|
||||
m_hovered_contacts_map.insert(elmt, bounding_rect);
|
||||
}
|
||||
else {
|
||||
m_hovered_contacts_map.insert(elmt, bounding_rect);
|
||||
}
|
||||
++m_drawed_contacts;
|
||||
}
|
||||
return bounding_rect;
|
||||
@@ -866,7 +1070,60 @@ void CrossRefItem::fillCrossRef(QPainter &painter)
|
||||
m_hovered_contact == elmt ? pen.setColor(Qt::blue) :pen.setColor(Qt::black);
|
||||
painter.setPen(pen);
|
||||
|
||||
// Collect terminal names for NO column.
|
||||
// Power: all terminals sorted numerically.
|
||||
// SW with typed terminals: NO+Common pair.
|
||||
// Others: first 2 named terminals.
|
||||
const bool is_power_no =
|
||||
elmt->kindInformations()["type"].toString() == "power";
|
||||
const bool is_sw_no =
|
||||
elmt->kindInformations()["state"].toString() == "SW";
|
||||
QStringList tnames;
|
||||
if (is_sw_no) {
|
||||
bool has_typed = false;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (t->terminalType() == TerminalData::No ||
|
||||
t->terminalType() == TerminalData::Nc ||
|
||||
t->terminalType() == TerminalData::Common) {
|
||||
has_typed = true; break;
|
||||
}
|
||||
}
|
||||
if (has_typed) {
|
||||
QString no_name, common_name;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (!t->name().isEmpty()) {
|
||||
if (t->terminalType() == TerminalData::No) no_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Common) common_name = t->name();
|
||||
}
|
||||
}
|
||||
tnames << no_name << common_name;
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) { tnames << tn; if (tnames.size() >= 2) break; }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) {
|
||||
tnames << tn;
|
||||
if (!is_power_no && tnames.size() >= 2) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
QString terminal_label;
|
||||
if (!tnames.isEmpty() && m_properties.showTerminalName())
|
||||
terminal_label = QStringLiteral("[") + tnames.join("-") + QStringLiteral("]");
|
||||
|
||||
QString str = elementPositionText(elmt, true);
|
||||
if (!terminal_label.isEmpty())
|
||||
str = terminal_label + QStringLiteral(" ") + str;
|
||||
|
||||
QRectF bounding = painter.boundingRect(
|
||||
QRectF(no_top_left,
|
||||
QSize(middle_cross, 1)),
|
||||
@@ -874,13 +1131,11 @@ void CrossRefItem::fillCrossRef(QPainter &painter)
|
||||
str);
|
||||
painter.drawText(bounding, Qt::AlignLeft, str);
|
||||
|
||||
if (m_hovered_contacts_map.contains(elmt))
|
||||
{
|
||||
m_hovered_contacts_map.insert(elmt, bounding);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hovered_contacts_map.insert(elmt, bounding);
|
||||
if (m_update_map) {
|
||||
QString pos_str = elementPositionText(elmt, true);
|
||||
QRectF pos_rect = painter.boundingRect(bounding, Qt::AlignRight, pos_str);
|
||||
pos_rect.adjust(-2, -1, 2, 1); // extend hit area slightly
|
||||
m_hovered_contacts_map.insert(elmt, pos_rect);
|
||||
}
|
||||
|
||||
no_top_left.ry() += bounding.height();
|
||||
@@ -895,7 +1150,60 @@ void CrossRefItem::fillCrossRef(QPainter &painter)
|
||||
:pen.setColor(Qt::black);
|
||||
painter.setPen(pen);
|
||||
|
||||
// Collect terminal names for NC column.
|
||||
// Power: all terminals sorted numerically.
|
||||
// SW with typed terminals: NC+Common pair.
|
||||
// Others: first 2 named terminals.
|
||||
const bool is_power_nc =
|
||||
elmt->kindInformations()["type"].toString() == "power";
|
||||
const bool is_sw_nc =
|
||||
elmt->kindInformations()["state"].toString() == "SW";
|
||||
QStringList tnames_nc;
|
||||
if (is_sw_nc) {
|
||||
bool has_typed = false;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (t->terminalType() == TerminalData::No ||
|
||||
t->terminalType() == TerminalData::Nc ||
|
||||
t->terminalType() == TerminalData::Common) {
|
||||
has_typed = true; break;
|
||||
}
|
||||
}
|
||||
if (has_typed) {
|
||||
QString nc_name, common_name;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (!t->name().isEmpty()) {
|
||||
if (t->terminalType() == TerminalData::Nc) nc_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Common) common_name = t->name();
|
||||
}
|
||||
}
|
||||
tnames_nc << nc_name << common_name;
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) { tnames_nc << tn; if (tnames_nc.size() >= 2) break; }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) {
|
||||
tnames_nc << tn;
|
||||
if (!is_power_nc && tnames_nc.size() >= 2) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
QString terminal_label;
|
||||
if (!tnames_nc.isEmpty() && m_properties.showTerminalName())
|
||||
terminal_label = QStringLiteral("[") + tnames_nc.join("-") + QStringLiteral("]");
|
||||
|
||||
QString str = elementPositionText(elmt, true);
|
||||
if (!terminal_label.isEmpty())
|
||||
str = terminal_label + QStringLiteral(" ") + str;
|
||||
|
||||
QRectF bounding = painter.boundingRect(
|
||||
QRectF(nc_top_left,
|
||||
QSize(middle_cross, 1)),
|
||||
@@ -903,13 +1211,11 @@ void CrossRefItem::fillCrossRef(QPainter &painter)
|
||||
str);
|
||||
painter.drawText(bounding, Qt::AlignRight, str);
|
||||
|
||||
if (m_hovered_contacts_map.contains(elmt))
|
||||
{
|
||||
m_hovered_contacts_map.insert(elmt, bounding);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hovered_contacts_map.insert(elmt, bounding);
|
||||
if (m_update_map) {
|
||||
QString pos_str = elementPositionText(elmt, true);
|
||||
QRectF pos_rect = painter.boundingRect(bounding, Qt::AlignRight, pos_str);
|
||||
pos_rect.adjust(-2, -1, 2, 1); // extend hit area slightly
|
||||
m_hovered_contacts_map.insert(elmt, pos_rect);
|
||||
}
|
||||
|
||||
nc_top_left.ry() += bounding.height();
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <QGraphicsObject>
|
||||
#include <QMultiMap>
|
||||
#include <QPicture>
|
||||
|
||||
class Element;
|
||||
class DynamicElementTextItem;
|
||||
@@ -103,11 +102,11 @@ class CrossRefItem : public QGraphicsObject
|
||||
|
||||
private:
|
||||
void linkedChanged();
|
||||
void buildHeaderContact();
|
||||
void buildHeaderContact(QPainter &painter, QPointF no_pos, QPointF nc_pos);
|
||||
void setUpCrossBoundingRect(QPainter &painter);
|
||||
void drawAsCross(QPainter &painter);
|
||||
void drawAsContacts(QPainter &painter);
|
||||
QRectF drawContact(QPainter &painter, int flags, Element *elmt);
|
||||
QRectF drawContact(QPainter &painter, int flags, Element *elmt, int pole_index = 0);
|
||||
void fillCrossRef(QPainter &painter);
|
||||
void AddExtraInfo(QPainter &painter, const QString&);
|
||||
QList<Element *> NOElements() const;
|
||||
@@ -117,10 +116,10 @@ class CrossRefItem : public QGraphicsObject
|
||||
private:
|
||||
Element *m_element; //element to display the cross reference
|
||||
QRectF m_bounding_rect;
|
||||
QPicture m_drawing, m_hdr_no_ctc, m_hdr_nc_ctc;
|
||||
QPainterPath m_shape_path;
|
||||
XRefProperties m_properties;
|
||||
int m_drawed_contacts;
|
||||
bool m_update_map = false;
|
||||
QMultiMap <Element *, QRectF> m_hovered_contacts_map;
|
||||
Element *m_hovered_contact = nullptr;
|
||||
DynamicElementTextItem *m_text = nullptr;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "crossrefitem.h"
|
||||
#include "element.h"
|
||||
#include "elementtextitemgroup.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
@@ -302,7 +302,8 @@ void DynamicElementTextItem::refreshLabelConnection()
|
||||
if ((m_text_from == ElementInfo && m_info_name == "label") ||
|
||||
(m_text_from == CompositeText && m_composite_text.contains("%{label}")))
|
||||
{
|
||||
if(m_parent_element.data()->linkType() & Element::AllReport)
|
||||
if((m_parent_element.data()->linkType() & Element::AllReport) ||
|
||||
m_parent_element.data()->linkType() == Element::ConductorDefinition)
|
||||
{
|
||||
updateReportFormulaConnection();
|
||||
updateReportText();
|
||||
@@ -418,7 +419,8 @@ void DynamicElementTextItem::setInfoName(const QString &info_name)
|
||||
updateXref();
|
||||
}
|
||||
|
||||
if (m_parent_element && (m_parent_element.data()->linkType() & Element::AllReport)) //special treatment for report
|
||||
if (m_parent_element && ((m_parent_element.data()->linkType() & Element::AllReport) ||
|
||||
m_parent_element.data()->linkType() == Element::ConductorDefinition)) //special treatment for report
|
||||
{
|
||||
if(old_info_name != info_name)
|
||||
{
|
||||
@@ -472,7 +474,8 @@ void DynamicElementTextItem::setCompositeText(const QString &text)
|
||||
updateXref();
|
||||
}
|
||||
|
||||
if (m_parent_element && (m_parent_element.data()->linkType() & Element::AllReport)) //special treatment for report
|
||||
if (m_parent_element && ((m_parent_element.data()->linkType() & Element::AllReport) ||
|
||||
m_parent_element.data()->linkType() == Element::ConductorDefinition)) //special treatment for report
|
||||
{
|
||||
/*
|
||||
* May be in some case the old and new composite text both have the var %{label},
|
||||
@@ -726,28 +729,29 @@ QVariant DynamicElementTextItem::itemChange(QGraphicsItem::GraphicsItemChange ch
|
||||
if(!m_parent_element.data()->linkedElements().isEmpty())
|
||||
masterChanged();
|
||||
}
|
||||
else if(m_parent_element.data()->linkType() & Element::AllReport)
|
||||
else if((m_parent_element.data()->linkType() & Element::AllReport) ||
|
||||
m_parent_element.data()->linkType() == Element::ConductorDefinition)
|
||||
{
|
||||
//Get the report formula, and add connection to keep up to date the formula.
|
||||
//Get the report formula, and add connection to keep up to date the formula.
|
||||
if (m_parent_element.data()->diagram() && m_parent_element.data()->diagram()->project())
|
||||
{
|
||||
m_report_formula = m_parent_element.data()->diagram()->project()->defaultReportProperties();
|
||||
m_report_formula_con = connect(m_parent_element.data()->diagram()->project(), &QETProject::reportPropertiesChanged, this, &DynamicElementTextItem::reportFormulaChanged);
|
||||
}
|
||||
|
||||
//Add connection to keep up to date the status of the element linked to the parent folio report of this text.
|
||||
|
||||
//Add connection to keep up to date the status of the element linked to the parent folio report of this text.
|
||||
connect(m_parent_element.data(), &Element::linkedElementChanged, this, &DynamicElementTextItem::reportChanged);
|
||||
//The parent is already linked, we call reportChanged for init the connection
|
||||
//The parent is already linked, we call reportChanged for init the connection
|
||||
if(!m_parent_element.data()->linkedElements().isEmpty())
|
||||
reportChanged();
|
||||
|
||||
|
||||
if(m_parent_element.data()->terminals().size())
|
||||
{
|
||||
//Add connection to keep up date the conductors added or removed to the parent folio report element
|
||||
//Add connection to keep up date the conductors added or removed to the parent folio report element
|
||||
connect(m_parent_element.data()->terminals().first(), &Terminal::conductorWasAdded, this, &DynamicElementTextItem::conductorWasAdded);
|
||||
connect(m_parent_element.data()->terminals().first(), &Terminal::conductorWasRemoved, this, &DynamicElementTextItem::conductorWasRemoved);
|
||||
}
|
||||
//Get a conductor in the potential
|
||||
//Get a conductor in the potential
|
||||
setPotentialConductor();
|
||||
}
|
||||
else if(m_parent_element.data()->linkType() == Element::Master)
|
||||
@@ -1027,7 +1031,8 @@ void DynamicElementTextItem::clearFormulaConnection()
|
||||
|
||||
void DynamicElementTextItem::updateReportFormulaConnection()
|
||||
{
|
||||
if(!(m_parent_element.data()->linkType() & Element::AllReport))
|
||||
if(!(m_parent_element.data()->linkType() & Element::AllReport) &&
|
||||
m_parent_element.data()->linkType() != Element::ConductorDefinition)
|
||||
return;
|
||||
|
||||
removeConnectionForReportFormula(m_report_formula);
|
||||
@@ -1041,7 +1046,8 @@ void DynamicElementTextItem::updateReportFormulaConnection()
|
||||
*/
|
||||
void DynamicElementTextItem::updateReportText()
|
||||
{
|
||||
if(!(m_parent_element.data()->linkType() & Element::AllReport))
|
||||
if(!(m_parent_element.data()->linkType() & Element::AllReport) &&
|
||||
m_parent_element.data()->linkType() != Element::ConductorDefinition)
|
||||
return;
|
||||
|
||||
if (m_text_from == ElementInfo && m_info_name == "label")
|
||||
@@ -1098,7 +1104,10 @@ void DynamicElementTextItem::updateLabel()
|
||||
void DynamicElementTextItem::conductorWasAdded(Conductor *conductor)
|
||||
{
|
||||
Q_UNUSED(conductor)
|
||||
setPotentialConductor();
|
||||
QTimer::singleShot(100, this, [this]() {
|
||||
setPotentialConductor();
|
||||
conductorPropertiesChanged();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1123,7 +1132,8 @@ void DynamicElementTextItem::conductorWasRemoved(Conductor *conductor)
|
||||
*/
|
||||
void DynamicElementTextItem::setPotentialConductor()
|
||||
{
|
||||
if(parentElement() && (parentElement()->linkType() & Element::AllReport))
|
||||
if(parentElement() && ((parentElement()->linkType() & Element::AllReport) || (parentElement()->linkType() == Element::ConductorDefinition) ||
|
||||
parentElement()->linkType() == Element::ConductorDefinition))
|
||||
{
|
||||
if(parentElement()->terminals().isEmpty())
|
||||
return;
|
||||
@@ -1156,6 +1166,7 @@ void DynamicElementTextItem::setPotentialConductor()
|
||||
connect(m_watched_conductor.data(), &Conductor::propertiesChange, this, &DynamicElementTextItem::conductorPropertiesChanged);
|
||||
}
|
||||
}
|
||||
conductorPropertiesChanged();
|
||||
}
|
||||
else //This text haven't got a parent element, then ther isn't a conductor in the potential
|
||||
{
|
||||
@@ -1172,7 +1183,8 @@ void DynamicElementTextItem::setPotentialConductor()
|
||||
*/
|
||||
void DynamicElementTextItem::conductorPropertiesChanged()
|
||||
{
|
||||
if(m_parent_element && (m_parent_element.data()->linkType() & Element::AllReport))
|
||||
if(m_parent_element && ((m_parent_element.data()->linkType() & Element::AllReport) || (m_parent_element.data()->linkType() == Element::ConductorDefinition) ||
|
||||
m_parent_element.data()->linkType() == Element::ConductorDefinition))
|
||||
{
|
||||
if(m_text_from == ElementInfo)
|
||||
{
|
||||
@@ -1200,8 +1212,9 @@ void DynamicElementTextItem::conductorPropertiesChanged()
|
||||
QString DynamicElementTextItem::reportReplacedCompositeText() const
|
||||
{
|
||||
QString string;
|
||||
|
||||
if(m_parent_element.data()->linkType() & Element::AllReport)
|
||||
|
||||
if((m_parent_element.data()->linkType() & Element::AllReport) || (m_parent_element.data()->linkType() == Element::ConductorDefinition) ||
|
||||
m_parent_element.data()->linkType() == Element::ConductorDefinition)
|
||||
{
|
||||
string = m_composite_text;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "../qetxml.h"
|
||||
#include "../qetversion.h"
|
||||
#include "qgraphicsitemutility.h"
|
||||
#include <QDebug>
|
||||
|
||||
#include <QDomElement>
|
||||
#include <utility>
|
||||
@@ -431,6 +432,11 @@ bool Element::buildFromXml(const QDomElement &xml_def_elmt, int *state)
|
||||
m_data.fromXml(xml_def_elmt);
|
||||
setToolTip(name());
|
||||
|
||||
QString my_type_str = xml_def_elmt.attribute(QStringLiteral("link_type"), QStringLiteral("simple"));
|
||||
if (my_type_str == QLatin1String("conductor_definition")) {
|
||||
m_link_type = Element::ConductorDefinition;
|
||||
}
|
||||
|
||||
//load kind informations
|
||||
m_kind_informations.fromXml(
|
||||
xml_def_elmt.firstChildElement(QStringLiteral("kindInformations")),
|
||||
@@ -627,6 +633,9 @@ Terminal *Element::parseTerminal(const QDomElement &dom_element)
|
||||
Terminal *new_terminal = new Terminal(data, this);
|
||||
m_terminals << new_terminal;
|
||||
|
||||
connect(new_terminal, &Terminal::conductorWasAdded, this, &Element::updateConductorTexts);
|
||||
connect(new_terminal, &Terminal::conductorWasRemoved, this, &Element::updateConductorTexts);
|
||||
|
||||
//Sort from top to bottom and left to right
|
||||
std::sort(m_terminals.begin(),
|
||||
m_terminals.end(),
|
||||
@@ -1288,6 +1297,8 @@ QString Element::linkTypeToString() const
|
||||
return QStringLiteral("Terminale");
|
||||
case Thumbnail:
|
||||
return QStringLiteral("Thumbnail");
|
||||
case ConductorDefinition:
|
||||
return QStringLiteral("ConductorDefinition");
|
||||
default:
|
||||
return QStringLiteral("Unknown");
|
||||
}
|
||||
@@ -1555,3 +1566,25 @@ ElementsLocation Element::location() const
|
||||
{
|
||||
return m_location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Element::updateConductorTexts
|
||||
*Slot that is triggered when a cable is *
|
||||
*connected to or disconnected from a terminal on this component.
|
||||
*/
|
||||
/**
|
||||
* @brief Element::updateConductorTexts
|
||||
*/
|
||||
void Element::updateConductorTexts()
|
||||
{
|
||||
if (m_link_type != Element::ConductorDefinition) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (DynamicElementTextItem *deti : m_dynamic_text_list) {
|
||||
if (deti) {
|
||||
deti->setPotentialConductor();
|
||||
deti->updateLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +52,15 @@ class Element : public QetGraphicsItem
|
||||
(master, slave, report ect...)
|
||||
*/
|
||||
enum kind {
|
||||
Simple = 1,
|
||||
NextReport = 2,
|
||||
PreviousReport = 4,
|
||||
AllReport = 6,
|
||||
Master = 8,
|
||||
Slave = 16,
|
||||
Terminale = 32,
|
||||
Thumbnail = 64};
|
||||
Simple = 1,
|
||||
NextReport = 2,
|
||||
PreviousReport = 4,
|
||||
AllReport = 6,
|
||||
Master = 8,
|
||||
Slave = 16,
|
||||
Terminale = 32,
|
||||
Thumbnail = 64,
|
||||
ConductorDefinition = 128};
|
||||
|
||||
Element(const ElementsLocation &location,
|
||||
QGraphicsItem * = nullptr,
|
||||
@@ -95,6 +96,8 @@ class Element : public QetGraphicsItem
|
||||
DynamicElementTextItem *text,
|
||||
ElementTextItemGroup *group);
|
||||
|
||||
public slots:
|
||||
void updateConductorTexts();
|
||||
|
||||
public:
|
||||
QList<Terminal *> terminals() const;
|
||||
|
||||
@@ -753,6 +753,15 @@ QString Terminal::name() const
|
||||
return d->m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Terminal::terminalType
|
||||
@return the type of this terminal (Generic, Inner, Outer, No, Nc, Common)
|
||||
*/
|
||||
TerminalData::Type Terminal::terminalType() const
|
||||
{
|
||||
return d->m_type;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Conductor::relatedPotentialTerminal
|
||||
Return terminal at the same potential from the same
|
||||
|
||||
@@ -18,13 +18,14 @@
|
||||
#ifndef TERMINAL_H
|
||||
#define TERMINAL_H
|
||||
#include "../qet.h"
|
||||
#include "../properties/terminaldata.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtXml>
|
||||
class Conductor;
|
||||
class Diagram;
|
||||
class Element;
|
||||
class TerminalData;
|
||||
|
||||
|
||||
/**
|
||||
@brief The Terminal class
|
||||
@@ -75,6 +76,7 @@ class Terminal : public QGraphicsObject
|
||||
Element *parentElement () const;
|
||||
QUuid uuid () const;
|
||||
QString name () const;
|
||||
TerminalData::Type terminalType() const;
|
||||
|
||||
QList<Conductor *> conductors() const;
|
||||
Qet::Orientation orientation() const;
|
||||
|
||||
@@ -308,6 +308,9 @@ void ElementPropertiesWidget::updateUi()
|
||||
case Element::Terminale:
|
||||
m_list_editor << new ElementInfoWidget(m_element, this);
|
||||
break;
|
||||
case Element::ConductorDefinition:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ void XRefPropertiesWidget::saveProperties(int index) {
|
||||
else if(ui->m_xrefpos_cb->itemData(ui->m_xrefpos_cb->currentIndex()).toString() == "right") xrp.setXrefPos(Qt::AlignRight);
|
||||
else if(ui->m_xrefpos_cb->itemData(ui->m_xrefpos_cb->currentIndex()).toString() == "alignment") xrp.setXrefPos(Qt::AlignBaseline);
|
||||
xrp.setShowPowerContac(ui->m_show_power_cb->isChecked());
|
||||
xrp.setShowTerminalName(ui->m_show_terminal_name_cb->isChecked());
|
||||
xrp.setPrefix("power", ui->m_power_prefix_le->text());
|
||||
xrp.setPrefix("delay", ui->m_delay_prefix_le->text());
|
||||
xrp.setPrefix("switch", ui->m_switch_prefix_le->text());
|
||||
@@ -190,6 +191,7 @@ void XRefPropertiesWidget::updateDisplay()
|
||||
else if(xrp.getXrefPos() == Qt::AlignBaseline) ui->m_xrefpos_cb->setCurrentIndex(ui->m_xrefpos_cb->findData("alignment"));
|
||||
else if(xrp.getXrefPos() == Qt::AlignBottom) ui->m_xrefpos_cb->setCurrentIndex(ui->m_xrefpos_cb->findData("bottom"));
|
||||
ui->m_show_power_cb->setChecked(xrp.showPowerContact());
|
||||
ui->m_show_terminal_name_cb->setChecked(xrp.showTerminalName());
|
||||
ui->m_power_prefix_le-> setText(xrp.prefix("power"));
|
||||
ui->m_delay_prefix_le-> setText(xrp.prefix("delay"));
|
||||
ui->m_switch_prefix_le->setText(xrp.prefix("switch"));
|
||||
|
||||
@@ -108,6 +108,13 @@
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_show_terminal_name_cb">
|
||||
<property name="text">
|
||||
<string>Afficher les numéros de bornes dans les Xrefs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_display_has_contacts_rb">
|
||||
<property name="text">
|
||||
@@ -283,6 +290,7 @@
|
||||
<tabstop>m_master_le</tabstop>
|
||||
<tabstop>m_slave_le</tabstop>
|
||||
<tabstop>m_show_power_cb</tabstop>
|
||||
<tabstop>m_show_terminal_name_cb</tabstop>
|
||||
<tabstop>m_power_prefix_le</tabstop>
|
||||
<tabstop>m_delay_prefix_le</tabstop>
|
||||
<tabstop>m_switch_prefix_le</tabstop>
|
||||
|
||||
+205
-114
@@ -5,9 +5,7 @@
|
||||
#include <QTextStream>
|
||||
#include <QDomDocument>
|
||||
#include <QFile>
|
||||
#include <QRegularExpression>
|
||||
#include <QQueue>
|
||||
#include <QSet>
|
||||
#include <algorithm>
|
||||
|
||||
WiringListExport::WiringListExport(QETProject *project, QWidget *parent) :
|
||||
QObject(parent),
|
||||
@@ -45,8 +43,27 @@ QDomElement WiringListExport::climbToDiagram(QDomNode node) const
|
||||
QMap<QString, ElementInfo> WiringListExport::collectElementsInfo(const QDomElement &root) const
|
||||
{
|
||||
QMap<QString, ElementInfo> infoMap;
|
||||
QDomNodeList elements = root.elementsByTagName("element");
|
||||
|
||||
QSet<QString> placeholderTypes;
|
||||
QDomElement collection = root.firstChildElement("collection");
|
||||
if (!collection.isNull()) {
|
||||
QDomNodeList defs = collection.elementsByTagName("definition");
|
||||
for (int i = 0; i < defs.size(); ++i) {
|
||||
QDomElement def = defs.at(i).toElement();
|
||||
QString ltype = def.attribute("link_type");
|
||||
if (ltype == "next_report" || ltype == "previous_report") {
|
||||
QDomElement parentEl = def.parentNode().toElement();
|
||||
if (parentEl.tagName().toLower() == "element") {
|
||||
QString name = parentEl.attribute("name");
|
||||
if (!name.isEmpty()) {
|
||||
placeholderTypes.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDomNodeList elements = root.elementsByTagName("element");
|
||||
for (int i = 0; i < elements.size(); ++i) {
|
||||
QDomElement el = elements.at(i).toElement();
|
||||
QString uuid = normalizeUuid(el.attribute("uuid", el.attribute("id", "")));
|
||||
@@ -75,13 +92,16 @@ QMap<QString, ElementInfo> WiringListExport::collectElementsInfo(const QDomEleme
|
||||
}
|
||||
}
|
||||
|
||||
QString typeVal = el.attribute("type").toLower();
|
||||
if (typeVal.contains("naechste") || typeVal.contains("vorherige") ||
|
||||
typeVal.contains("next") || typeVal.contains("previous")) {
|
||||
info.isPlaceholder = true;
|
||||
QString typeVal = el.attribute("type");
|
||||
info.isPlaceholder = false;
|
||||
for (const QString &ptype : placeholderTypes) {
|
||||
if (typeVal.endsWith(ptype)) {
|
||||
info.isPlaceholder = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
infoMap.insert(uuid, info);
|
||||
infoMap.insert(uuid, info);
|
||||
}
|
||||
return infoMap;
|
||||
}
|
||||
@@ -102,7 +122,15 @@ QList<ConductorData> WiringListExport::collectConductors(const QDomElement &root
|
||||
data.el2_uuid = normalizeUuid(cond.attribute("element2", cond.attribute("element2id", "")));
|
||||
|
||||
data.element1_label = cond.attribute("element1_label");
|
||||
if (data.element1_label.isEmpty()) {
|
||||
data.element1_label = cond.attribute("element1_linked");
|
||||
}
|
||||
|
||||
data.element2_label = cond.attribute("element2_label");
|
||||
if (data.element2_label.isEmpty()) {
|
||||
data.element2_label = cond.attribute("element2_linked");
|
||||
}
|
||||
|
||||
data.terminalname1 = cond.attribute("terminalname1");
|
||||
data.terminalname2 = cond.attribute("terminalname2");
|
||||
data.tension_protocol = cond.attribute("tension_protocol");
|
||||
@@ -119,101 +147,6 @@ QList<ConductorData> WiringListExport::collectConductors(const QDomElement &root
|
||||
return conductors;
|
||||
}
|
||||
|
||||
void WiringListExport::resolveEndpoints(QList<ConductorData> &conductors, const QMap<QString, ElementInfo> &elementsInfo) const
|
||||
{
|
||||
QRegularExpression numericLabelRe("^\\d+(\\.\\d+)?$");
|
||||
|
||||
QMap<QString, QList<ConductorData>> el_to_cons;
|
||||
for (const ConductorData &c : conductors) {
|
||||
if (!c.el1_uuid.isEmpty()) el_to_cons[c.el1_uuid].append(c);
|
||||
if (!c.el2_uuid.isEmpty()) el_to_cons[c.el2_uuid].append(c);
|
||||
}
|
||||
|
||||
for (int i = 0; i < conductors.size(); ++i) {
|
||||
ConductorData &c = conductors[i];
|
||||
|
||||
auto resolveSide = [&](const QString &startUuid, QString &outLabel, QString &outTerminal) {
|
||||
if (startUuid.isEmpty() || !elementsInfo.contains(startUuid)) return;
|
||||
|
||||
const ElementInfo &startInfo = elementsInfo[startUuid];
|
||||
if (!startInfo.links.isEmpty() || startInfo.isPlaceholder) {
|
||||
QQueue<QString> q;
|
||||
QSet<QString> visited;
|
||||
q.enqueue(startUuid);
|
||||
visited.insert(startUuid);
|
||||
|
||||
int depth = 0;
|
||||
while (!q.isEmpty() && depth < 3) {
|
||||
int levelSize = q.size();
|
||||
for (int k = 0; k < levelSize; ++k) {
|
||||
QString curr = q.dequeue();
|
||||
|
||||
if (elementsInfo.contains(curr)) {
|
||||
const ElementInfo &currInfo = elementsInfo[curr];
|
||||
|
||||
if (!currInfo.isPlaceholder && !currInfo.label.isEmpty() && !numericLabelRe.match(currInfo.label).hasMatch()) {
|
||||
outLabel = currInfo.label;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const QString &lnk : currInfo.links) {
|
||||
if (!visited.contains(lnk)) {
|
||||
visited.insert(lnk);
|
||||
q.enqueue(lnk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const ConductorData &cond : el_to_cons.value(curr)) {
|
||||
if (cond.index == c.index) continue;
|
||||
|
||||
QString other;
|
||||
QString terminalHint;
|
||||
if (cond.el1_uuid == curr) {
|
||||
other = cond.el2_uuid;
|
||||
terminalHint = cond.terminalname2;
|
||||
} else {
|
||||
other = cond.el1_uuid;
|
||||
terminalHint = cond.terminalname1;
|
||||
}
|
||||
|
||||
if (!other.isEmpty() && !visited.contains(other)) {
|
||||
if (elementsInfo.contains(other)) {
|
||||
const ElementInfo &oInfo = elementsInfo[other];
|
||||
if (!oInfo.isPlaceholder && !oInfo.label.isEmpty() && !numericLabelRe.match(oInfo.label).hasMatch()) {
|
||||
outLabel = oInfo.label;
|
||||
if (outTerminal.isEmpty()) outTerminal = terminalHint;
|
||||
return;
|
||||
}
|
||||
}
|
||||
visited.insert(other);
|
||||
q.enqueue(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
depth++;
|
||||
}
|
||||
} else {
|
||||
if (outLabel.isEmpty()) {
|
||||
outLabel = startInfo.label.isEmpty() ? startInfo.name : startInfo.label;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool p1 = elementsInfo.value(c.el1_uuid).isPlaceholder;
|
||||
bool p2 = elementsInfo.value(c.el2_uuid).isPlaceholder;
|
||||
|
||||
if (c.element1_label.isEmpty() || p1) {
|
||||
if (p1) c.element1_label = "";
|
||||
resolveSide(c.el1_uuid, c.element1_label, c.terminalname1);
|
||||
}
|
||||
if (c.element2_label.isEmpty() || p2) {
|
||||
if (p2) c.element2_label = "";
|
||||
resolveSide(c.el2_uuid, c.element2_label, c.terminalname2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WiringListExport::toCsv()
|
||||
{
|
||||
if (!m_project) return;
|
||||
@@ -225,6 +158,45 @@ void WiringListExport::toCsv()
|
||||
return;
|
||||
}
|
||||
|
||||
QSet<QString> conductorDefinitionTypes;
|
||||
QDomElement rootElem = doc.documentElement();
|
||||
QDomElement collection = rootElem.firstChildElement("collection");
|
||||
if (!collection.isNull()) {
|
||||
QDomNodeList defs = collection.elementsByTagName("definition");
|
||||
for (int i = 0; i < defs.size(); ++i) {
|
||||
QDomElement def = defs.at(i).toElement();
|
||||
if (def.attribute("link_type") == "conductor_definition") {
|
||||
QDomElement parentEl = def.parentNode().toElement();
|
||||
if (parentEl.tagName().toLower() == "element") {
|
||||
QString name = parentEl.attribute("name");
|
||||
if (!name.isEmpty()) {
|
||||
conductorDefinitionTypes.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QSet<QString> conductorDefinitionUuids;
|
||||
QDomNodeList projectElements = rootElem.elementsByTagName("element");
|
||||
for (int i = 0; i < projectElements.size(); ++i) {
|
||||
QDomElement el = projectElements.at(i).toElement();
|
||||
QString typeVal = el.attribute("type");
|
||||
bool isCondDef = false;
|
||||
for (const QString &cType : conductorDefinitionTypes) {
|
||||
if (typeVal.endsWith(cType)) {
|
||||
isCondDef = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCondDef) {
|
||||
QString uuid = normalizeUuid(el.attribute("uuid", el.attribute("id", "")));
|
||||
if (!uuid.isEmpty()) {
|
||||
conductorDefinitionUuids.insert(uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QFileDialog dialog(m_parent);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog.setWindowTitle(tr("Exporter le plan de câblage"));
|
||||
@@ -243,25 +215,144 @@ void WiringListExport::toCsv()
|
||||
QMap<QString, ElementInfo> elementsInfo = collectElementsInfo(doc.documentElement());
|
||||
QList<ConductorData> conductors = collectConductors(doc.documentElement());
|
||||
|
||||
resolveEndpoints(conductors, elementsInfo);
|
||||
|
||||
QList<ConductorData> uniqueConductors;
|
||||
QSet<QString> seenConnections;
|
||||
QMap<QString, ConductorData> partialWires;
|
||||
|
||||
for (const ConductorData &c : conductors) {
|
||||
if (c.element1_label.isEmpty() && c.element2_label.isEmpty()) continue;
|
||||
auto normalizePartial = [](ConductorData c, const QString &ph_uuid) {
|
||||
if (c.el1_uuid == ph_uuid) {
|
||||
std::swap(c.el1_uuid, c.el2_uuid);
|
||||
std::swap(c.element1_label, c.element2_label);
|
||||
std::swap(c.terminalname1, c.terminalname2);
|
||||
}
|
||||
return c;
|
||||
};
|
||||
|
||||
QString sideA = c.element1_label + ":" + c.terminalname1;
|
||||
QString sideB = c.element2_label + ":" + c.terminalname2;
|
||||
auto mergeField = [](const QString &a, const QString &b) {
|
||||
QString at = a.trimmed();
|
||||
QString bt = b.trimmed();
|
||||
if (at.isEmpty()) return bt;
|
||||
if (bt.isEmpty()) return at;
|
||||
if (at == bt) return at;
|
||||
return at + ", " + bt;
|
||||
};
|
||||
|
||||
QString key = (sideA < sideB) ? (sideA + "||" + sideB) : (sideB + "||" + sideA);
|
||||
for (int i = 0; i < conductors.size(); ++i) {
|
||||
ConductorData c = conductors[i];
|
||||
|
||||
if (!seenConnections.contains(key)) {
|
||||
seenConnections.insert(key);
|
||||
if (conductorDefinitionUuids.contains(c.el1_uuid) || conductorDefinitionUuids.contains(c.el2_uuid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c.element1_label.isEmpty() && elementsInfo.contains(c.el1_uuid)) {
|
||||
c.element1_label = elementsInfo[c.el1_uuid].label;
|
||||
if (c.element1_label.isEmpty()) c.element1_label = elementsInfo[c.el1_uuid].name;
|
||||
}
|
||||
if (c.element2_label.isEmpty() && elementsInfo.contains(c.el2_uuid)) {
|
||||
c.element2_label = elementsInfo[c.el2_uuid].label;
|
||||
if (c.element2_label.isEmpty()) c.element2_label = elementsInfo[c.el2_uuid].name;
|
||||
}
|
||||
|
||||
bool el1_ph = elementsInfo.value(c.el1_uuid).isPlaceholder;
|
||||
bool el2_ph = elementsInfo.value(c.el2_uuid).isPlaceholder;
|
||||
|
||||
if (!el1_ph && !el2_ph) {
|
||||
uniqueConductors.append(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (el1_ph && el2_ph) {
|
||||
uniqueConductors.append(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
QString ph_uuid = el1_ph ? c.el1_uuid : c.el2_uuid;
|
||||
ConductorData normC = normalizePartial(c, ph_uuid);
|
||||
|
||||
QString matching_ph_uuid;
|
||||
if (!elementsInfo[ph_uuid].links.isEmpty()) {
|
||||
matching_ph_uuid = elementsInfo[ph_uuid].links.first();
|
||||
}
|
||||
|
||||
if (!matching_ph_uuid.isEmpty() && partialWires.contains(matching_ph_uuid)) {
|
||||
ConductorData otherHalf = partialWires.take(matching_ph_uuid);
|
||||
|
||||
ConductorData merged;
|
||||
merged.folio = mergeField(otherHalf.folio, normC.folio);
|
||||
|
||||
merged.el1_uuid = otherHalf.el1_uuid;
|
||||
merged.element1_label = otherHalf.element1_label;
|
||||
merged.terminalname1 = otherHalf.terminalname1;
|
||||
|
||||
merged.el2_uuid = normC.el1_uuid;
|
||||
merged.element2_label = normC.element1_label;
|
||||
merged.terminalname2 = normC.terminalname1;
|
||||
|
||||
merged.tension_protocol = mergeField(otherHalf.tension_protocol, normC.tension_protocol);
|
||||
merged.conductor_color = mergeField(otherHalf.conductor_color, normC.conductor_color);
|
||||
merged.conductor_section = mergeField(otherHalf.conductor_section, normC.conductor_section);
|
||||
merged.function = mergeField(otherHalf.function, normC.function);
|
||||
|
||||
uniqueConductors.append(merged);
|
||||
} else {
|
||||
partialWires.insert(ph_uuid, normC);
|
||||
}
|
||||
}
|
||||
|
||||
for (const ConductorData &leftover : partialWires.values()) {
|
||||
uniqueConductors.append(leftover);
|
||||
}
|
||||
|
||||
for (ConductorData &c : uniqueConductors) {
|
||||
if (!c.element2_label.isEmpty() && (c.element1_label.isEmpty() || c.element2_label.toLower() < c.element1_label.toLower())) {
|
||||
std::swap(c.element1_label, c.element2_label);
|
||||
std::swap(c.terminalname1, c.terminalname2);
|
||||
std::swap(c.el1_uuid, c.el2_uuid);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(uniqueConductors.begin(), uniqueConductors.end(), [](const ConductorData &a, const ConductorData &b) {
|
||||
QStringList partsA = a.folio.split(',');
|
||||
QStringList partsB = b.folio.split(',');
|
||||
int minLen = std::min(partsA.size(), partsB.size());
|
||||
int folioCmp = 0;
|
||||
|
||||
for (int i = 0; i < minLen; ++i) {
|
||||
bool okA, okB;
|
||||
int numA = partsA[i].trimmed().toInt(&okA);
|
||||
int numB = partsB[i].trimmed().toInt(&okB);
|
||||
|
||||
if (okA && okB) {
|
||||
if (numA != numB) {
|
||||
folioCmp = (numA < numB) ? -1 : 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int strCmp = partsA[i].trimmed().compare(partsB[i].trimmed(), Qt::CaseInsensitive);
|
||||
if (strCmp != 0) {
|
||||
folioCmp = strCmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (folioCmp == 0 && partsA.size() != partsB.size()) {
|
||||
folioCmp = (partsA.size() < partsB.size()) ? -1 : 1;
|
||||
}
|
||||
|
||||
if (folioCmp != 0) return folioCmp < 0;
|
||||
|
||||
int el1Cmp = a.element1_label.toLower().compare(b.element1_label.toLower());
|
||||
if (el1Cmp != 0) return el1Cmp < 0;
|
||||
|
||||
int el2Cmp = a.element2_label.toLower().compare(b.element2_label.toLower());
|
||||
if (el2Cmp != 0) return el2Cmp < 0;
|
||||
|
||||
int term1Cmp = a.terminalname1.compare(b.terminalname1);
|
||||
if (term1Cmp != 0) return term1Cmp < 0;
|
||||
|
||||
return a.terminalname2 < b.terminalname2;
|
||||
});
|
||||
|
||||
QTextStream out(&file);
|
||||
out << tr("Page", "Wiring list CSV header") << ";"
|
||||
<< tr("Composant 1", "Wiring list CSV header") << ";"
|
||||
|
||||
@@ -12,7 +12,6 @@ class QWidget;
|
||||
class QDomElement;
|
||||
class QDomNode;
|
||||
|
||||
// Internal data structures for parsing the XML graph
|
||||
struct ElementInfo {
|
||||
QString folio;
|
||||
QStringList links;
|
||||
@@ -34,18 +33,11 @@ struct ConductorData {
|
||||
QString conductor_section;
|
||||
QString function;
|
||||
QString folio;
|
||||
|
||||
// Resolved endpoints
|
||||
QString chosen_a_uuid;
|
||||
QString chosen_a_label;
|
||||
QString chosen_b_uuid;
|
||||
QString chosen_b_label;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The WiringListExport class
|
||||
* Handles the export of the wiring list (Verdrahtungsplan) to a CSV file.
|
||||
* Automatically resolves links and placeholders to find physical endpoints.
|
||||
* Exports the wiring diagram from QElectroTech as a CSV file.
|
||||
*/
|
||||
class WiringListExport : public QObject
|
||||
{
|
||||
@@ -64,8 +56,6 @@ private:
|
||||
|
||||
QMap<QString, ElementInfo> collectElementsInfo(const QDomElement &root) const;
|
||||
QList<ConductorData> collectConductors(const QDomElement &root) const;
|
||||
|
||||
void resolveEndpoints(QList<ConductorData> &conductors, const QMap<QString, ElementInfo> &elementsInfo) const;
|
||||
};
|
||||
|
||||
#endif // WIRINGLISTEXPORT_H
|
||||
|
||||
Reference in New Issue
Block a user