Files
core/ASCImageStudio3/ASCGraphics/Interfaces/TextMeasurer/Numeration.h

366 lines
8.6 KiB
C++

#pragma once
using XmlUtils::CXmlNode;
using XmlUtils::CXmlNodes;
class BaseNumbering {
public:
enum NumberingFormat {
DecimalNumbering,
BulletNumbering,
LowerLetterNumbering,
UpperLetterNumbering,
LowerRomanNumbering,
UpperRomanNumbering,
NumberInDashNumbering
};
protected:
CString getNumber(const int& number, const NumberingFormat& format) const {
switch (format) {
case DecimalNumbering: return getNum(number);
case LowerLetterNumbering: return getAlpha(number);
case UpperLetterNumbering: return getAlpha(number, true);
case LowerRomanNumbering: return getRoman(number);
case UpperRomanNumbering: return getRoman(number, true);
case NumberInDashNumbering: return getNumInDash(number);
default: return getNum(number);
}
}
private:
CString getNum(const int& number) const {
CString num;
num.Format(_T("%i"), number);
return num;
}
CString getNumInDash(const int& number) const {
CString num;
num.Format(_T("-%i-"), number);
return num;
}
CString getAlpha(const int& number, const bool& upper = false) const {
static CString alphas = _T(" abcdefghijklmnopqrstuvwxyz");
CString alphaNumber;
if (number < alphas.GetLength())
alphaNumber = alphas[number];
else
alphaNumber = alphas[alphas.GetLength() - 1];
if (upper)
alphaNumber.MakeUpper();
return alphaNumber;
}
CString getRoman(int number, const bool& upper = false) const {
static CString romans[] = {_T(""), _T("i"), _T("ii"), _T("iii"), _T("iv"),
_T("v"), _T("vi"), _T("vii"), _T("iix"), _T("ix")};
CString romanNumber = _T("");
while (number >= 10) {
romanNumber += _T("x");
number -= 10;
}
romanNumber += romans[number];
if (upper)
romanNumber.MakeUpper();
return romanNumber;
}
protected:
NumberingFormat getNumberingFormat(const CString& format) {
if (_T("decimal") == format) return DecimalNumbering;
else if (_T("bullet") == format) return BulletNumbering;
else if (_T("lowerLetter") == format) return LowerLetterNumbering;
else if (_T("upperLetter") == format) return UpperLetterNumbering;
else if (_T("lowerRoman") == format) return LowerRomanNumbering;
else if (_T("upperRoman") == format) return UpperRomanNumbering;
else if (_T("numberInDash") == format) return NumberInDashNumbering;
return DecimalNumbering;
}
};
class ListNumeration {
private:
class Numbering : public BaseNumbering {
private:
class Level {
public:
int _start;
CString _text;
NumberingFormat _format;
public:
Level()
: _start(1), _format(DecimalNumbering) {
}
};
private:
CArray<Level> _levels;
CArray<int> _numbers;
public:
Numbering()
: _numbers() {
}
Numbering(const Numbering& src) {
_levels.Copy(src._levels);
_numbers.Copy(src._numbers);
}
Numbering(CXmlNode& numberingXml) {
loadFromXml(numberingXml);
}
public:
void loadFromXml(CXmlNode& numberingXml) {
CXmlNodes levelXmls;
if (numberingXml.GetNodes(_T("lvl"), levelXmls)) {
int count = levelXmls.GetCount();
for (int i = 0; i < count; ++i) {
CXmlNode levelXml;
levelXmls.GetAt(i, levelXml);
_levels.Add();
Level& level = _levels[i];
level._start = levelXml.ReadAttributeInt(_T("start"), 1);
level._text = levelXml.GetAttribute(_T("text"));
level._format = getNumberingFormat(levelXml.GetAttribute(_T("format")));
}
}
}
public:
CString getElement(const int& level, const Numbering& numOverride) {
int overrideLevelCount = (int) numOverride._levels.GetCount();
if (level >= overrideLevelCount)
return getElement(level);
Level tmpLevel = _levels[level];
tmpLevel._format = numOverride._levels[level]._format;
tmpLevel._text = numOverride._levels[level]._text;
processElementLevel(level);
return getLevelElement(tmpLevel);
}
CString getElement(const int& level) {
processElementLevel(level);
return getLevelElement(_levels[level]);
}
private:
CString getFormattedText(const CString& text, const NumberingFormat& format) const {
CString formattedText;
int i = 0;
while (i < text.GetLength()) {
if (text[i] != _T('%'))
formattedText += text[i++];
else if (isdigit(text[++i])) {
wchar_t symbolLevel = text[i++];
int level = _wtoi(&symbolLevel) - 1;
if (level < (int)_numbers.GetCount())
formattedText += getNumber(_numbers[level], format);
}
}
return formattedText;
}
private:
CString getLevelElement(const Level& level) {
if (level._format == BulletNumbering)
return level._text;
else
return getFormattedText(level._text, level._format);
}
void processElementLevel(const int& level) {
addMissingLevels(level);
int count = (int)_numbers.GetCount();
if (level >= count)
for (int i = count; i <= level; ++i)
_numbers.Add(_levels[i]._start);
else {
for (int i = level + 1; i < count; ++i)
_numbers[i] = 0;
++_numbers[level];
}
}
void addMissingLevels(const int& level) {
int levelsCount = (int) _levels.GetCount();
if (level < levelsCount)
return;
for (int i = levelsCount; i < level + 1; ++i) {
_levels.Add();
_levels[i]._text.Format(_T("%%i"), i);
}
}
};
private:
std::map<CString, Numbering> _numberings;
std::map<CString, Numbering> _numOverrides;
public:
ListNumeration() {
}
public:
void loadFromXml(CXmlNode& listSettingsXml) {
CXmlNodes numXmls;
if (listSettingsXml.GetNodes(_T("num"), numXmls)) {
int count = numXmls.GetCount();
for (int i = 0; i < count; ++i) {
CXmlNode numXml;
numXmls.GetAt(i, numXml);
CString id = numXml.GetAttribute(_T("id"));
_numberings[id].loadFromXml(numXml);
}
}
CXmlNodes numOverrideXmls;
if (listSettingsXml.GetNodes(_T("numOverride"), numOverrideXmls)) {
int count = numOverrideXmls.GetCount();
for (int i = 0; i < count; ++i) {
CXmlNode numOverrideXml;
numOverrideXmls.GetAt(i, numOverrideXml);
CString id = numOverrideXml.GetAttribute(_T("id"));
_numOverrides[id].loadFromXml(numOverrideXml);
}
}
}
void clear() {
_numberings.clear();
_numOverrides.clear();
}
public:
CString getElement(const CString& id, const CString& numId, const int& level) {
std::map<CString, Numbering>::iterator numbering = _numberings.find(id);
if (numbering == _numberings.end())
numbering = _numberings.insert(std::pair<CString, Numbering>(id, Numbering())).first;
std::map<CString, Numbering>::iterator numOverride = _numOverrides.find(numId);
if (numOverride != _numOverrides.end())
return (*numbering).second.getElement(level, (*numOverride).second);
else
return (*numbering).second.getElement(level);
}
};
class PageNumbering : public BaseNumbering {
private:
NumberingFormat _format;
int _start;
int _index;
public:
PageNumbering()
: _start(1), _index(-1) {
}
public:
PageNumbering& operator=(const PageNumbering& src) {
_format = src._format;
_start = src._start;
_index = src._index;
return *this;
}
public:
void loadFromXml(CXmlNode& numberingXml) {
_format = getNumberingFormat(numberingXml.GetAttribute(_T("format")));
_start = numberingXml.ReadAttributeInt(_T("start"), -1);
_index = -1;
}
void clear() {
_format = DecimalNumbering;
_start = 1;
_index = -1;
}
public:
void next() {
++_index;
}
void setAfter(const PageNumbering& numbering) {
if (_start == -1) {
_start = numbering.getIndex();
_index = 0;
}
else
_index = -1;
}
public:
int getIndex() const {
return _start + _index;
}
CString getIndexString( ) const {
return getNumber(getIndex(), _format);
}
};
class PageNumeration {
private:
PageNumbering _numbering;
int _pageCount;
public:
PageNumeration()
: _pageCount(0) {
}
public:
void loadFromXml(CXmlNode& numSettingsXml) {
_numbering.clear();
_pageCount = numSettingsXml.ReadAttributeInt(_T("pageCount"), 1);
}
void clear() {
_numbering.clear();
_pageCount = 0;
}
public:
void setNumbering(PageNumbering numbering) {
numbering.setAfter(_numbering);
_numbering = numbering;
}
public:
void nextPage() {
_numbering.next();
}
int getPageIndex() const {
return _numbering.getIndex();
}
CString getPageIndexElement() const {
return _numbering.getIndexString();
}
int getPageCount() const {
return _pageCount;
}
CString getPageCountElement() const {
CString pageCount;
pageCount.Format(_T("%i"), _pageCount);
return pageCount;
}
};