Merge pull request #697 from ispyisail/feature/autonum-inline-increment

Edit increment and preview the next number in the auto-numbering dock (bugtracker #331)
This commit is contained in:
Laurent Trinques
2026-08-08 13:53:23 +02:00
committed by GitHub
5 changed files with 403 additions and 25 deletions
+45
View File
@@ -220,6 +220,24 @@ void NumerotationContext::replaceValue(int index, QString content) {
content_[index] = type + "|" + value + "|" + increase + "|" + initvalue + "|" + modulus + "|" + format;
}
/**
@brief NumerotationContext::replaceIncrease
Change how much this part advances per step, leaving its current value,
initial value, modulus and format untouched. Sibling to replaceValue(),
which deliberately never touches this field.
@param index of NC item
@param increase new increase for that item
*/
void NumerotationContext::replaceIncrease(int index, int increase) {
QStringList strl = content_[index].split("|");
QString type = strl.at(0);
QString value = strl.at(1);
QString initvalue = strl.at(3);
QString modulus = strl.size() > 4 ? strl.at(4) : QStringLiteral("0");
QString format = strl.size() > 5 ? strl.at(5) : QString();
content_[index] = type + "|" + value + "|" + QString::number(increase) + "|" + initvalue + "|" + modulus + "|" + format;
}
/**
@brief NumerotationContext::formatOf
@param item : a context item as returned by itemAt()
@@ -230,3 +248,30 @@ QString NumerotationContext::formatOf(const QStringList &item)
{
return item.size() > 5 ? item.at(5) : QString();
}
/**
@brief NumerotationContext::formatValue
@param item : a context item as returned by itemAt()
@return the part's value, zero-padded exactly as
autonum::setSequentialToList() pads it when composing a real label: an
explicit format mask wins, then "ten"/"hundred" parts get their
implicit 2/3-digit width, "alpha" is used as-is, everything else is a
plain number. Kept in step with that function by hand since the two
cannot share code without exposing an assignvariables.cpp-local helper.
*/
QString NumerotationContext::formatValue(const QStringList &item)
{
const QString &type = item.at(0);
const QString &value = item.at(1);
if (type == QLatin1String("alpha"))
return value;
const QString mask = formatOf(item);
if (!mask.isEmpty())
return QString("%1").arg(value.toInt(), mask.length(), 10, QChar('0'));
if (type == QLatin1String("ten") || type == QLatin1String("tenfolio"))
return QString("%1").arg(value.toInt(), 2, 10, QChar('0'));
if (type == QLatin1String("hundred") || type == QLatin1String("hundredfolio"))
return QString("%1").arg(value.toInt(), 3, 10, QChar('0'));
return QString::number(value.toInt());
}
+5
View File
@@ -54,6 +54,11 @@ class NumerotationContext
QDomElement toXml(QDomDocument &, const QString&);
void fromXml(QDomElement &);
void replaceValue(int, QString);
void replaceIncrease(int, int);
/// Zero-pad a part's value the same way the real numbering engine
/// does (autonum::setSequentialToList in assignvariables.cpp), so a
/// UI preview of a part's value matches what actually gets rendered.
static QString formatValue(const QStringList &item);
private:
QStringList content_;
+166 -25
View File
@@ -24,10 +24,13 @@
#include "../../titleblockproperties.h"
#include "../../ui/projectpropertiesdialog.h"
#include "../numerotationcontext.h"
#include "../numerotationcontextcommands.h"
#include "ui_autonumberingdockwidget.h"
#include <QComboBox>
#include <QLineEdit>
#include <QSignalBlocker>
#include <QSpinBox>
/**
@brief AutoNumberingDockWidget::AutoNumberingDockWidget
@@ -64,6 +67,29 @@ void AutoNumberingDockWidget::clear()
ui->m_conductor_value_le->clear();
ui->m_element_value_le->clear();
ui->m_folio_value_le->clear();
ui->m_conductor_next_le->clear();
ui->m_element_next_le->clear();
ui->m_folio_next_le->clear();
}
/**
@brief AutoNumberingDockWidget::rowFor
@return the combo/value/increase/next widgets that make up category's row.
*/
AutoNumberingDockWidget::Row AutoNumberingDockWidget::rowFor(AutoNumCategory category) const
{
switch (category) {
case AutoNumCategory::Conductor:
return {ui->m_conductor_cb, ui->m_conductor_value_le,
ui->m_conductor_increase_sb, ui->m_conductor_next_le};
case AutoNumCategory::Element:
return {ui->m_element_cb, ui->m_element_value_le,
ui->m_element_increase_sb, ui->m_element_next_le};
case AutoNumCategory::Folio:
return {ui->m_folio_cb, ui->m_folio_value_le,
ui->m_folio_increase_sb, ui->m_folio_next_le};
}
return {nullptr, nullptr, nullptr, nullptr};
}
void AutoNumberingDockWidget::projectClosed()
@@ -201,9 +227,9 @@ void AutoNumberingDockWidget::setContext()
//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);
refreshRow(AutoNumCategory::Conductor);
refreshRow(AutoNumCategory::Element);
refreshRow(AutoNumCategory::Folio);
this->setActive();
}
@@ -279,7 +305,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);
refreshRow(AutoNumCategory::Conductor);
}
/**
@@ -308,7 +334,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);
refreshRow(AutoNumCategory::Element);
}
/**
@@ -346,7 +372,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);
refreshRow(AutoNumCategory::Folio);
}
void AutoNumberingDockWidget::on_m_configure_pb_clicked()
@@ -389,6 +415,21 @@ void AutoNumberingDockWidget::on_m_folio_value_le_editingFinished()
applyValueField(ui->m_folio_cb, ui->m_folio_value_le, AutoNumCategory::Folio);
}
void AutoNumberingDockWidget::on_m_conductor_increase_sb_valueChanged(int)
{
applyIncreaseField(ui->m_conductor_cb, ui->m_conductor_increase_sb, AutoNumCategory::Conductor);
}
void AutoNumberingDockWidget::on_m_element_increase_sb_valueChanged(int)
{
applyIncreaseField(ui->m_element_cb, ui->m_element_increase_sb, AutoNumCategory::Element);
}
void AutoNumberingDockWidget::on_m_folio_increase_sb_valueChanged(int)
{
applyIncreaseField(ui->m_folio_cb, ui->m_folio_increase_sb, AutoNumCategory::Folio);
}
/**
@brief AutoNumberingDockWidget::contextFor
@return the numerotation context named by combo_box, for category
@@ -455,17 +496,21 @@ int AutoNumberingDockWidget::counterIndex(const NumerotationContext &context)
*/
void AutoNumberingDockWidget::refreshValueFields()
{
//Leave alone a field the user is typing in: numbering an element
//refreshes all three, and overwriting a half-typed value under the
//cursor is worse than showing it a moment out of date. Only this
//automatic path skips; an explicit refresh after a reset or an edit
//still writes, so the field always ends up canonical.
if (!ui->m_conductor_value_le->hasFocus())
refreshValueField(ui->m_conductor_cb, ui->m_conductor_value_le, AutoNumCategory::Conductor);
if (!ui->m_element_value_le->hasFocus())
refreshValueField(ui->m_element_cb, ui->m_element_value_le, AutoNumCategory::Element);
if (!ui->m_folio_value_le->hasFocus())
refreshValueField(ui->m_folio_cb, ui->m_folio_value_le, AutoNumCategory::Folio);
//Leave alone a row the user is typing in: numbering an element
//refreshes all three rows, and overwriting a half-typed value or
//increment under the cursor is worse than showing it a moment out
//of date. Only this automatic path skips; an explicit refresh after
//a reset or an edit still writes, so the row always ends up
//canonical. The next-value preview has no such guard: it is
//read-only, so there is nothing a refresh could clobber.
for (AutoNumCategory category : {AutoNumCategory::Conductor,
AutoNumCategory::Element,
AutoNumCategory::Folio})
{
const Row row = rowFor(category);
if (!row.value->hasFocus() && !row.increase->hasFocus())
refreshRow(category);
}
}
/**
@@ -507,13 +552,114 @@ void AutoNumberingDockWidget::applyValueField(QComboBox *combo_box, QLineEdit *l
const QString typed = line_edit->text();
if (typed.isEmpty() || typed == context.itemAt(index).at(1))
{
refreshValueField(combo_box, line_edit, category);
refreshRow(category);
return;
}
context.replaceValue(index, typed);
storeContext(combo_box, category, context);
refreshValueField(combo_box, line_edit, category);
refreshRow(category);
}
/**
@brief AutoNumberingDockWidget::refreshIncreaseField
Show the counter's current step size (bug #331: previously only
reachable from the full configuration dialog, via "Configurer").
*/
void AutoNumberingDockWidget::refreshIncreaseField(QComboBox *combo_box, QSpinBox *increase_sb, AutoNumCategory category)
{
//QSpinBox::setValue() emits valueChanged() even when called
//programmatically. Without blocking it, this refresh would
//immediately re-trigger on_..._increase_sb_valueChanged() ->
//applyIncreaseField() -> storeContext() -> the project's
//autoNumContextUpdated signal -> refreshValueFields() -> back here.
const QSignalBlocker blocker(increase_sb);
if (!m_project || combo_box->currentText().isEmpty())
{
increase_sb->setEnabled(false);
increase_sb->setValue(increase_sb->minimum());
return;
}
const NumerotationContext context = contextFor(combo_box, category);
const int index = counterIndex(context);
increase_sb->setEnabled(index >= 0);
increase_sb->setValue(index >= 0 ? context.itemAt(index).at(2).toInt()
: increase_sb->minimum());
}
/**
@brief AutoNumberingDockWidget::applyIncreaseField
Write the spin box's step size to the counter it displays (bug #331).
*/
void AutoNumberingDockWidget::applyIncreaseField(QComboBox *combo_box, QSpinBox *increase_sb, AutoNumCategory category)
{
if (!m_project || combo_box->currentText().isEmpty())
return;
NumerotationContext context = contextFor(combo_box, category);
const int index = counterIndex(context);
if (index < 0)
return;
if (increase_sb->value() == context.itemAt(index).at(2).toInt())
return;
context.replaceIncrease(index, increase_sb->value());
storeContext(combo_box, category, context);
refreshRow(category);
}
/**
@brief AutoNumberingDockWidget::refreshNextField
Show what this counter will read after one more step (bug #331: "visualiser
la prochaine numérotation qui sera appliquée"). Advances a copy of the
whole context through NumerotationContextCommands -- the same engine the
Suivant button in the full configuration dialog uses to step a context --
so wrap-and-carry into this part from a following part, or out of it into
a preceding one, comes out identical to what will actually happen when the
number is next consumed.
*/
void AutoNumberingDockWidget::refreshNextField(QComboBox *combo_box, QLineEdit *next_edit, AutoNumCategory category)
{
if (!m_project || combo_box->currentText().isEmpty())
{
next_edit->clear();
next_edit->setEnabled(false);
return;
}
const NumerotationContext context = contextFor(combo_box, category);
const int index = counterIndex(context);
if (index < 0)
{
next_edit->clear();
next_edit->setEnabled(false);
return;
}
Diagram *diagram = (m_project_view && m_project_view->currentDiagram())
? m_project_view->currentDiagram()->diagram()
: nullptr;
NumerotationContextCommands ncc(context, diagram);
const NumerotationContext next_context = ncc.next();
next_edit->setEnabled(true);
next_edit->setText(NumerotationContext::formatValue(next_context.itemAt(index)));
}
/**
@brief AutoNumberingDockWidget::refreshRow
Refresh a category's value, increment and next-value preview together --
every call site that used to refresh just the value field needs the
other two kept in step with it as well.
*/
void AutoNumberingDockWidget::refreshRow(AutoNumCategory category)
{
const Row row = rowFor(category);
refreshValueField(row.combo, row.value, category);
refreshIncreaseField(row.combo, row.increase, category);
refreshNextField(row.combo, row.next, category);
}
/**
@@ -557,10 +703,5 @@ void AutoNumberingDockWidget::resetAutoNum(QComboBox *combo_box, AutoNumCategory
}
storeContext(combo_box, category, context);
switch (category) {
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;
}
refreshRow(category);
}
@@ -25,6 +25,7 @@
class QComboBox;
class QLineEdit;
class QSpinBox;
namespace Ui {
class AutoNumberingDockWidget;
@@ -66,12 +67,28 @@ class AutoNumberingDockWidget : public QDockWidget
void on_m_element_value_le_editingFinished();
void on_m_folio_value_le_editingFinished();
void on_m_conductor_increase_sb_valueChanged(int);
void on_m_element_increase_sb_valueChanged(int);
void on_m_folio_increase_sb_valueChanged(int);
signals:
void folioAutoNumChanged(QString);
private:
enum class AutoNumCategory { Conductor, Element, Folio };
/// The four widgets that make up one category's row, bundled so
/// refreshRow() can be called with just a category instead of
/// four pointers that must always be passed in matching sets.
struct Row
{
QComboBox *combo;
QLineEdit *value;
QSpinBox *increase;
QLineEdit *next;
};
Row rowFor(AutoNumCategory category) const;
/**
@brief resetAutoNum
Reset the numerotation context currently selected in combo_box
@@ -93,6 +110,23 @@ class AutoNumberingDockWidget : public QDockWidget
void refreshValueField(QComboBox *combo_box, QLineEdit *line_edit, AutoNumCategory category);
void applyValueField(QComboBox *combo_box, QLineEdit *line_edit, AutoNumCategory category);
/// Refresh/apply the increment spin box the same way.
void refreshIncreaseField(QComboBox *combo_box, QSpinBox *increase_sb, AutoNumCategory category);
void applyIncreaseField(QComboBox *combo_box, QSpinBox *increase_sb, AutoNumCategory category);
/// Show what the counter will read after one more step, using
/// the same NumerotationContextCommands engine the Suivant
/// button in the full configuration dialog already advances
/// the whole context with -- so the preview can never disagree
/// with what actually happens when the number is next consumed.
void refreshNextField(QComboBox *combo_box, QLineEdit *next_edit, AutoNumCategory category);
/// Refresh a whole row -- value, increment and next-value
/// preview -- in one call. Every refresh call site needs the
/// increment and preview kept in step with the value now, so
/// this replaces refreshValueField() at each of them.
void refreshRow(AutoNumCategory category);
Ui::AutoNumberingDockWidget *ui;
QETProject* m_project = nullptr;
ProjectView* m_project_view = nullptr;
@@ -15,6 +15,36 @@
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="3">
<widget class="QLabel" name="value_header_label">
<property name="text">
<string>Valeur</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="increase_header_label">
<property name="text">
<string>Incrément</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="next_header_label">
<property name="text">
<string>Suivant</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="m_element_cb"/>
</item>
@@ -61,6 +91,47 @@
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QSpinBox" name="m_conductor_increase_sb">
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Incrément : valeur ajoutée au compteur à chaque nouvelle numérotation</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="accelerated">
<bool>true</bool>
</property>
<property name="minimum">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QLineEdit" name="m_conductor_next_le">
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Prochaine valeur qui sera appliquée avec cet incrément</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
@@ -108,6 +179,47 @@
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QSpinBox" name="m_element_increase_sb">
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Incrément : valeur ajoutée au compteur à chaque nouvelle numérotation</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="accelerated">
<bool>true</bool>
</property>
<property name="minimum">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="5">
<widget class="QLineEdit" name="m_element_next_le">
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Prochaine valeur qui sera appliquée avec cet incrément</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="m_folio_cb"/>
</item>
@@ -144,6 +256,47 @@
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QSpinBox" name="m_folio_increase_sb">
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Incrément : valeur ajoutée au compteur à chaque nouvelle numérotation</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="accelerated">
<bool>true</bool>
</property>
<property name="minimum">
<number>0</number>
</property>
</widget>
</item>
<item row="4" column="5">
<widget class="QLineEdit" name="m_folio_next_le">
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Prochaine valeur qui sera appliquée avec cet incrément</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer">
<property name="orientation">