Reapply "Add cable management: drawing, cores, numbering, cross-references and cable list"

This reverts commit 2bb3343d2d.
This commit is contained in:
Laurent Trinques
2026-10-11 05:00:01 +02:00
parent 124a889be3
commit 1cd8fadbc4
113 changed files with 18793 additions and 209 deletions
+233 -9
View File
@@ -46,8 +46,11 @@
#endif
#include "diagramevent/diagrameventaddshape.h"
#include "diagramevent/diagrameventaddpath.h"
#include "diagramevent/diagrameventaddcable.h"
#include "diagramevent/diagrameventfillet.h"
#include "diagramevent/diagrameventaddtext.h"
#include "cable/cablepart.h"
#include "cable/editcablecommand.h"
#include "diagramevent/diagrameventaddpaste.h"
#include "diagramview.h"
#include "elementspanelwidget.h"
@@ -55,6 +58,7 @@
#include "factory/qetgraphicstablefactory.h"
#include "print/projectprintwindow.h"
#include "project/projectpropertieshandler.h"
#include "ui/projectpropertiesdialog.h"
#include "projectview.h"
#include "qetproject.h"
#include "qetgraphicsitem/ViewItem/qetgraphicstableitem.h"
@@ -65,6 +69,7 @@
#include "recentfiles.h"
#include "textgrid.h"
#include "shortcutmanager.h"
#include "cablelist/cableexportdialog.h"
#include "ui/bomexportdialog.h"
#include "ui/conductorcolortoolbutton.h"
#include "ui/diagrambgcolorbutton.h"
@@ -90,6 +95,7 @@
#include "wiringlistexport.h"
#include "ui/wiringlistdialog.h"
#include "ui/terminalnumberingdialog.h"
#include "ui/cablenumberingdialog.h"
#include "toolbarsettings.h"
#include <QDateTime>
#include <QDebug>
@@ -744,6 +750,27 @@ void QETDiagramEditor::setUpActions()
ShortcutManager::instance().registerAction(m_project_terminalBloc, "diagrameditor.terminal_strip_plugin", tr("Diagram editors"), QKeySequence());
connect(m_project_terminalBloc, &QAction::triggered, this, &QETDiagramEditor::generateTerminalBlock);
//Add a cable list
m_add_cable_list = new QAction(QET::Icons::TableOfContent, tr("Add a cable list"), this);
connect(m_add_cable_list, &QAction::triggered, this, [this]() {
if (this->currentDiagramView()) {
QetGraphicsTableFactory::createAndAddCableList(this->currentDiagramView()->diagram());
}
});
//Export the whole cable list to CSV, every column of the list
m_export_cable_list = new QAction(QET::Icons::DocumentSpreadsheet, tr("Export the cable list to CSV format"), this);
connect(m_export_cable_list, &QAction::triggered, [this]() {
QETProject *project = this->currentProject();
if (!project) {
return;
}
//The same dialog the material list is exported with, only
//with the columns of the cable list
CableExportDialog dialog(project, this);
dialog.exec();
});
//Export conductor num to csv
m_project_export_conductor_num = new QAction(QET::Icons::DocumentSpreadsheet, tr("Export the list of names of wires"), this);
ShortcutManager::instance().registerAction(m_project_export_conductor_num, "diagrameditor.export_conductor_names", tr("Diagram editors"), QKeySequence());
@@ -784,6 +811,14 @@ void QETDiagramEditor::setUpActions()
ShortcutManager::instance().registerAction(m_terminal_numbering, "diagrameditor.terminal_numbering", tr("Diagram editors"), QKeySequence());
connect(m_terminal_numbering, &QAction::triggered, this, &QETDiagramEditor::slot_terminalNumbering);
// Cable numbering: the rule the project numbers its cables with, and
// the numbering of every cable of that project at once
m_cable_numbering = new QAction(QET::Icons::AutoNum, tr("Cable numbering"), this);
m_cable_numbering->setStatusTip(
tr("Shows the cable numbering rule of the project and "
"renumbers its cables with it"));
connect(m_cable_numbering, &QAction::triggered, this, &QETDiagramEditor::slot_cableNumbering);
// Reload element drawings from their current definition (bugtracker #802)
m_reload_element_drawings = new QAction(QET::Icons::ViewRefresh, tr("Reload element drawings"), this);
ShortcutManager::instance().registerAction(m_reload_element_drawings, "diagrameditor.reload_element_drawings", tr("Diagram editors"), QKeySequence());
@@ -1243,6 +1278,9 @@ void QETDiagramEditor::setUpActions()
QAction *add_fillet = m_add_item_actions_group.addAction(QET::Icons::DrawFillet, tr("Add a fillet"));
QAction *add_terminal_strip = m_add_item_actions_group.addAction(QET::Icons::TerminalStrip, tr("Add a terminal plan"));
QAction *add_generic_device = m_add_item_actions_group.addAction(QET::Icons::GenericDevice, tr("Add a generic device…"));
//Not an element of the drawing but a line drawn across the
//conductors: what it crosses becomes the cores of a cable.
m_add_cable = m_add_item_actions_group.addAction(QET::Icons::Cable, tr("Draw a cable"));
add_text ->setStatusTip(tr("Adds a text field to the current sheet"));
add_image ->setStatusTip(tr("Add an image to the current sheet"));
@@ -1258,6 +1296,7 @@ void QETDiagramEditor::setUpActions()
add_fillet ->setStatusTip(tr("Rounds the corner between two lines of the current sheet"));
add_terminal_strip->setStatusTip(tr("Adds a terminal plan to the current sheet"));
add_generic_device->setStatusTip(tr("Makes a box symbol with terminals on any side and places it on the current sheet"));
m_add_cable ->setStatusTip(tr("Draws the main line of a cable: every conductor crossed becomes one of its cores"));
add_text ->setData(QStringLiteral("text"));
add_image ->setData(QStringLiteral("image"));
@@ -1273,6 +1312,7 @@ void QETDiagramEditor::setUpActions()
add_fillet ->setData(QStringLiteral("fillet"));
add_terminal_strip->setData(QStringLiteral("terminal_strip"));
add_generic_device->setData(QStringLiteral("generic_device"));
m_add_cable ->setData(QStringLiteral("cable"));
add_text->setCheckable(true);
add_line->setCheckable(true);
@@ -1281,6 +1321,7 @@ void QETDiagramEditor::setUpActions()
add_arc->setCheckable(true);
add_polyline->setCheckable(true);
add_path->setCheckable(true);
m_add_cable->setCheckable(true);
add_fillet->setCheckable(true);
connect(&m_add_item_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::addItemGroupTriggered);
@@ -1442,6 +1483,10 @@ void QETDiagramEditor::setUpMenu()
QMenu* menu_fichier = new QMenu(tr("&File"), this);
QMenu* menu_edition = new QMenu(tr("&Edit"), this);
QMenu* menu_project = new QMenu(tr("&Project"), this);
//Numbering of everything the project numbers, kept together
//and sitting right behind the project it belongs to
QMenu* menu_numbering = new QMenu(tr("Numbering"), this);
QMenu* menu_lists = new QMenu(tr("Lists"), this);
QMenu* menu_affichage = new QMenu(tr("Displ&ay"), this);
// QMenu *menu_outils = new QMenu(tr("O&utils"), this);
windows_menu = new QMenu(tr("Wi&ndows"), this);
@@ -1449,6 +1494,8 @@ void QETDiagramEditor::setUpMenu()
insertMenu(settings_menu_, menu_fichier);
insertMenu(settings_menu_, menu_edition);
insertMenu(settings_menu_, menu_project);
insertMenu(settings_menu_, menu_numbering);
insertMenu(settings_menu_, menu_lists);
insertMenu(settings_menu_, menu_affichage);
insertMenu(help_menu_, windows_menu);
@@ -1556,15 +1603,11 @@ void QETDiagramEditor::setUpMenu()
menu_project -> addAction(m_remove_diagram_from_project);
menu_project -> addAction(m_clean_project);
menu_project -> addSeparator();
menu_project -> addAction(m_add_summary);
menu_project -> addAction(m_add_nomenclature);
menu_project -> addAction(m_csv_export);
menu_project -> addAction(m_export_cable_list);
menu_project -> addAction(m_project_export_conductor_num);
menu_project -> addAction(m_terminal_strip_dialog);
menu_project -> addAction(m_project_terminalBloc);
menu_project -> addAction(m_project_export_wiring_list);
menu_project -> addAction(m_project_wiring_list_view);
menu_project -> addAction(m_terminal_numbering);
menu_project -> addAction(m_reload_element_drawings);
#ifdef QET_HAS_SCRIPTING
m_scripts_menu = menu_project -> addMenu(tr("Scripts"));
@@ -1578,6 +1621,27 @@ void QETDiagramEditor::setUpMenu()
menu_project -> addAction(m_export_project_db);
#endif
// menu Numbering
//Everything the project numbers sits here together: the
//terminals have come out of the project menu, the cables are
//the new one
menu_numbering -> addAction(m_terminal_numbering);
menu_numbering -> addAction(m_cable_numbering);
// menu Listes
//Everything which drops a table or a list onto the sheets has
//come out of the project menu and sits here together: the
//summary, the material list, the terminal strip tools and the
//cable list. The CSV exports stay with the other exports in the
//project menu, the cable list's among them.
menu_lists -> addAction(m_add_summary);
menu_lists -> addAction(m_add_nomenclature);
menu_lists -> addSeparator();
menu_lists -> addAction(m_terminal_strip_dialog);
menu_lists -> addAction(m_project_terminalBloc);
menu_lists -> addSeparator();
menu_lists -> addAction(m_add_cable_list);
main_tool_bar -> toggleViewAction() -> setStatusTip(tr("Display or hide the main toolbar"));
view_tool_bar -> toggleViewAction() -> setStatusTip(tr("Display or hide the Display toolbar"));
diagram_tool_bar -> toggleViewAction() -> setStatusTip(tr("Display or hide the Diagram toolbar"));
@@ -2242,6 +2306,90 @@ void QETDiagramEditor::selectGroupTriggered(QAction *action)
diagram->selectAllTextFields();
}
/**
@brief QETDiagramEditor::cableNumberingGate
Decide whether the cable tool may start, asking about the numbering
rule when the project numbers its cables by no rule at all.
A project which does have one is asked nothing: the tool starts and
that rule gives the numbers. A project which has none is asked once
whether one should be defined now:
- Oui opens the window where the rule is written, straight onto the
cable page of its automatic numbering; whatever he does in there,
the tool only starts if a rule really exists by the time that
window is closed.
- Non says no, and says it for good: it is remembered in the program
settings so the question does not come up on the next start
either. Drawing goes on all the same, with W as the cable's name:
no number is worked out where none has been defined.
- Annuler leaves everything as it was, the tool does not start, and
the question comes again the next time he picks the tool up.
@param diagram the folio the cable would be drawn on
@return true when the cable tool may start
*/
bool QETDiagramEditor::cableNumberingGate(Diagram *diagram)
{
if (!diagram || !diagram->project()) return true;
QETProject *project = diagram->project();
if (project->hasCableAutoNum()) return true;
//A read-only project is left alone without a question: there is
//nowhere to define a rule in it, so asking whether he wants to
//would be a way to nowhere. Its cables are drawn called W, the
//same as any project without a rule.
if (project->isReadOnly()) return true;
//Whether he has once answered no in THIS project. The answer is
//kept with the project rather than in the program settings, so
//one project being answered with no does not stop every other
//project from being asked.
if (!project->cableAskNumbering()) {
return true;
}
QMessageBox box(QMessageBox::Question,
tr("Automatic numbering", "window title"),
tr("No automatic cable numbering is defined.",
"shown when a project has no cable numbering rule"),
QMessageBox::NoButton,
this);
box.setInformativeText(tr(
"Do you want to define one now?\n\n"
"You can also number the cables automatically later: the rule "
"is set at any time in the project properties, on the "
"\"Auto Numbering\" page.",
"ask whether a cable numbering rule should be defined now"));
QPushButton *define_button = box.addButton(tr("Yes", "yes"), QMessageBox::YesRole);
QPushButton *later_button = box.addButton(tr("No", "no"), QMessageBox::NoRole);
box.addButton(tr("Cancel", "cancel"), QMessageBox::RejectRole);
box.setDefaultButton(later_button);
box.exec();
if (box.clickedButton() == later_button) {
//With this project only: he has answered once here and
//should not be asked again every time he picks the tool
//up in this project -- another project is free to ask.
project->setCableAskNumbering(false);
project->setModified(true);
return true;
}
if (box.clickedButton() != define_button) {
return false;
}
//Oui: the window itself, opened where the rule is written. It
//has to really be there by the time that window is closed --
//a Cancel in it must not leave the tool running all the same.
ProjectPropertiesDialog dialog(diagram->project(), this);
dialog.setCurrentPage(ProjectPropertiesDialog::Autonum);
dialog.changeToCable();
dialog.exec();
return diagram->project()->hasCableAutoNum();
}
/**
@brief QETDiagramEditor::addItemGroupTriggered
This slot is called when an item must be added to the current diagram,
@@ -2294,6 +2442,22 @@ void QETDiagramEditor::addItemGroupTriggered(QAction *action)
{
diagram_event = new DiagramEventAddPath (d);
}
else if (value == QLatin1String("cable"))
{
//The rule the number comes from -- or the word about there
//being no rule yet -- comes before anything is drawn.
if (!cableNumberingGate(d))
{
//Nothing is drawn, so the button must not go on looking
//like a tool which is running, and whichever tool was
//active before this click must not keep going with its
//own button unchecked either.
action->setChecked(false);
d->clearEventInterface();
return;
}
diagram_event = new DiagramEventAddCable(d);
}
else if (value == "fillet")
diagram_event = new DiagramEventFillet (d);
else if (value == "image")
@@ -2388,8 +2552,30 @@ void QETDiagramEditor::selectionGroupTriggered(QAction *action)
"Unbridge and/or remove the levels from the affected terminals so that they can be "
"deleted"));
} else {
//A cable line is not held by DiagramContent: it is
//removed by its own command, which also lets the cable
//it belongs to go when no line of it is left anywhere.
QList<CablePart *> cable_parts;
for (QGraphicsItem *item : diagram->selectedItems()) {
if (auto *part = qgraphicsitem_cast<CablePart *>(item)) {
cable_parts << part;
}
}
const bool other_items = dc.hasDeletableItems();
diagram->clearSelection();
diagram->undoStack().push(new DeleteQGraphicsItemCommand(diagram, dc));
if (cable_parts.isEmpty()) {
diagram->undoStack().push(new DeleteQGraphicsItemCommand(diagram, dc));
} else if (!other_items) {
diagram->undoStack().push(new RemoveCableCommand(diagram, cable_parts));
} else {
//One single step, so a selection holding both a
//cable and ordinary drawings comes back whole.
diagram->undoStack().push(new BatchCommand(
new DeleteQGraphicsItemCommand(diagram, dc),
new RemoveCableCommand(diagram, cable_parts)));
}
dv->adjustSceneRect();
}
}
@@ -2593,6 +2779,9 @@ void QETDiagramEditor::slot_updateActions()
m_project_export_wiring_list -> setEnabled(opened_project);
m_project_wiring_list_view -> setEnabled(opened_project);
m_terminal_numbering -> setEnabled(editable_project);
m_cable_numbering -> setEnabled(editable_project);
m_add_cable_list -> setEnabled(editable_project);
m_export_cable_list -> setEnabled(editable_project);
m_reload_element_drawings -> setEnabled(opened_project);
#ifdef QET_HAS_SCRIPTING
m_run_script -> setEnabled(opened_project);
@@ -2686,8 +2875,20 @@ void QETDiagramEditor::slot_updateComplexActions()
m_mirror_vertical->setEnabled(!ro && selected_elements_count);
//Actions that need items (elements, conductors, texts...) selected, to be enabled
bool copiable_items = dc.hasCopiableItems();
bool deletable_items = dc.hasDeletableItems();
//A cable line is drawn on the folio but held by the cable, not
//by DiagramContent: it counts on its own for deleting and editing.
int selected_cables = 0;
for (QGraphicsItem *item : diagram_->selectedItems()) {
if (item && item->type() == CablePart::Type) {
selected_cables++;
}
}
//A drawn cable line is copyable, cuttable and duplicatable on
//its own, although it belongs to its cable rather than to the
//folio and DiagramContent never sees it.
bool copiable_items = dc.hasCopiableItems() || selected_cables > 0;
bool deletable_items = dc.hasDeletableItems() || selected_cables > 0;
m_cut -> setEnabled(!ro && copiable_items);
m_copy -> setEnabled(copiable_items);
m_duplicate -> setEnabled(!ro && copiable_items);
@@ -2743,7 +2944,8 @@ void QETDiagramEditor::slot_updateComplexActions()
- selected_dynamic_elmt_text)
+ selected_image
+ selected_shape
+ selected_conductors_count;
+ selected_conductors_count
+ selected_cables;
if (selected_editable == 1)
{
@@ -2769,6 +2971,13 @@ void QETDiagramEditor::slot_updateComplexActions()
"edit image"));
m_edit_selection -> setIcon(QET::Icons::resize_image);
}
//edit cable
else if (selected_cables)
{
m_edit_selection -> setText(tr("Edit the cable",
"edit cable"));
m_edit_selection -> setIcon(QET::Icons::Cable);
}
//edit conductor
else if (selected_conductors_count)
{
@@ -4011,6 +4220,21 @@ void QETDiagramEditor::slot_terminalNumbering() {
}
}
/**
* @brief QETDiagramEditor::slot_cableNumbering
* Opens the window holding the numbering rule of the project's cables
* and the button which numbers every one of them again. The window
* writes the project and pushes its own undo step itself, so nothing
* is done with its result here beyond letting it work.
*/
void QETDiagramEditor::slot_cableNumbering() {
QETProject *project = currentProject();
if (!project) return;
CableNumberingDialog dialog(project, this);
dialog.exec();
}
/**
@brief QETDiagramEditor::slot_reloadElementDrawings
Redraw every placed element of the current project from its current