mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-28 04:54:13 +02:00
dcb79b6553
Three bugs stacked to produce the symptom in issue #409 (move button does nothing): 1. selectionChanged() was declared in freeterminaleditor.h but had no body and was never connected to the selection model, so the move button had no awareness of whether a terminal was selected. The button could appear enabled with nothing selected, then silently return early in on_m_move_pb_clicked() at the real_t_vector.isEmpty() guard. 2. The dataChanged→setDisabledMove(true) connection was a one-way trap: any cell edit (including accidentally opening and closing a type/function combo, or toggling LED back to its current value) permanently disabled the move button until reload() was called. There was no tooltip explaining why the button was greyed out, so the user had no way to recover. 3. FreeTerminalModel::setData() for LED_CELL had no change guard, unlike LABEL_CELL which checks label != value. Clicking the LED combo while it was already at the same value still emitted dataChanged and triggered the disable. Fix: - Implement selectionChanged() to enable the move controls only when at least one row is selected AND there are no pending (yellow) edits. - Connect it to both selectionModel::selectionChanged and model::dataChanged so the button state is always consistent with actual UI state. - Route reload()'s re-enable through selectionChanged() instead of calling setDisabledMove(false) directly, so the selection state is respected immediately after a move. - Add a tooltip to m_move_pb explaining the disabled state. - Add the missing change guard to LED_CELL in setData(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
293 lines
8.0 KiB
C++
293 lines
8.0 KiB
C++
/*
|
|
Copyright 2006-2026 The QElectroTech Team
|
|
This file is part of QElectroTech.
|
|
|
|
QElectroTech is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
QElectroTech is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "freeterminaleditor.h"
|
|
#include "ui_freeterminaleditor.h"
|
|
|
|
#include "../undocommand/changeelementdatacommand.h"
|
|
#include "../../diagram.h"
|
|
#include "../../elementprovider.h"
|
|
#include "freeterminalmodel.h"
|
|
#include "../terminalstrip.h"
|
|
#include "../UndoCommand/addterminaltostripcommand.h"
|
|
|
|
/**
|
|
* @brief FreeTerminalEditor::FreeTerminalEditor
|
|
* @param project
|
|
* @param parent
|
|
*/
|
|
FreeTerminalEditor::FreeTerminalEditor(QETProject *project, QWidget *parent) :
|
|
QWidget(parent),
|
|
ui(new Ui::FreeTerminalEditor),
|
|
m_project(project)
|
|
{
|
|
ui->setupUi(this);
|
|
ui->m_table_view->setItemDelegate(new FreeTerminalModelDelegate(ui->m_table_view));
|
|
|
|
m_model = new FreeTerminalModel(m_project, this);
|
|
ui->m_table_view->setModel(m_model);
|
|
ui->m_table_view->setCurrentIndex(m_model->index(0,0));
|
|
|
|
if (m_project) {
|
|
connect(m_project, &QObject::destroyed, this, &FreeTerminalEditor::reload);
|
|
}
|
|
|
|
//Disable the move button while cells are edited (yellow), re-evaluate on every change
|
|
connect(m_model, &FreeTerminalModel::dataChanged, this, &FreeTerminalEditor::selectionChanged);
|
|
|
|
connect(ui->m_table_view->selectionModel(), &QItemSelectionModel::selectionChanged,
|
|
this, &FreeTerminalEditor::selectionChanged);
|
|
|
|
connect(ui->m_table_view, &QAbstractItemView::doubleClicked, this, [=](const QModelIndex &index)
|
|
{
|
|
if (m_model->columnTypeForIndex(index) == FreeTerminalModel::XRef)
|
|
{
|
|
auto mrtd = m_model->dataAtRow(index.row());
|
|
if (mrtd.element_)
|
|
{
|
|
auto elmt = mrtd.element_;
|
|
auto diagram = elmt->diagram();
|
|
if (diagram)
|
|
{
|
|
diagram->showMe();
|
|
if (diagram->views().size())
|
|
{
|
|
auto fit_view = elmt->sceneBoundingRect();
|
|
fit_view.adjust(-200,-200,200,200);
|
|
diagram->views().at(0)->fitInView(fit_view, Qt::KeepAspectRatioByExpanding);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @brief FreeTerminalEditor::~FreeTerminalEditor
|
|
*/
|
|
FreeTerminalEditor::~FreeTerminalEditor()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
/**
|
|
* @brief FreeTerminalEditor::reload
|
|
* Reload the editor to be up to date with
|
|
* the current state of the project.
|
|
* Every not applied change will be lost.
|
|
*/
|
|
void FreeTerminalEditor::reload()
|
|
{
|
|
m_model->clear();
|
|
ui->m_move_in_cb->clear();
|
|
|
|
if (m_project)
|
|
{
|
|
const auto strip_vector = m_project->terminalStrip();
|
|
for (const auto &strip : strip_vector)
|
|
{
|
|
QString str(strip->installation() + " " + strip->location() + " " + strip->name());
|
|
ui->m_move_in_cb->addItem(str, strip->uuid());
|
|
}
|
|
selectionChanged();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief FreeTerminalEditor::apply
|
|
* Applu current edited values
|
|
*/
|
|
void FreeTerminalEditor::apply()
|
|
{
|
|
const auto modified_data = m_model->modifiedModelRealTerminalData();
|
|
if (modified_data.size())
|
|
{
|
|
m_project->undoStack()->beginMacro(tr("Modifier des propriétés de borniers"));
|
|
|
|
for (const auto &data_ : modified_data)
|
|
{
|
|
if (auto element_ = data_.element_)
|
|
{
|
|
auto current_data = element_->elementData();
|
|
current_data.setTerminalType(data_.type_);
|
|
current_data.setTerminalFunction(data_.function_);
|
|
current_data.setTerminalLED(data_.led_);
|
|
current_data.m_informations.addValue(QStringLiteral("label"), data_.label_);
|
|
|
|
if (element_->elementData() != current_data) {
|
|
m_project->undoStack()->push(new ChangeElementDataCommand(element_, current_data));
|
|
}
|
|
}
|
|
}
|
|
|
|
m_project->undoStack()->endMacro();
|
|
}
|
|
|
|
reload();
|
|
}
|
|
|
|
/**
|
|
* @brief FreeTerminalEditor::setProject
|
|
* Set @project as project handled by this editor.
|
|
* If a previous project was setted, everything is clear.
|
|
* This function track the destruction of the project,
|
|
* that mean if the project pointer is deleted
|
|
* no need to call this function with a nullptr,
|
|
* everything is made inside this class.
|
|
* @param project
|
|
*/
|
|
void FreeTerminalEditor::setProject(QETProject *project)
|
|
{
|
|
if(m_project) {
|
|
disconnect(m_project, &QObject::destroyed, this, &FreeTerminalEditor::reload);
|
|
}
|
|
m_project = project;
|
|
if (m_model) {
|
|
m_model->setProject(project);
|
|
}
|
|
if (m_project) {
|
|
connect(m_project, &QObject::destroyed, this, &FreeTerminalEditor::reload);
|
|
}
|
|
reload();
|
|
}
|
|
|
|
void FreeTerminalEditor::on_m_type_cb_activated(int index)
|
|
{
|
|
if (m_model)
|
|
{
|
|
const auto index_list = ui->m_table_view->selectionModel()->selectedIndexes();
|
|
|
|
for (auto model_index : index_list)
|
|
{
|
|
auto type_index = m_model->index(model_index.row(), FreeTerminalModel::Type, model_index.parent());
|
|
if (type_index.isValid())
|
|
{
|
|
ElementData::TerminalType override_type;
|
|
switch (index) {
|
|
case 0:
|
|
override_type = ElementData::TTGeneric; break;
|
|
case 1:
|
|
override_type = ElementData::TTFuse; break;
|
|
case 2:
|
|
override_type = ElementData::TTSectional; break;
|
|
case 3:
|
|
override_type = ElementData::TTDiode; break;
|
|
case 4:
|
|
override_type = ElementData::TTGround; break;
|
|
default:
|
|
override_type = ElementData::TTGeneric; break;
|
|
}
|
|
m_model->setData(type_index, override_type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FreeTerminalEditor::on_m_function_cb_activated(int index)
|
|
{
|
|
if (m_model)
|
|
{
|
|
const auto index_list = ui->m_table_view->selectionModel()->selectedIndexes();
|
|
|
|
for (auto model_index : index_list)
|
|
{
|
|
auto function_index = m_model->index(model_index.row(), FreeTerminalModel::Function, model_index.parent());
|
|
if (function_index.isValid())
|
|
{
|
|
ElementData::TerminalFunction override_function;
|
|
switch (index) {
|
|
case 0:
|
|
override_function = ElementData::TFGeneric; break;
|
|
case 1:
|
|
override_function = ElementData::TFPhase; break;
|
|
case 2:
|
|
override_function = ElementData::TFNeutral; break;
|
|
default:
|
|
override_function = ElementData::TFGeneric; break;
|
|
}
|
|
m_model->setData(function_index, override_function);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FreeTerminalEditor::on_m_led_cb_activated(int index)
|
|
{
|
|
if (m_model)
|
|
{
|
|
const auto index_list = ui->m_table_view->selectionModel()->selectedIndexes();
|
|
|
|
for (auto model_index : index_list)
|
|
{
|
|
auto led_index = m_model->index(model_index.row(), FreeTerminalModel::Led, model_index.parent());
|
|
|
|
if (led_index.isValid()) {
|
|
m_model->setData(led_index,
|
|
index == 0 ? false : true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FreeTerminalEditor::on_m_move_pb_clicked()
|
|
{
|
|
//Get the selected real terminal
|
|
const auto index_list = ui->m_table_view->selectionModel()->selectedIndexes();
|
|
const auto real_t_vector = m_model->realTerminalForIndex(index_list);
|
|
if (real_t_vector.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
//Get the terminal strip who receive the real terminal
|
|
const auto strip_uuid = ui->m_move_in_cb->currentData().toUuid();
|
|
TerminalStrip *terminal_strip{nullptr};
|
|
for (const auto &strip : m_project->terminalStrip()) {
|
|
if (strip->uuid() == strip_uuid) {
|
|
terminal_strip = strip;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!terminal_strip) {
|
|
return;
|
|
}
|
|
|
|
m_project->undoStack()->push(new AddTerminalToStripCommand(real_t_vector, terminal_strip));
|
|
|
|
reload();
|
|
}
|
|
|
|
void FreeTerminalEditor::selectionChanged()
|
|
{
|
|
const bool has_selection = !ui->m_table_view->selectionModel()->selectedIndexes().isEmpty();
|
|
const bool has_pending = !m_model->modifiedModelRealTerminalData().isEmpty();
|
|
setDisabledMove(!has_selection || has_pending);
|
|
}
|
|
|
|
void FreeTerminalEditor::setDisabledMove(bool b)
|
|
{
|
|
ui->m_move_label->setDisabled(b);
|
|
ui->m_move_in_cb->setDisabled(b);
|
|
ui->m_move_pb->setDisabled(b);
|
|
ui->m_move_pb->setToolTip(b ? tr("Apply or discard pending edits before moving")
|
|
: tr("Move selected terminals to the chosen terminal strip"));
|
|
}
|
|
|