From 684d27c0fbae75931586324c061e6a6b456ea632 Mon Sep 17 00:00:00 2001 From: Richard Kimberly Heck Date: Thu, 30 Apr 2020 21:56:58 -0400 Subject: [PATCH] New counter manipulation inset. This inset allows counters to be set, reset, saved, restored, etc, both in the LyX GUI and in the output; optionally, the effect can be limited to the GUI. Of course, LaTeX provides means for doing all of these things, so they could previously be done with ERT, as far as the output is concerned. But there was no mechanism for manipulating counters in the GUI and none for other output formats. --- src/Counters.cpp | 167 ++++++------------ src/Counters.h | 12 ++ src/Makefile.am | 2 + src/factory.cpp | 10 ++ src/insets/Inset.cpp | 1 + src/insets/InsetCode.h | 2 + src/insets/InsetCommand.cpp | 3 +- src/insets/InsetCommandParams.cpp | 11 +- src/insets/InsetCounter.cpp | 284 ++++++++++++++++++++++++++++++ src/insets/InsetCounter.h | 99 +++++++++++ src/support/Makefile.am | 2 + src/support/counter_reps.cpp | 135 ++++++++++++++ src/support/counter_reps.h | 33 ++++ 13 files changed, 640 insertions(+), 121 deletions(-) create mode 100644 src/insets/InsetCounter.cpp create mode 100644 src/insets/InsetCounter.h create mode 100644 src/support/counter_reps.cpp create mode 100644 src/support/counter_reps.h diff --git a/src/Counters.cpp b/src/Counters.cpp index 830a1002ca..830c7e0b7a 100644 --- a/src/Counters.cpp +++ b/src/Counters.cpp @@ -18,6 +18,7 @@ #include "Lexer.h" #include "support/convert.h" +#include "support/counter_reps.h" #include "support/debug.h" #include "support/gettext.h" #include "support/lassert.h" @@ -143,6 +144,18 @@ int Counter::value() const } +void Counter::saveValue() +{ + saved_value_ = value_; +} + + +void Counter::restoreValue() +{ + value_ = saved_value_; +} + + void Counter::step() { ++value_; @@ -265,6 +278,34 @@ int Counters::value(docstring const & ctr) const } +void Counters::saveValue(docstring const & ctr) const +{ + CounterList::const_iterator const cit = counterList_.find(ctr); + if (cit == counterList_.end()) { + lyxerr << "value: Counter does not exist: " + << to_utf8(ctr) << endl; + return; + } + Counter const & cnt = cit->second; + Counter & ccnt = const_cast(cnt); + ccnt.saveValue(); +} + + +void Counters::restoreValue(docstring const & ctr) const +{ + CounterList::const_iterator const cit = counterList_.find(ctr); + if (cit == counterList_.end()) { + lyxerr << "value: Counter does not exist: " + << to_utf8(ctr) << endl; + return; + } + Counter const & cnt = cit->second; + Counter & ccnt = const_cast(cnt); + ccnt.restoreValue(); +} + + void Counters::resetSlaves(docstring const & count) { for (auto & ctr : counterList_) { @@ -357,124 +398,6 @@ void Counters::copy(Counters & from, Counters & to, docstring const & match) } -namespace { - -char loweralphaCounter(int const n) -{ - if (n < 1 || n > 26) - return '?'; - return 'a' + n - 1; -} - - -char alphaCounter(int const n) -{ - if (n < 1 || n > 26) - return '?'; - return 'A' + n - 1; -} - - -char hebrewCounter(int const n) -{ - static const char hebrew[22] = { - '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', - '\xe9', '\xeb', '\xec', '\xee', '\xf0', '\xf1', '\xf2', '\xf4', '\xf6', - '\xf7', '\xf8', '\xf9', '\xfa' - }; - - if (n < 1 || n > 22) - return '?'; - return hebrew[n - 1]; -} - - -// On the special cases, see http://mathworld.wolfram.com/RomanNumerals.html -// and for a list of roman numerals up to and including 3999, see -// http://www.research.att.com/~njas/sequences/a006968.txt. (Thanks to Joost -// for this info.) -docstring const romanCounter(int const n) -{ - static char const * const ones[9] = { - "I", "II", "III", "IV", "V", - "VI", "VII", "VIII", "IX" - }; - - static char const * const tens[9] = { - "X", "XX", "XXX", "XL", "L", - "LX", "LXX", "LXXX", "XC" - }; - - static char const * const hunds[9] = { - "C", "CC", "CCC", "CD", "D", - "DC", "DCC", "DCCC", "CM" - }; - - if (n >= 1000 || n < 1) - return from_ascii("??"); - - int val = n; - string roman; - switch (n) { - //special cases - case 900: - roman = "CM"; - break; - case 400: - roman = "CD"; - break; - default: - if (val >= 100) { - int hundreds = val / 100; - roman = hunds[hundreds - 1]; - val = val % 100; - } - if (val >= 10) { - switch (val) { - //special case - case 90: - roman = roman + "XC"; - val = 0; //skip next - break; - default: - int tensnum = val / 10; - roman = roman + tens[tensnum - 1]; - val = val % 10; - } // end switch - } // end tens - if (val > 0) - roman = roman + ones[val -1]; - } - return from_ascii(roman); -} - - -docstring const lowerromanCounter(int const n) -{ - return lowercase(romanCounter(n)); -} - - -docstring const fnsymbolCounter(int const n) -{ - switch(n) { - case 1: return docstring(1, 0x002a); //* - case 2: return docstring(1, 0x2020); // dagger - case 3: return docstring(1, 0x2021); // double dagger - case 4: return docstring(1, 0x00A7); // section sign - case 5: return docstring(1, 0x00B6); // pilcrow sign - case 6: return docstring(1, 0x2016); // vertical bar - case 7: return docstring(2, 0x002a); // two * - case 8: return docstring(2, 0x2020); // two daggers - case 9: return docstring(2, 0x2021); // two double daggers - default: - return from_ascii("?"); - }; -} - -} // namespace - - docstring Counters::labelItem(docstring const & ctr, docstring const & numbertype) const { @@ -687,4 +610,12 @@ void Counters::endEnvironment() } +vector Counters::listOfCounters() const { + vector ret; + for(auto const & k : counterList_) + ret.emplace_back(k.first); + return ret; +} + + } // namespace lyx diff --git a/src/Counters.h b/src/Counters.h index 89383bc76a..77e1f118fa 100644 --- a/src/Counters.h +++ b/src/Counters.h @@ -45,6 +45,10 @@ public: /// int value() const; /// + void saveValue(); + /// + void restoreValue(); + /// void step(); /// void reset(); @@ -79,6 +83,8 @@ private: /// This is actually one less than the initial value, since the /// counter is always stepped before being used. int initial_value_; + /// + int saved_value_; /// contains master counter name. /** The master counter is the counter that, if stepped * (incremented) zeroes this counter. E.g. "subsection"'s @@ -128,6 +134,10 @@ public: void addto(docstring const & ctr, int val); /// int value(docstring const & ctr) const; + /// + void saveValue(docstring const & ctr) const; + /// + void restoreValue(docstring const & ctr) const; /// Reset recursively all the counters that are slaves of the one named by \c ctr. void resetSlaves(docstring const & ctr); /// Increment by one master of counter named by \c ctr. @@ -202,6 +212,8 @@ public: /// void restoreLastCounter() { counter_stack_.pop_back(); } // @} + /// + std::vector listOfCounters() const; private: /** expands recursively any \\the macro in the * labelstring of \c counter. The \c lang code is used to diff --git a/src/Makefile.am b/src/Makefile.am index 5a9ba93513..f76de2be9b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -555,6 +555,7 @@ SOURCEFILESINSETS = \ insets/InsetCollapsible.cpp \ insets/InsetCommand.cpp \ insets/InsetCommandParams.cpp \ + insets/InsetCounter.cpp \ insets/InsetERT.cpp \ insets/InsetExternal.cpp \ insets/InsetFlex.cpp \ @@ -615,6 +616,7 @@ HEADERFILESINSETS = \ insets/InsetCollapsible.h \ insets/InsetCommand.h \ insets/InsetCommandParams.h \ + insets/InsetCounter.h \ insets/InsetERT.h \ insets/InsetExternal.h \ insets/InsetFlex.h \ diff --git a/src/factory.cpp b/src/factory.cpp index 653a128761..f255ef2540 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -26,6 +26,7 @@ #include "insets/InsetBranch.h" #include "insets/InsetCaption.h" #include "insets/InsetCitation.h" +#include "insets/InsetCounter.h" #include "insets/InsetFlex.h" #include "insets/InsetERT.h" #include "insets/InsetListings.h" @@ -301,6 +302,12 @@ Inset * createInsetHelper(Buffer * buf, FuncRequest const & cmd) return new InsetCitation(buf, icp); } + case COUNTER_CODE: { + InsetCommandParams icp(code); + InsetCommand::string2params(to_utf8(cmd.argument()), icp); + return new InsetCounter(buf, icp); + } + case ERT_CODE: { return new InsetERT(buf, InsetERT::string2params(to_utf8(cmd.argument()))); @@ -551,6 +558,9 @@ Inset * readInset(Lexer & lex, Buffer * buf) case CITE_CODE: inset.reset(new InsetCitation(buf, inscmd)); break; + case COUNTER_CODE: + inset.reset(new InsetCounter(buf, inscmd)); + break; case HYPERLINK_CODE: inset.reset(new InsetHyperlink(buf, inscmd)); break; diff --git a/src/insets/Inset.cpp b/src/insets/Inset.cpp index 397a8d0380..2043436ba9 100644 --- a/src/insets/Inset.cpp +++ b/src/insets/Inset.cpp @@ -74,6 +74,7 @@ static void build_translator() insetnames[TOC_CODE] = InsetName("toc"); insetnames[QUOTE_CODE] = InsetName("quote"); insetnames[REF_CODE] = InsetName("ref"); + insetnames[COUNTER_CODE] = InsetName("counter"); insetnames[HYPERLINK_CODE] = InsetName("href"); insetnames[SEPARATOR_CODE] = InsetName("separator"); insetnames[ENDING_CODE] = InsetName("ending"); diff --git a/src/insets/InsetCode.h b/src/insets/InsetCode.h index 3633da727a..43ed4b5d0a 100644 --- a/src/insets/InsetCode.h +++ b/src/insets/InsetCode.h @@ -237,6 +237,8 @@ enum InsetCode { /// MATH_CLASS_CODE, /// + COUNTER_CODE, + /// INSET_CODE_SIZE }; diff --git a/src/insets/InsetCommand.cpp b/src/insets/InsetCommand.cpp index f2f0cd8455..47affcc543 100644 --- a/src/insets/InsetCommand.cpp +++ b/src/insets/InsetCommand.cpp @@ -346,7 +346,8 @@ bool decodeInsetParam(string const & name, string & data, case NOMENCL_PRINT_CODE: case REF_CODE: case TOC_CODE: - case HYPERLINK_CODE: { + case HYPERLINK_CODE: + case COUNTER_CODE: { InsetCommandParams p(code); data = InsetCommand::params2string(p); break; diff --git a/src/insets/InsetCommandParams.cpp b/src/insets/InsetCommandParams.cpp index c4c0a5cf46..1f7d321108 100644 --- a/src/insets/InsetCommandParams.cpp +++ b/src/insets/InsetCommandParams.cpp @@ -20,6 +20,7 @@ #include "InsetBibitem.h" #include "InsetBibtex.h" #include "InsetCitation.h" +#include "InsetCounter.h" #include "InsetFloatList.h" #include "InsetHyperlink.h" #include "InsetInclude.h" @@ -63,6 +64,8 @@ static ParamInfo const & findInfo(InsetCode code, string const & cmdName) return InsetBibtex::findInfo(cmdName); case CITE_CODE: return InsetCitation::findInfo(cmdName); + case COUNTER_CODE: + return InsetCounter::findInfo(cmdName); case FLOAT_LIST_CODE: return InsetFloatList::findInfo(cmdName); case HYPERLINK_CODE: @@ -201,6 +204,8 @@ string InsetCommandParams::getDefaultCmd(InsetCode code) return InsetBibtex::defaultCommand(); case CITE_CODE: return InsetCitation::defaultCommand(); + case COUNTER_CODE: + return InsetCounter::defaultCommand(); case FLOAT_LIST_CODE: return InsetFloatList::defaultCommand(); case HYPERLINK_CODE: @@ -238,6 +243,8 @@ bool InsetCommandParams::isCompatibleCommand(InsetCode code, string const & s) return InsetBibtex::isCompatibleCommand(s); case CITE_CODE: return InsetCitation::isCompatibleCommand(s); + case COUNTER_CODE: + return InsetCounter::isCompatibleCommand(s); case FLOAT_LIST_CODE: return InsetFloatList::isCompatibleCommand(s); case HYPERLINK_CODE: @@ -282,7 +289,7 @@ void InsetCommandParams::setCmdName(string const & name) void InsetCommandParams::read(Lexer & lex) { - Read(lex, 0); + Read(lex, nullptr); } @@ -356,7 +363,7 @@ void InsetCommandParams::Read(Lexer & lex, Buffer const * buffer) void InsetCommandParams::write(ostream & os) const { - Write(os, 0); + Write(os, nullptr); } diff --git a/src/insets/InsetCounter.cpp b/src/insets/InsetCounter.cpp new file mode 100644 index 0000000000..cdd5393c5f --- /dev/null +++ b/src/insets/InsetCounter.cpp @@ -0,0 +1,284 @@ +/** + * \file InsetCounter.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Richard Kimberly Heck + * + * Full author contact details are available in file CREDITS. + */ +#include + +#include "InsetCounter.h" + +#include "Buffer.h" +#include "BufferParams.h" +#include "Counters.h" +#include "LaTeXFeatures.h" +#include "OutputParams.h" +#include "output_xhtml.h" +#include "sgml.h" +#include "texstream.h" +#include "TextClass.h" + +#include "support/convert.h" +#include "support/counter_reps.h" +#include "support/docstream.h" +#include "support/gettext.h" +#include "support/lassert.h" +#include "support/lstrings.h" + +#include + +/* +#include "Cursor.h" +#include "DispatchResult.h" +#include "Language.h" +#include "LyX.h" +#include "ParIterator.h" +#include "TocBackend.h" + +#include "support/debug.h" +#include "support/textutils.h" +*/ + +using namespace lyx::support; +using namespace std; + +namespace lyx { + + +InsetCounter::InsetCounter(Buffer * buf, InsetCommandParams const & p) + : InsetCommand(buf, p) +{} + + +InsetCounter::InsetCounter(InsetCounter const & ir) + : InsetCommand(ir) +{} + + +const map InsetCounter::counterTable = +{ + {"set", N_("Set")}, + {"addto", N_("Add To")}, + {"reset", N_("Reset")}, + {"save", N_("Save")}, + {"restore", N_("Restore")}, + {"value", N_("Value")} +}; + + +bool InsetCounter::isCompatibleCommand(string const & s) { + return counterTable.count(s); +} + + +ParamInfo const & InsetCounter::findInfo(string const & /* cmdName */) +{ + static ParamInfo param_info_; + if (param_info_.empty()) { + param_info_.add("counter", ParamInfo::LYX_INTERNAL); + param_info_.add("value", ParamInfo::LYX_INTERNAL); + param_info_.add("vtype", ParamInfo::LYX_INTERNAL); + param_info_.add("lyxonly", ParamInfo::LYX_INTERNAL); + } + return param_info_; +} + + +void InsetCounter::latex(otexstream & os, OutputParams const &) const +{ + bool const lyxonly = lowercase(getParam("lyxonly")) == "true"; + if (lyxonly) + return; + + string const cmd = getCmdName(); + docstring cntr = getParam("counter"); + Counters & cnts = buffer().params().documentClass().counters(); + if (cmd == "set") { + docstring const & val = getParam("value"); + os << "\\setcounter{" << cntr << "}{" << val << "}"; + } else if (cmd == "addto") { + docstring const & val = getParam("value"); + os << "\\addtocounter{" << cntr << "}{" << val << "}"; + } else if (cmd == "reset") { + os << "\\setcounter{" << cntr << "}{0}"; + } else if (cmd == "save") { + cnts.saveValue(cntr); + os << "\\setcounter{" << lyxSaveCounter() + << "}{\\value{" << cntr << "}}"; + } else if (cmd == "restore") { + cnts.restoreValue(cntr); + os << "\\setcounter{" << cntr + << "{\\value{" << lyxSaveCounter() << "}}"; + } else if (cmd == "value") { + os << "\\value{" << cntr << "}"; + } +} + + +void InsetCounter::toString(odocstream & os) const +{ + os << "[Counter " << from_utf8(getCmdName()) << ": " + << getParam("counter") << "]"; +} + + +int InsetCounter::plaintext(odocstringstream & os, + OutputParams const &, size_t) const +{ + toString(os); + return 0; +} + + +void InsetCounter::trackCounters(string const & cmd) const +{ + Counters & cnts = buffer().params().documentClass().counters(); + docstring cntr = getParam("counter"); + if (cmd == "set") { + docstring const & val = getParam("value"); + cnts.set(cntr, convert(val)); + } else if (cmd == "addto") { + docstring const & val = getParam("value"); + cnts.addto(cntr, convert(val)); + } else if (cmd == "reset") { + cnts.reset(cntr); + } else if (cmd == "save") { + cnts.saveValue(cntr); + } else if (cmd == "restore") { + cnts.restoreValue(cntr); + } +} + + +const map InsetCounter::valueTable = +{ + {"Roman", N_("Roman Uppercase")}, + {"roman", N_("Roman Lowercase")}, + {"Alpha", N_("Uppercase Letter")}, + {"alpha", N_("Lowercase Letter")}, + {"arabic", N_("Arabic Numeral")} +}; + + +docstring InsetCounter::value() const { + docstring const & cnt = getParam("counter"); + string const & vtype = getCmdName(); + int const val = buffer().params().documentClass().counters().value(cnt); + if (vtype == "Roman") + return romanCounter(val); + if (vtype == "roman") + return lowerromanCounter(val); + if (vtype == "Alpha") + return docstring(1, alphaCounter(val)); + if (vtype == "alpha") + return docstring(1, loweralphaCounter(val)); + if (vtype == "arabic") + return convert(val); + LATTEST(false); + return empty_docstring(); +} + + +int InsetCounter::docbook(odocstream & os, OutputParams const &) const +{ + // Here, we need to track counter values ourselves, + // since unlike in the LaTeX case, there is no external + // mechanism for doing that. + string const cmd = getCmdName(); + if (cmd == "value") { + docstring cntr = getParam("counter"); + Counters & cnts = buffer().params().documentClass().counters(); + if (cnts.hasCounter(cntr)) + os << cnts.value(cntr); + } else + trackCounters(cmd); + + return 0; +} + + +docstring InsetCounter::xhtml(XHTMLStream & xs, OutputParams const &) const +{ + // Here, we need to track counter values ourselves, + // since unlike in the LaTeX case, there is no external + // mechanism for doing that. + string const cmd = getCmdName(); + if (cmd == "value") { + docstring cntr = getParam("counter"); + Counters & cnts = buffer().params().documentClass().counters(); + if (cnts.hasCounter(cntr)) + xs << cnts.value(cntr); + } else + trackCounters(cmd); + + return docstring(); +} + + +void InsetCounter::updateBuffer(ParIterator const &, UpdateType, bool const) +{ + string const cmd = getCmdName(); + docstring cntr = getParam("counter"); + Counters & cnts = buffer().params().documentClass().counters(); + map::const_iterator cit = counterTable.find(cmd); + LASSERT(cit != counterTable.end(), return); + string const label = cit->second; + docstring const tlabel = translateIfPossible(from_ascii(label)); + + if (cmd == "set") { + docstring const & val = getParam("value"); + cnts.set(cntr, convert(val)); + screen_label_ = bformat(_("Counter: Set %1$s"), cntr); + tooltip_ = bformat(_("Set value of counter %1$s to %2$s"), cntr, val); + } else if (cmd == "addto") { + docstring const & val = getParam("value"); + cnts.addto(cntr, convert(val)); + screen_label_ = bformat(_("Counter: Add to %1$s"), cntr); + tooltip_ = bformat(_("Add to value of counter %1$s"), cntr); + } else if (cmd == "reset") { + cnts.reset(cntr); + screen_label_ = bformat(_("Counter: Reset %1$s"), cntr); + tooltip_ = bformat(_("Reset value of counter %1$s"), cntr); + } else if (cmd == "save") { + cnts.saveValue(cntr); + screen_label_ = bformat(_("Counter: Save %1$s"), cntr); + tooltip_ = bformat(_("Save value of counter %1$s"), cntr); + } else if (cmd == "restore") { + cnts.restoreValue(cntr); + screen_label_ = bformat(_("Counter: Restore %1$s"), cntr); + tooltip_ = bformat(_("Restore value of counter %1$s"), cntr); + } else if (cmd == "value") { + screen_label_ = bformat(_("Counter: Value %1$s"), cntr); + tooltip_ = bformat(_("Print value of counter %1$s"), cntr); + } + +} + + +docstring InsetCounter::lyxSaveCounter() const +{ + docstring cntr = getParam("counter"); + return from_ascii("LyXSave") + cntr; +} + + +void InsetCounter::validate(LaTeXFeatures & features) const +{ + // create save counter if needed + string const cmd = getCmdName(); + docstring const lyxonly = getParam("lyxonly"); + if ((cmd == "save" || cmd == "restore") && lyxonly != "true") { + features.addPreambleSnippet(from_ascii("\\newcounter{") + lyxSaveCounter() + "}"); + } + InsetCommand::validate(features); +} + + +string InsetCounter::contextMenuName() const +{ + return "context-counter"; +} +} // namespace lyx diff --git a/src/insets/InsetCounter.h b/src/insets/InsetCounter.h new file mode 100644 index 0000000000..44d909c384 --- /dev/null +++ b/src/insets/InsetCounter.h @@ -0,0 +1,99 @@ +// -*- C++ -*- +/** + * \file InsetCounter.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Richard Kimberly Heck + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef INSET_COUNTER_H +#define INSET_COUNTER_H + +#include "InsetCommand.h" + + +namespace lyx { + +/// +class InsetCounter : public InsetCommand { +public: + /// + InsetCounter(Buffer * buffer, InsetCommandParams const &); + /// \name Public functions inherited from Inset class + //@{ + /// + bool isLabeled() const { return true; } + /// + docstring toolTip(BufferView const &, int, int) const + { return tooltip_; } + /// + bool hasSettings() const { return true; } + /// + InsetCode lyxCode() const { return COUNTER_CODE; } + /// + void latex(otexstream &, OutputParams const &) const; + /// + int plaintext(odocstringstream & ods, OutputParams const & op, + size_t max_length = INT_MAX) const; + /// + int docbook(odocstream &, OutputParams const &) const; + /// + docstring xhtml(XHTMLStream &, OutputParams const &) const; + /// + void toString(odocstream &) const; + /// + void validate(LaTeXFeatures & features) const; + /// + void updateBuffer(ParIterator const & it, UpdateType, bool const); + /// + std::string contextMenuName() const; + //@} + + /// \name Static public methods obligated for InsetCommand derived classes + //@{ + /// + static ParamInfo const & findInfo(std::string const &); + /// + static std::string defaultCommand() { return "set"; } + /// + static bool isCompatibleCommand(std::string const & s); + //@} + /// keys are commands, values are GUI strings + static const std::map counterTable; + static const std::map valueTable; + +protected: + /// + InsetCounter(InsetCounter const &); + +private: + /// \name Private functions inherited from Inset class + //@{ + /// + Inset * clone() const { return new InsetCounter(*this); } + //@} + + /// \name Private functions inherited from InsetCommand class + //@{ + /// + docstring screenLabel() const { return screen_label_; } + //@} + /// + docstring value() const; + /// + docstring lyxSaveCounter() const; + /// + void trackCounters(std::string const & cmd) const; + /// + mutable docstring screen_label_; + /// + mutable docstring tooltip_; +}; + + +} // namespace lyx + +#endif // INSET_REF_H diff --git a/src/support/Makefile.am b/src/support/Makefile.am index 70bbee266e..3d92b62db0 100644 --- a/src/support/Makefile.am +++ b/src/support/Makefile.am @@ -44,6 +44,8 @@ liblyxsupport_a_SOURCES = \ convert.cpp \ convert.h \ copied_ptr.h \ + counter_reps.cpp \ + counter_reps.h \ debug.cpp \ debug.h \ docstream.cpp \ diff --git a/src/support/counter_reps.cpp b/src/support/counter_reps.cpp new file mode 100644 index 0000000000..96cbe24f5c --- /dev/null +++ b/src/support/counter_reps.cpp @@ -0,0 +1,135 @@ +/** + * \file convert.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * \author Lars Gullik Bjønnes + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "support/counter_reps.h" +#include "support/docstring.h" +#include "support/lstrings.h" + +using namespace std; + +namespace lyx { + +char loweralphaCounter(int const n) +{ + if (n < 1 || n > 26) + return '?'; + return 'a' + n - 1; +} + + +char alphaCounter(int const n) +{ + if (n < 1 || n > 26) + return '?'; + return 'A' + n - 1; +} + + +char hebrewCounter(int const n) +{ + static const char hebrew[22] = { + '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', + '\xe9', '\xeb', '\xec', '\xee', '\xf0', '\xf1', '\xf2', '\xf4', '\xf6', + '\xf7', '\xf8', '\xf9', '\xfa' + }; + + if (n < 1 || n > 22) + return '?'; + return hebrew[n - 1]; +} + + +// On the special cases, see http://mathworld.wolfram.com/RomanNumerals.html +// and for a list of roman numerals up to and including 3999, see +// http://www.research.att.com/~njas/sequences/a006968.txt. (Thanks to Joost +// for this info.) +docstring const romanCounter(int const n) +{ + static char const * const ones[9] = { + "I", "II", "III", "IV", "V", + "VI", "VII", "VIII", "IX" + }; + + static char const * const tens[9] = { + "X", "XX", "XXX", "XL", "L", + "LX", "LXX", "LXXX", "XC" + }; + + static char const * const hunds[9] = { + "C", "CC", "CCC", "CD", "D", + "DC", "DCC", "DCCC", "CM" + }; + + if (n >= 1000 || n < 1) + return from_ascii("??"); + + int val = n; + string roman; + switch (n) { + //special cases + case 900: + roman = "CM"; + break; + case 400: + roman = "CD"; + break; + default: + if (val >= 100) { + int hundreds = val / 100; + roman = hunds[hundreds - 1]; + val = val % 100; + } + if (val >= 10) { + switch (val) { + //special case + case 90: + roman = roman + "XC"; + val = 0; //skip next + break; + default: + int tensnum = val / 10; + roman = roman + tens[tensnum - 1]; + val = val % 10; + } // end switch + } // end tens + if (val > 0) + roman = roman + ones[val -1]; + } + return from_ascii(roman); +} + + +docstring const lowerromanCounter(int const n) +{ + return support::lowercase(romanCounter(n)); +} + + +docstring const fnsymbolCounter(int const n) +{ + switch(n) { + case 1: return docstring(1, 0x002a); //* + case 2: return docstring(1, 0x2020); // dagger + case 3: return docstring(1, 0x2021); // double dagger + case 4: return docstring(1, 0x00A7); // section sign + case 5: return docstring(1, 0x00B6); // pilcrow sign + case 6: return docstring(1, 0x2016); // vertical bar + case 7: return docstring(2, 0x002a); // two * + case 8: return docstring(2, 0x2020); // two daggers + case 9: return docstring(2, 0x2021); // two double daggers + default: + return from_ascii("?"); + }; +} + +} // namespace lyx diff --git a/src/support/counter_reps.h b/src/support/counter_reps.h new file mode 100644 index 0000000000..e6a3f67d9e --- /dev/null +++ b/src/support/counter_reps.h @@ -0,0 +1,33 @@ +// -*- C++ -*- +/** + * \file counter_reps.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Lars Gullik Bjønnes + * \author Richard Kimberly Heck (roman numerals) + * \author Jean-Marc Lasgouttes + * + * Full author contact details are available in file CREDITS. + * + * A collection of helper functions to convert counters to different + * formats. + */ + +#ifndef COUNTER_REPS_H +#define COUNTER_REPS_H + +#include "support/strfwd.h" + +namespace lyx { + +char loweralphaCounter(int const n); +char alphaCounter(int const n); +char hebrewCounter(int const n); +docstring const romanCounter(int const n); +docstring const lowerromanCounter(int const n); +docstring const fnsymbolCounter(int const n); + +} // namespace lyx + +#endif