#ifndef DOC_VISITOR_H
#define DOC_VISITOR_H
#include <stack>
#include "tinyxml.h"
#include "DocStyle.h"
#include "DocTemplate.h"
class DocVisitor : public TiXmlVisitor
{
public:
DocVisitor(DocOutputDevice* doc, DocStyle* style, DocTemplate* templ, int pageCount = -1);
virtual ~DocVisitor();
/// Visit a document.
virtual bool VisitEnter( const TiXmlDocument& doc );
/// Visit a document.
virtual bool VisitExit( const TiXmlDocument& doc );
/// Visit a declaration
virtual bool Visit( const TiXmlDeclaration& declaration );
/// Visit a stylesheet reference
virtual bool Visit( const TiXmlStylesheetReference& stylesheet );
/// Visit a comment node
virtual bool Visit( const TiXmlComment& comment );
/// Visit an unknow node
virtual bool Visit( const TiXmlUnknown& unknown );
/// Visit an element.
virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
/// Visit an element.
virtual bool VisitExit( const TiXmlElement& element );
/// Visit a text node
virtual bool Visit( const TiXmlText& text );
bool needsPageCount() const { return m_needPageCount; }
int pageCount() const { return m_pageNum; }
private:
DocOutputDevice* m_doc;
DocOutputPage* m_page;
void OutputText(const char* str);
float OutputTextHelper(const char* str, bool doSplit = true);
void OutputCurrentWord(const char* str);
void CheckIfEndOfPage();
void AddPage();
void NewLine(float amount = 1.0);
void DrawCodeBlockRect();
void OutputTable();
float WidestWordInText(std::string& str, bool& stretch);
struct ListState
{
bool ordered;
int index;
};
struct TextNode
{
int listLevel;
ListState listState[16]; // up to 16 nested list levels
bool codeFlag;
bool linkFlag;
bool blockQuoteFlag;
bool italicsFlag;
bool boldFlag;
bool preFlag;
bool tableFlag;
FontType style;
std::string words;
};
float bufferedTextWidth;
std::vector<TextNode> bufferedText;
void FlushBufferedText();
bool redirect = false;
struct RedirectedText
{
float x;
float y;
std::string text;
};
std::vector<RedirectedText> redirectedText;
void RedirectBounds(float& x1, float& y1, float& x2, float& y2);
void DrawText(float x, float y, std::string str)
{
if (redirect)
redirectedText.emplace_back(RedirectedText{x, y, str});
else
m_page->drawText(x, y, str.c_str());
}
void StartRedirect()
{
redirect = true;
}
void EndRedirect()
{
redirect = false;
for (auto& t : redirectedText)
DrawText(t.x, t.y, t.text);
redirectedText.clear();
}
float x, y;
DocStyle* m_style;
DocTemplate* m_templ;
std::stack<FontType> currentStyle;
std::stack<int> currentHeadingLevel;
std::string codeText;
float indentLevels[32];
int indentLevel;
int insideCode;
int insideLink;
bool orderedList;
int listItemIndex;
bool startOfListItem;
bool alignCenter;
int insideBlockQuote; // block quotes can be nested
bool needBlockQuoteBar;
int insidePreformatted;
float codeStartX;
float codeStartY;
bool insideTable;
enum TDAlign { TDA_Left, TDA_Center, TDA_Right };
struct TD { TDAlign align; std::string str; };
std::vector<std::vector<TD>> tableData;
int m_columnNum;
int m_columnCount;
float m_columnSpacing;
float m_columnWidth;
float m_truePageLeftMargin;
int m_pageNum;
int m_pageCount;
int m_needPageCount;
float m_pageLeftMarginX; // = 60.0f;
float m_pageRightMarginX; // = pageWidth - 60.0f;
float m_pageTopMarginY; // = 120.0f;
float m_pageBottomMarginY; // = pageHeight - 60.0f;
};
#endif // DOC_VISITOR_H