Editable counter value in the dock, and fix two bugs in the reset button

Follows @scorpio810's review on PR #626 and three defects found by finally
running the thing rather than only building it.

Replace the "?" button with an editable value field, as asked for. It shows
the current value of the context's counter -- the last part that actually
progresses, i.e. the least significant digit -- and typing a new value and
committing it writes that value back. This is strictly more useful than the
button it replaces: "?" is still reachable by typing it, and any other value
is now reachable too, which was the point of the request.

It also removes a destructive edge the button had: "reset to ?" rewrote
*every* part, so a scheme built as "K" + counter became "?????" and the
configured prefix was gone for good. There is no undo command for
numbering contexts.

Two bugs fixed in the reset path itself:

- The project was never marked modified. addConductorAutoNum() and friends
  are a plain insert into a QMap; they emit nothing and set no dirty flag,
  and the properties dialog that this code was modelled on calls
  setModified(true) separately afterwards. Without it the user resets a
  counter, closes the project, is not asked to save, and the reset is lost.
  Verified before the fix: projectWasModified() stayed false across a click.

- A wrap part was reset to "1". A modulo part cycles over [0, modulus) --
  the PLC addressing that motivated the feature runs %IX0.0..%IX0.31 -- so
  its starting value is 0, not 1.

An empty value field is treated as "no change" rather than as an empty
value, so clearing the box by accident cannot wipe a counter, and the field
is refreshed from the context after every write and whenever the selected
context changes.
This commit is contained in:
ispyisail
2026-08-02 18:33:14 +12:00
parent 031710b5fc
commit 52c8ef6b49
3 changed files with 185 additions and 77 deletions
+155 -51
View File
@@ -27,6 +27,7 @@
#include "ui_autonumberingdockwidget.h"
#include <QComboBox>
#include <QLineEdit>
/**
@brief AutoNumberingDockWidget::AutoNumberingDockWidget
@@ -60,6 +61,9 @@ void AutoNumberingDockWidget::clear()
ui->m_conductor_cb->clear();
ui->m_element_cb->clear();
ui->m_folio_cb->clear();
ui->m_conductor_value_le->clear();
ui->m_element_value_le->clear();
ui->m_folio_value_le->clear();
}
void AutoNumberingDockWidget::projectClosed()
@@ -191,6 +195,12 @@ void AutoNumberingDockWidget::setContext()
{ ui->m_folio_cb -> addItem(str);}
}
//The combo boxes have just been repopulated, so the value fields next
//to them are showing whatever the previous project left there.
refreshValueField(ui->m_conductor_cb, ui->m_conductor_value_le, AutoNumCategory::Conductor);
refreshValueField(ui->m_element_cb, ui->m_element_value_le, AutoNumCategory::Element);
refreshValueField(ui->m_folio_cb, ui->m_folio_value_le, AutoNumCategory::Folio);
this->setActive();
}
@@ -265,6 +275,7 @@ void AutoNumberingDockWidget::on_m_conductor_cb_activated(int)
m_project->setCurrentConductorAutoNum(current_autonum);
m_project_view->currentDiagram()->diagram()->setConductorsAutonumName(current_autonum);
m_project_view->currentDiagram()->diagram()->loadCndFolioSeq();
refreshValueField(ui->m_conductor_cb, ui->m_conductor_value_le, AutoNumCategory::Conductor);
}
/**
@@ -293,6 +304,7 @@ void AutoNumberingDockWidget::on_m_element_cb_activated(int)
{
m_project->setCurrrentElementAutonum(ui->m_element_cb->currentText());
m_project_view->currentDiagram()->diagram()->loadElmtFolioSeq();
refreshValueField(ui->m_element_cb, ui->m_element_value_le, AutoNumCategory::Element);
}
/**
@@ -330,6 +342,7 @@ void AutoNumberingDockWidget::on_m_folio_cb_activated(int) {
m_project->setDefaultTitleBlockProperties(ip);
}
emit(folioAutoNumChanged(current_autonum));
refreshValueField(ui->m_folio_cb, ui->m_folio_value_le, AutoNumCategory::Folio);
}
void AutoNumberingDockWidget::on_m_configure_pb_clicked()
@@ -344,74 +357,162 @@ void AutoNumberingDockWidget::on_m_configure_pb_clicked()
void AutoNumberingDockWidget::on_m_conductor_reset_start_pb_clicked()
{
resetAutoNum(ui->m_conductor_cb, AutoNumCategory::Conductor, false);
}
void AutoNumberingDockWidget::on_m_conductor_reset_placeholder_pb_clicked()
{
resetAutoNum(ui->m_conductor_cb, AutoNumCategory::Conductor, true);
resetAutoNum(ui->m_conductor_cb, AutoNumCategory::Conductor);
}
void AutoNumberingDockWidget::on_m_element_reset_start_pb_clicked()
{
resetAutoNum(ui->m_element_cb, AutoNumCategory::Element, false);
}
void AutoNumberingDockWidget::on_m_element_reset_placeholder_pb_clicked()
{
resetAutoNum(ui->m_element_cb, AutoNumCategory::Element, true);
resetAutoNum(ui->m_element_cb, AutoNumCategory::Element);
}
void AutoNumberingDockWidget::on_m_folio_reset_start_pb_clicked()
{
resetAutoNum(ui->m_folio_cb, AutoNumCategory::Folio, false);
resetAutoNum(ui->m_folio_cb, AutoNumCategory::Folio);
}
void AutoNumberingDockWidget::on_m_folio_reset_placeholder_pb_clicked()
void AutoNumberingDockWidget::on_m_conductor_value_le_editingFinished()
{
resetAutoNum(ui->m_folio_cb, AutoNumCategory::Folio, true);
applyValueField(ui->m_conductor_cb, ui->m_conductor_value_le, AutoNumCategory::Conductor);
}
void AutoNumberingDockWidget::on_m_element_value_le_editingFinished()
{
applyValueField(ui->m_element_cb, ui->m_element_value_le, AutoNumCategory::Element);
}
void AutoNumberingDockWidget::on_m_folio_value_le_editingFinished()
{
applyValueField(ui->m_folio_cb, ui->m_folio_value_le, AutoNumCategory::Folio);
}
/**
@brief AutoNumberingDockWidget::resetAutoNum
Reset the numerotation context currently selected in combo_box (for
category) either to a per-type starting value (to_placeholder = false)
or to the literal placeholder "?" on every part (to_placeholder =
true), then write it back so the existing refresh signals fire as
normal. Does nothing if no context is selected.
"Reset to start" only touches parts that actually represent a
progressing counter (numeric types, wrap, alpha): folio-anchored
numeric types go back to their own stored initialvalue, plain numeric
types and wrap go back to "1", alpha goes back to "a". Non-incrementing
types (string, plant, locmach, idfolio, folio, elementline,
elementcolumn, elementprefix) are left untouched -- there's no
meaningful "start" distinct from whatever the user configured for a
fixed/contextual value. "Reset to ?" applies to every part
unconditionally, since its purpose is marking the whole context as
needing manual attention.
@brief AutoNumberingDockWidget::contextFor
@return the numerotation context named by combo_box, for category
*/
void AutoNumberingDockWidget::resetAutoNum(QComboBox *combo_box, AutoNumCategory category, bool to_placeholder)
NumerotationContext AutoNumberingDockWidget::contextFor(QComboBox *combo_box, AutoNumCategory category) const
{
const QString key = combo_box->currentText();
switch (category) {
case AutoNumCategory::Conductor: return m_project->conductorAutoNum(key);
case AutoNumCategory::Element: return m_project->elementAutoNum(key);
case AutoNumCategory::Folio: return m_project->folioAutoNum(key);
}
return NumerotationContext();
}
/**
@brief AutoNumberingDockWidget::storeContext
Write context back under the name selected in combo_box and flag the
project as modified -- without that last step the change is not saved
and the user is never asked to save it on close.
*/
void AutoNumberingDockWidget::storeContext(QComboBox *combo_box, AutoNumCategory category, const NumerotationContext &context)
{
const QString key = combo_box->currentText();
switch (category) {
case AutoNumCategory::Conductor: m_project->addConductorAutoNum(key, context); break;
case AutoNumCategory::Element: m_project->addElementAutoNum(key, context); break;
case AutoNumCategory::Folio: m_project->addFolioAutoNum(key, context); break;
}
m_project->setModified(true);
}
/**
@brief AutoNumberingDockWidget::counterIndex
@return the index of the part the value field shows: the last one that
actually progresses, i.e. the least significant digit of the number.
-1 when the context has no progressing part at all.
*/
int AutoNumberingDockWidget::counterIndex(const NumerotationContext &context)
{
for (int i = context.size() - 1 ; i >= 0 ; --i)
{
const QString type = context.itemAt(i).at(0);
if (type == QLatin1String("unit")
|| type == QLatin1String("ten")
|| type == QLatin1String("hundred")
|| type == QLatin1String("unitfolio")
|| type == QLatin1String("tenfolio")
|| type == QLatin1String("hundredfolio")
|| type == QLatin1String("wrap")
|| type == QLatin1String("alpha"))
return i;
}
return -1;
}
/**
@brief AutoNumberingDockWidget::refreshValueField
Show the current value of the selected context's counter, so the field
always reflects where the numbering has actually got to.
*/
void AutoNumberingDockWidget::refreshValueField(QComboBox *combo_box, QLineEdit *line_edit, AutoNumCategory category)
{
if (!m_project || combo_box->currentText().isEmpty())
{
line_edit->clear();
line_edit->setEnabled(false);
return;
}
const NumerotationContext context = contextFor(combo_box, category);
const int index = counterIndex(context);
line_edit->setEnabled(index >= 0);
line_edit->setText(index >= 0 ? context.itemAt(index).at(1) : QString());
}
/**
@brief AutoNumberingDockWidget::applyValueField
Write the value typed in line_edit to the counter it displays. An empty
field is treated as "no change" rather than as an empty value, so
clearing the box by accident cannot wipe the counter.
*/
void AutoNumberingDockWidget::applyValueField(QComboBox *combo_box, QLineEdit *line_edit, AutoNumCategory category)
{
if (!m_project || combo_box->currentText().isEmpty())
return;
const QString key = combo_box->currentText();
NumerotationContext context;
switch (category) {
case AutoNumCategory::Conductor: context = m_project->conductorAutoNum(key); break;
case AutoNumCategory::Element: context = m_project->elementAutoNum(key); break;
case AutoNumCategory::Folio: context = m_project->folioAutoNum(key); break;
NumerotationContext context = contextFor(combo_box, category);
const int index = counterIndex(context);
if (index < 0)
return;
const QString typed = line_edit->text();
if (typed.isEmpty() || typed == context.itemAt(index).at(1))
{
refreshValueField(combo_box, line_edit, category);
return;
}
for (int i = 0; i < context.size(); ++i)
{
if (to_placeholder)
{
context.replaceValue(i, QStringLiteral("?"));
continue;
}
context.replaceValue(index, typed);
storeContext(combo_box, category, context);
refreshValueField(combo_box, line_edit, category);
}
/**
@brief AutoNumberingDockWidget::resetAutoNum
Reset the numerotation context currently selected in combo_box back to
a per-type starting value, then write it back. Does nothing if no
context is selected.
Only parts that actually progress are touched: folio-anchored numeric
types go back to their own stored initialvalue, plain numeric types go
back to "1", a wrap part goes back to "0" because a modulo counter
cycles over [0, modulus) -- a PLC card addressed %IX0.0..%IX0.31 starts
at 0, not 1 -- and alpha goes back to "a". Non-incrementing types
(string, plant, locmach, idfolio, folio, elementline, elementcolumn,
elementprefix) are left alone: there is no "start" for them distinct
from the fixed or contextual value the user configured.
*/
void AutoNumberingDockWidget::resetAutoNum(QComboBox *combo_box, AutoNumCategory category)
{
if (!m_project || combo_box->currentText().isEmpty())
return;
NumerotationContext context = contextFor(combo_box, category);
for (int i = 0 ; i < context.size() ; ++i)
{
const QStringList item = context.itemAt(i);
const QString &type = item.at(0);
if (type == QLatin1String("unitfolio")
@@ -420,16 +521,19 @@ void AutoNumberingDockWidget::resetAutoNum(QComboBox *combo_box, AutoNumCategory
context.replaceValue(i, item.size() > 3 ? item.at(3) : QStringLiteral("1"));
else if (type == QLatin1String("unit")
|| type == QLatin1String("ten")
|| type == QLatin1String("hundred")
|| type == QLatin1String("wrap"))
|| type == QLatin1String("hundred"))
context.replaceValue(i, QStringLiteral("1"));
else if (type == QLatin1String("wrap"))
context.replaceValue(i, QStringLiteral("0"));
else if (type == QLatin1String("alpha"))
context.replaceValue(i, QStringLiteral("a"));
}
storeContext(combo_box, category, context);
switch (category) {
case AutoNumCategory::Conductor: m_project->addConductorAutoNum(key, context); break;
case AutoNumCategory::Element: m_project->addElementAutoNum(key, context); break;
case AutoNumCategory::Folio: m_project->addFolioAutoNum(key, context); break;
case AutoNumCategory::Conductor: refreshValueField(combo_box, ui->m_conductor_value_le, category); break;
case AutoNumCategory::Element: refreshValueField(combo_box, ui->m_element_value_le, category); break;
case AutoNumCategory::Folio: refreshValueField(combo_box, ui->m_folio_value_le, category); break;
}
}
+21 -8
View File
@@ -24,6 +24,7 @@
#include <QDockWidget>
class QComboBox;
class QLineEdit;
namespace Ui {
class AutoNumberingDockWidget;
@@ -57,11 +58,12 @@ class AutoNumberingDockWidget : public QDockWidget
void on_m_configure_pb_clicked();
void on_m_conductor_reset_start_pb_clicked();
void on_m_conductor_reset_placeholder_pb_clicked();
void on_m_element_reset_start_pb_clicked();
void on_m_element_reset_placeholder_pb_clicked();
void on_m_folio_reset_start_pb_clicked();
void on_m_folio_reset_placeholder_pb_clicked();
void on_m_conductor_value_le_editingFinished();
void on_m_element_value_le_editingFinished();
void on_m_folio_value_le_editingFinished();
signals:
void folioAutoNumChanged(QString);
@@ -72,12 +74,23 @@ class AutoNumberingDockWidget : public QDockWidget
/**
@brief resetAutoNum
Reset the numerotation context currently selected in combo_box
(for the given category) either to a per-type starting value
(to_placeholder = false) or to the literal placeholder "?" on
every part (to_placeholder = true). Does nothing if no context
is selected.
(for the given category) to a per-type starting value. Does
nothing if no context is selected.
*/
void resetAutoNum(QComboBox *combo_box, AutoNumCategory category, bool to_placeholder);
void resetAutoNum(QComboBox *combo_box, AutoNumCategory category);
/// Read/write the numerotation context named in combo_box.
NumerotationContext contextFor(QComboBox *combo_box, AutoNumCategory category) const;
void storeContext(QComboBox *combo_box, AutoNumCategory category, const NumerotationContext &context);
/// Index of the counter the value field shows and edits: the last
/// part that actually progresses. Returns -1 when the context has
/// no such part (e.g. it is only fixed text).
static int counterIndex(const NumerotationContext &context);
/// Refresh a value field from its context, and apply a typed value.
void refreshValueField(QComboBox *combo_box, QLineEdit *line_edit, AutoNumCategory category);
void applyValueField(QComboBox *combo_box, QLineEdit *line_edit, AutoNumCategory category);
Ui::AutoNumberingDockWidget *ui;
QETProject* m_project = nullptr;
+9 -18
View File
@@ -49,18 +49,15 @@
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="m_conductor_reset_placeholder_pb">
<widget class="QLineEdit" name="m_conductor_value_le">
<property name="maximumSize">
<size>
<width>24</width>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Réinitialiser à « ? » (à numéroter manuellement)</string>
</property>
<property name="text">
<string>?</string>
<string>Valeur actuelle du compteur. Saisir une nouvelle valeur et valider pour la modifier.</string>
</property>
</widget>
</item>
@@ -99,18 +96,15 @@
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="m_element_reset_placeholder_pb">
<widget class="QLineEdit" name="m_element_value_le">
<property name="maximumSize">
<size>
<width>24</width>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Réinitialiser à « ? » (à numéroter manuellement)</string>
</property>
<property name="text">
<string>?</string>
<string>Valeur actuelle du compteur. Saisir une nouvelle valeur et valider pour la modifier.</string>
</property>
</widget>
</item>
@@ -138,18 +132,15 @@
</widget>
</item>
<item row="4" column="3">
<widget class="QPushButton" name="m_folio_reset_placeholder_pb">
<widget class="QLineEdit" name="m_folio_value_le">
<property name="maximumSize">
<size>
<width>24</width>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Réinitialiser à « ? » (à numéroter manuellement)</string>
</property>
<property name="text">
<string>?</string>
<string>Valeur actuelle du compteur. Saisir une nouvelle valeur et valider pour la modifier.</string>
</property>
</widget>
</item>