diff --git a/sources/autoNum/numerotationcontext.cpp b/sources/autoNum/numerotationcontext.cpp index 28702eefb..1fb4110be 100644 --- a/sources/autoNum/numerotationcontext.cpp +++ b/sources/autoNum/numerotationcontext.cpp @@ -51,12 +51,14 @@ void NumerotationContext::clear () @param value the value itself @param increase the increase number of value @param initialvalue + @param modulus wrap-and-carry modulus (0 means "not a wrapping part") @return true if value is append */ bool NumerotationContext::addValue(const QString &type, const QVariant &value, const int increase, - const int initialvalue) { + const int initialvalue, + const int modulus) { if (!keyIsAcceptable(type) && !value.canConvert()) return false; if (keyIsNumber(type) && !value.canConvert()) @@ -70,7 +72,9 @@ bool NumerotationContext::addValue(const QString &type, + "|" + QString::number(increase) + "|" - + QString::number(initialvalue); + + QString::number(initialvalue) + + "|" + + QString::number(modulus); return true; } @@ -125,7 +129,7 @@ QStringList NumerotationContext::itemAt(const int i) const */ QString NumerotationContext::validRegExpNum () const { - return ("unit|unitfolio|ten|tenfolio|hundred|hundredfolio|string|idfolio|folio|plant|locmach|elementline|elementcolumn|elementprefix"); + return ("unit|unitfolio|ten|tenfolio|hundred|hundredfolio|wrap|string|idfolio|folio|plant|locmach|elementline|elementcolumn|elementprefix"); } /** @@ -134,7 +138,7 @@ QString NumerotationContext::validRegExpNum () const */ QString NumerotationContext::validRegExpNumber() const { - return ("unit|unitfolio|ten|tenfolio|hundred|hundredfolio"); + return ("unit|unitfolio|ten|tenfolio|hundred|hundredfolio|wrap"); } /** @@ -172,6 +176,9 @@ QDomElement NumerotationContext::toXml(QDomDocument &d, const QString& str) { strl.at(0) == ("hundredfolio")) { part.setAttribute("initialvalue", strl.at(3)); } + if (strl.at(0) == ("wrap") && strl.size() > 4) { + part.setAttribute("modulus", strl.at(4)); + } num_auto.appendChild(part); } return num_auto; @@ -183,7 +190,7 @@ QDomElement NumerotationContext::toXml(QDomDocument &d, const QString& str) { */ void NumerotationContext::fromXml(QDomElement &e) { clear(); - foreach(QDomElement qde, QET::findInDomElement(e, "part")) addValue(qde.attribute("type"), qde.attribute("value"), qde.attribute("increase").toInt(), qde.attribute("initialvalue").toInt()); + foreach(QDomElement qde, QET::findInDomElement(e, "part")) addValue(qde.attribute("type"), qde.attribute("value"), qde.attribute("increase").toInt(), qde.attribute("initialvalue").toInt(), qde.attribute("modulus").toInt()); } /** @@ -193,10 +200,11 @@ void NumerotationContext::fromXml(QDomElement &e) { @param content to replace current value */ void NumerotationContext::replaceValue(int index, QString content) { - QString sep = "|"; - QString type = content_[index].split("|").at(0); + QStringList strl = content_[index].split("|"); + QString type = strl.at(0); const QString& value = std::move(content); - QString increase = content_[index].split("|").at(2); - QString initvalue = content_[index].split("|").at(3); - content_[index].replace(content_[index], type + "|" + value + "|" + increase + "|" + initvalue); + QString increase = strl.at(2); + QString initvalue = strl.at(3); + QString modulus = strl.size() > 4 ? strl.at(4) : QStringLiteral("0"); + content_[index] = type + "|" + value + "|" + increase + "|" + initvalue + "|" + modulus; } diff --git a/sources/autoNum/numerotationcontext.h b/sources/autoNum/numerotationcontext.h index 7720e2347..dcc0139ea 100644 --- a/sources/autoNum/numerotationcontext.h +++ b/sources/autoNum/numerotationcontext.h @@ -36,6 +36,7 @@ class NumerotationContext bool addValue(const QString &, const QVariant & = QVariant(1), const int = 1, + const int = 0, const int = 0); QString operator[] (const int &) const; void operator << (const NumerotationContext &); diff --git a/sources/autoNum/numerotationcontextcommands.cpp b/sources/autoNum/numerotationcontextcommands.cpp index 360a5874c..6e3544ffe 100644 --- a/sources/autoNum/numerotationcontextcommands.cpp +++ b/sources/autoNum/numerotationcontextcommands.cpp @@ -48,6 +48,15 @@ NumerotationContext NumerotationContextCommands::next() QStringList str = context_.itemAt(i); setNumStrategy(str.at(0)); contextnum << strategy_ -> next(context_, i); + + //Wrap-and-carry: str still holds the pre-increment value, so + //this checks the same condition WrapNum::next() used to decide + //whether to wrap its own value back to 0. + if (str.at(0) == "wrap" && str.size() > 4) { + int modulus = str.at(4).toInt(); + if (modulus > 0 && (str.at(1).toInt() + str.at(2).toInt()) >= modulus) + carry(contextnum, i - 1); + } } return contextnum; } @@ -64,10 +73,80 @@ NumerotationContext NumerotationContextCommands::previous() QStringList str = context_.itemAt(i); setNumStrategy(str.at(0)); contextnum << strategy_ -> previous(context_, i); + + if (str.at(0) == "wrap" && str.size() > 4) { + int modulus = str.at(4).toInt(); + if (modulus > 0 && (str.at(1).toInt() - str.at(2).toInt()) < 0) + borrow(contextnum, i - 1); + } } return contextnum; } +/** + @brief NumerotationContextCommands::carry + Add one unit to the nearest numeric part at or before from_index in + contextnum, skipping non-numeric parts (e.g. a "." string separator) + along the way. If that part is itself a wrap part and this pushes it + to (or past) its own modulus, it wraps back to 0 and the carry + cascades further back -- so wrap parts can be chained (e.g. seconds + wrapping into minutes wrapping into hours). + @param contextnum the context being built by next(); already contains + entries for every index <= from_index + @param from_index index to start looking from, going backwards +*/ +void NumerotationContextCommands::carry(NumerotationContext &contextnum, int from_index) +{ + for (int j = from_index; j >= 0; --j) { + QStringList strl = contextnum.itemAt(j); + if (!contextnum.keyIsNumber(strl.at(0))) + continue; + + int value = strl.at(1).toInt() + 1; + if (strl.at(0) == "wrap" && strl.size() > 4) { + int modulus = strl.at(4).toInt(); + if (modulus > 0 && value >= modulus) { + contextnum.replaceValue(j, QString::number(value - modulus)); + carry(contextnum, j - 1); + return; + } + } + contextnum.replaceValue(j, QString::number(value)); + return; + } + //No preceding numeric part: the carry has nowhere to go and is dropped, + //same as any other counter in this engine has no overflow tracking + //beyond the parts the user actually configured. +} + +/** + @brief NumerotationContextCommands::borrow + Inverse of carry(): subtract one unit from the nearest numeric part at + or before from_index. If that part is itself a wrap part and this + takes it below 0, it wraps to (modulus - 1) and the borrow cascades + further back. +*/ +void NumerotationContextCommands::borrow(NumerotationContext &contextnum, int from_index) +{ + for (int j = from_index; j >= 0; --j) { + QStringList strl = contextnum.itemAt(j); + if (!contextnum.keyIsNumber(strl.at(0))) + continue; + + int value = strl.at(1).toInt() - 1; + if (strl.at(0) == "wrap" && strl.size() > 4) { + int modulus = strl.at(4).toInt(); + if (modulus > 0 && value < 0) { + contextnum.replaceValue(j, QString::number(value + modulus)); + borrow(contextnum, j - 1); + return; + } + } + contextnum.replaceValue(j, QString::number(value)); + return; + } +} + /** @brief NumerotationContextCommands::toFinalString @return the string represented by the numerotation context @@ -117,6 +196,10 @@ void NumerotationContextCommands::setNumStrategy(const QString &str) { strategy_ = new HundredFNum (diagram_); return; } + else if (str == "wrap") { + strategy_ = new WrapNum (diagram_); + return; + } else if (str == "string") { strategy_ = new StringNum (diagram_); return; @@ -431,6 +514,62 @@ NumerotationContext HundredFNum::previous(const NumerotationContext &nc, const i return (previousNumber(nc, i)); } +/** + Constructor +*/ +WrapNum::WrapNum (Diagram *d): + NumStrategy (d) +{} + +/** + @brief WrapNum::toRepresentedString + @return the represented string of num +*/ +QString WrapNum::toRepresentedString(const QString num) const +{ + return (num); +} + +/** + @brief WrapNum::next + Wraps this part's own value back to 0 every `modulus` values (carrying + into the adjacent part is handled by NumerotationContextCommands::next(), + which has visibility into the other parts). + @return the next NumerotationContext nc at position i +*/ +NumerotationContext WrapNum::next (const NumerotationContext &nc, const int i) const +{ + QStringList strl = nc.itemAt(i); + NumerotationContext newnc; + int increase = strl.at(2).toInt(); + int modulus = strl.size() > 4 ? strl.at(4).toInt() : 0; + int new_value = strl.at(1).toInt() + increase; + if (modulus > 0) + new_value %= modulus; + newnc.addValue(strl.at(0), QString::number(new_value), increase, strl.at(3).toInt(), modulus); + return (newnc); +} + +/** + @brief WrapNum::previous + @return the previous NumerotationContext nc at posiiton i +*/ +NumerotationContext WrapNum::previous(const NumerotationContext &nc, const int i) const +{ + QStringList strl = nc.itemAt(i); + NumerotationContext newnc; + int increase = strl.at(2).toInt(); + int modulus = strl.size() > 4 ? strl.at(4).toInt() : 0; + int new_value = strl.at(1).toInt() - increase; + if (modulus > 0) { + new_value %= modulus; + if (new_value < 0) + new_value += modulus; + } + newnc.addValue(strl.at(0), QString::number(new_value), increase, strl.at(3).toInt(), modulus); + return (newnc); +} + /** Constructor */ diff --git a/sources/autoNum/numerotationcontextcommands.h b/sources/autoNum/numerotationcontextcommands.h index 46de55033..14b44d670 100644 --- a/sources/autoNum/numerotationcontextcommands.h +++ b/sources/autoNum/numerotationcontextcommands.h @@ -38,6 +38,8 @@ class NumerotationContextCommands private: void setNumStrategy (const QString &); + static void carry(NumerotationContext &contextnum, int from_index); + static void borrow(NumerotationContext &contextnum, int from_index); Diagram *diagram_; NumerotationContext context_; @@ -115,6 +117,24 @@ class HundredFNum: public NumStrategy NumerotationContext previous (const NumerotationContext &, const int) const override; }; +/** + @brief The WrapNum class + A counter that wraps back to 0 (borrowing from initialvalue on the + way down) every `modulus` values, instead of counting up forever like + UnitNum/TenNum/HundredNum. Its own next()/previous() only computes its + own wrapped value; carrying into (or borrowing from) the preceding + numeric part is handled by NumerotationContextCommands::next()/ + previous(), since only the composition loop can see adjacent parts. +*/ +class WrapNum: public NumStrategy +{ + public: + WrapNum (Diagram *); + QString toRepresentedString(const QString) const override; + NumerotationContext next (const NumerotationContext &, const int) const override; + NumerotationContext previous (const NumerotationContext &, const int) const override; +}; + class StringNum: public NumStrategy { public: diff --git a/sources/autoNum/ui/numparteditorw.cpp b/sources/autoNum/ui/numparteditorw.cpp index 6ced7db77..7ca2d2290 100644 --- a/sources/autoNum/ui/numparteditorw.cpp +++ b/sources/autoNum/ui/numparteditorw.cpp @@ -71,6 +71,8 @@ NumPartEditorW::NumPartEditorW (NumerotationContext &context, setType(NumPartEditorW::hundred, true); else if (strl.at(0)=="hundredfolio") setType(NumPartEditorW::hundredfolio, true); + else if (strl.at(0)=="wrap") + setType(NumPartEditorW::wrap, true); else if (strl.at(0)=="string") setType(NumPartEditorW::string); else if (strl.at(0)=="idfolio") @@ -89,6 +91,8 @@ NumPartEditorW::NumPartEditorW (NumerotationContext &context, setType(NumPartEditorW::elementprefix); ui -> value_field -> setText(strl.at(1)); ui -> increase_spinBox -> setValue(strl.at(2).toInt()); + if (strl.at(0)=="wrap" && strl.size() > 4) + ui -> modulus_spinBox -> setValue(strl.at(4).toInt()); } } @@ -110,6 +114,7 @@ void NumPartEditorW::setVisibleItems() items << tr("Chiffre 1") << tr("Chiffre 01") << tr("Chiffre 001") + << tr("Cyclique (modulo)") << tr("Texte"); } else if (m_edited_type == 1) @@ -120,6 +125,7 @@ void NumPartEditorW::setVisibleItems() << tr("Chiffre 01 - Folio") << tr("Chiffre 001") << tr("Chiffre 001 - Folio") + << tr("Cyclique (modulo)") << tr("Texte") << tr("N° folio") << tr("Folio") @@ -133,6 +139,7 @@ void NumPartEditorW::setVisibleItems() << tr("Chiffre 01 - Folio") << tr("Chiffre 001") << tr("Chiffre 001 - Folio") + << tr("Cyclique (modulo)") << tr("Texte") << tr("N° folio") << tr("Folio") @@ -195,6 +202,9 @@ NumerotationContext NumPartEditorW::toNumContext() case elementprefix: type_str = "elementprefix"; break; + case wrap: + type_str = "wrap"; + break; } if (type_str == "unitfolio" || type_str == "tenfolio" @@ -203,6 +213,12 @@ NumerotationContext NumPartEditorW::toNumContext() ui -> value_field -> displayText(), ui -> increase_spinBox -> value(), ui->value_field->displayText().toInt()); + else if (type_str == "wrap") + nc.addValue(type_str, + ui -> value_field -> displayText(), + ui -> increase_spinBox -> value(), + 0, + ui -> modulus_spinBox -> value()); else nc.addValue(type_str, ui -> value_field -> displayText(), @@ -260,6 +276,8 @@ void NumPartEditorW::on_type_cb_activated(int) { setType(elementcolumn); else if (ui->type_cb->currentText() == tr("Element Prefix")) setType(elementprefix); + else if (ui->type_cb->currentText() == tr("Cyclique (modulo)")) + setType(wrap); emit changed(); } @@ -280,6 +298,14 @@ void NumPartEditorW::on_increase_spinBox_valueChanged(int) { if (!ui -> value_field -> text().isEmpty()) emit changed(); } +/** + @brief NumPartEditorW::on_modulus_spinBox_valueChanged + emit changed when modulus_spinBox value changed +*/ +void NumPartEditorW::on_modulus_spinBox_valueChanged(int) { + if (!ui -> value_field -> text().isEmpty()) emit changed(); +} + /** @brief NumPartEditorW::setType Set good behavior by type t @@ -299,6 +325,7 @@ void NumPartEditorW::setType(NumPartEditorW::type t, bool fnum) { || t==tenfolio || t==hundred || t==hundredfolio + || t==wrap ) && (type_==string || type_==folio @@ -317,6 +344,8 @@ void NumPartEditorW::setType(NumPartEditorW::type t, bool fnum) { ui -> value_field -> setValidator(intValidator); ui -> increase_spinBox -> setEnabled(true); ui -> increase_spinBox -> setValue(1); + if (t == wrap) + ui -> modulus_spinBox -> setValue(8); } //@t isn't a numeric type else if (t == string @@ -362,6 +391,7 @@ void NumPartEditorW::setType(NumPartEditorW::type t, bool fnum) { ui -> increase_spinBox -> setDisabled(true); } } + ui -> modulus_spinBox -> setEnabled(t == wrap); type_= t; } @@ -400,5 +430,7 @@ void NumPartEditorW::setCurrentIndex(NumPartEditorW::type t) { i = ui->type_cb->findText(tr("Element Column")); else if (t == elementprefix) i = ui->type_cb->findText(tr("Element Prefix")); + else if (t == wrap) + i = ui->type_cb->findText(tr("Cyclique (modulo)")); ui->type_cb->setCurrentIndex(i); } diff --git a/sources/autoNum/ui/numparteditorw.h b/sources/autoNum/ui/numparteditorw.h index f91568818..332711eda 100644 --- a/sources/autoNum/ui/numparteditorw.h +++ b/sources/autoNum/ui/numparteditorw.h @@ -49,6 +49,7 @@ class NumPartEditorW : public QWidget enum type {unit,unitfolio,ten,tenfolio, hundred, hundredfolio, string,idfolio,folio,plant,locmach, elementline,elementcolumn,elementprefix, + wrap, }; NumerotationContext toNumContext(); bool isValid (); @@ -63,6 +64,7 @@ class NumPartEditorW : public QWidget void on_type_cb_activated(int); void on_value_field_textEdited(); void on_increase_spinBox_valueChanged(int); + void on_modulus_spinBox_valueChanged(int); void setType (NumPartEditorW::type t, bool=false); signals: diff --git a/sources/autoNum/ui/numparteditorw.ui b/sources/autoNum/ui/numparteditorw.ui index a4250af8c..bfc4fd9d2 100644 --- a/sources/autoNum/ui/numparteditorw.ui +++ b/sources/autoNum/ui/numparteditorw.ui @@ -75,6 +75,9 @@ false + + Mettre à 0 pour un chiffre qui n'avance que par le report d'un chiffre cyclique suivant (ex: le "0" de "0.7") + Qt::AlignCenter @@ -88,7 +91,38 @@ - 1 + 0 + + + + + + + false + + + + 0 + 0 + + + + Valeur à laquelle ce chiffre revient à 0 en incrémentant le chiffre précédent (0 = pas de cycle) + + + Qt::AlignCenter + + + true + + + mod. + + + 0 + + + 99999