[LyX/master] New counter manipulation inset.

Richard Kimberly Heck rikiheck at lyx.org
Fri May 1 02:53:50 UTC 2020


commit 684d27c0fbae75931586324c061e6a6b456ea632
Author: Richard Kimberly Heck <rikiheck at lyx.org>
Date:   Thu Apr 30 21:56:58 2020 -0400

    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(-)

diff --git a/src/Counters.cpp b/src/Counters.cpp
index 830a100..830c7e0 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<Counter &>(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<Counter &>(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<docstring> Counters::listOfCounters() const {
+	vector<docstring> 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 89383bc..77e1f11 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<docstring> listOfCounters() const;
 private:
 	/** expands recursively any \\the<counter> 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 5a9ba93..f76de2b 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 653a128..f255ef2 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 397a8d0..2043436 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 3633da7..43ed4b5 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 f2f0cd8..47affcc 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 c4c0a5c..1f7d321 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 0000000..cdd5393
--- /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 <config.h>
+
+#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 <map>
+
+/*
+#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<string, string> 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<int>(val));
+	} else if (cmd == "addto") {
+		docstring const & val = getParam("value");
+		cnts.addto(cntr, convert<int>(val));
+	} else if (cmd == "reset") {
+		cnts.reset(cntr);		
+	} else if (cmd == "save") {
+		cnts.saveValue(cntr);
+	} else if (cmd == "restore") {
+		cnts.restoreValue(cntr);
+	}
+}
+
+
+const map<string, string> 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<docstring>(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<string, string>::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<int>(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<int>(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 0000000..44d909c
--- /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<std::string, std::string> counterTable;
+	static const std::map<std::string, std::string> 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 70bbee2..3d92b62 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 0000000..96cbe24
--- /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 <config.h>
+
+#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 0000000..e6a3f67
--- /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


More information about the lyx-cvs mailing list