diff --git a/sources/autoNum/numerotationcontext.cpp b/sources/autoNum/numerotationcontext.cpp index a8f3b11f4..3355a1bb4 100644 --- a/sources/autoNum/numerotationcontext.cpp +++ b/sources/autoNum/numerotationcontext.cpp @@ -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()); +} diff --git a/sources/autoNum/numerotationcontext.h b/sources/autoNum/numerotationcontext.h index f53c42751..b1575e468 100644 --- a/sources/autoNum/numerotationcontext.h +++ b/sources/autoNum/numerotationcontext.h @@ -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_; diff --git a/sources/autoNum/ui/autonumberingdockwidget.cpp b/sources/autoNum/ui/autonumberingdockwidget.cpp index 664a00e90..080126d6c 100644 --- a/sources/autoNum/ui/autonumberingdockwidget.cpp +++ b/sources/autoNum/ui/autonumberingdockwidget.cpp @@ -24,10 +24,13 @@ #include "../../titleblockproperties.h" #include "../../ui/projectpropertiesdialog.h" #include "../numerotationcontext.h" +#include "../numerotationcontextcommands.h" #include "ui_autonumberingdockwidget.h" #include #include +#include +#include /** @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); } diff --git a/sources/autoNum/ui/autonumberingdockwidget.h b/sources/autoNum/ui/autonumberingdockwidget.h index cdfb9f08e..5e86610e1 100644 --- a/sources/autoNum/ui/autonumberingdockwidget.h +++ b/sources/autoNum/ui/autonumberingdockwidget.h @@ -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; diff --git a/sources/autoNum/ui/autonumberingdockwidget.ui b/sources/autoNum/ui/autonumberingdockwidget.ui index 578a475b1..4fcd61901 100644 --- a/sources/autoNum/ui/autonumberingdockwidget.ui +++ b/sources/autoNum/ui/autonumberingdockwidget.ui @@ -15,6 +15,36 @@ + + + + Valeur + + + Qt::AlignCenter + + + + + + + Incrément + + + Qt::AlignCenter + + + + + + + Suivant + + + Qt::AlignCenter + + + @@ -61,6 +91,47 @@ + + + + + 55 + 16777215 + + + + Incrément : valeur ajoutée au compteur à chaque nouvelle numérotation + + + Qt::AlignCenter + + + true + + + 0 + + + + + + + + 70 + 16777215 + + + + Prochaine valeur qui sera appliquée avec cet incrément + + + true + + + Qt::AlignCenter + + + @@ -108,6 +179,47 @@ + + + + + 55 + 16777215 + + + + Incrément : valeur ajoutée au compteur à chaque nouvelle numérotation + + + Qt::AlignCenter + + + true + + + 0 + + + + + + + + 70 + 16777215 + + + + Prochaine valeur qui sera appliquée avec cet incrément + + + true + + + Qt::AlignCenter + + + @@ -144,6 +256,47 @@ + + + + + 55 + 16777215 + + + + Incrément : valeur ajoutée au compteur à chaque nouvelle numérotation + + + Qt::AlignCenter + + + true + + + 0 + + + + + + + + 70 + 16777215 + + + + Prochaine valeur qui sera appliquée avec cet incrément + + + true + + + Qt::AlignCenter + + +