mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 02:44:13 +08:00
Fix bugs in html to OOXML/Markdown conversion
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
#include "CDocumentStyle.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
#include <wchar.h>
|
||||
#include <math.h>
|
||||
|
||||
@ -29,8 +29,6 @@ namespace HTML
|
||||
#define UNKNOWN_TAG GumboTag::GUMBO_TAG_UNKNOWN
|
||||
#define HtmlTag GumboTag
|
||||
|
||||
#define TAGS_COUNT 32
|
||||
|
||||
const static std::map<std::wstring, HtmlTag> m_HTML_TAGS
|
||||
{
|
||||
ADD_TAG(L"a", A),
|
||||
@ -344,6 +342,8 @@ void CHTMLReader::Clear()
|
||||
|
||||
if (nullptr != m_pTableElement)
|
||||
delete m_pTableElement;
|
||||
|
||||
ClearStopTags();
|
||||
}
|
||||
|
||||
bool CHTMLReader::InitOOXMLTags(THTMLParameters* pParametrs)
|
||||
@ -382,6 +382,13 @@ bool CHTMLReader::InitOOXMLTags(THTMLParameters* pParametrs)
|
||||
std::vector<NSCSS::CNode>& arSelectors)
|
||||
{ GetSubClass(oReader, arSelectors, m_oCSSCalculator); };
|
||||
|
||||
oExternalData.ReadInside = [this](XmlUtils::CXmlLiteReader& oReader,
|
||||
std::vector<NSCSS::CNode>& arSelectors)
|
||||
{ return ReadInside(oReader, arSelectors); };
|
||||
|
||||
oExternalData.AddStopTag = [this](const std::wstring& wsTag){ AddStopTag(wsTag); };
|
||||
oExternalData.ClearStopTags = [this]{ ClearStopTags(); };
|
||||
|
||||
oExternalData.m_pWriter = pWriter;
|
||||
|
||||
m_pTableElement = new COOXMLTable(oExternalData);
|
||||
@ -418,11 +425,18 @@ bool CHTMLReader::InitMDTags(TMarkdownParameters* pParametrs)
|
||||
|
||||
oExternalData.ReadStream = [this](XmlUtils::CXmlLiteReader& oReader,
|
||||
std::vector<NSCSS::CNode>& arSelectors)
|
||||
{ return ReadStream(oReader, arSelectors, true); };
|
||||
{ return ReadStream(oReader, arSelectors, true); };
|
||||
|
||||
oExternalData.GetSubClass = [this](XmlUtils::CXmlLiteReader& oReader,
|
||||
std::vector<NSCSS::CNode>& arSelectors)
|
||||
{ GetSubClass(oReader, arSelectors, m_oCSSCalculator); };
|
||||
{ GetSubClass(oReader, arSelectors, m_oCSSCalculator); };
|
||||
|
||||
oExternalData.ReadInside = [this](XmlUtils::CXmlLiteReader& oReader,
|
||||
std::vector<NSCSS::CNode>& arSelectors)
|
||||
{ return ReadInside(oReader, arSelectors); };
|
||||
|
||||
oExternalData.AddStopTag = [this](const std::wstring& wsTag){ AddStopTag(wsTag); };
|
||||
oExternalData.ClearStopTags = [this]{ ClearStopTags(); };
|
||||
|
||||
oExternalData.m_pWriter = pWriter;
|
||||
|
||||
@ -665,6 +679,9 @@ bool CHTMLReader::ReadStream(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCS
|
||||
|
||||
do
|
||||
{
|
||||
if (!m_arStopTags.empty() && m_arStopTags.end() != m_arStopTags.find(oReader.GetName()))
|
||||
return bResult;
|
||||
|
||||
if (ReadInside(oReader, arSelectors))
|
||||
bResult = true;
|
||||
} while(oReader.ReadNextSiblingNode2(nDeath));
|
||||
@ -688,10 +705,10 @@ bool CHTMLReader::ReadInside(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCS
|
||||
|
||||
GetSubClass(oReader, arSelectors, m_oCSSCalculator);
|
||||
|
||||
bool bResult{false};
|
||||
|
||||
const HtmlTag eHtmlTag{GetHtmlTag(wsName)};
|
||||
|
||||
bool bResult{false};
|
||||
|
||||
switch(eHtmlTag)
|
||||
{
|
||||
case HTML_TAG(A):
|
||||
@ -1002,6 +1019,16 @@ bool CHTMLReader::ReadTable(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS
|
||||
return true;
|
||||
}
|
||||
|
||||
void CHTMLReader::AddStopTag(const std::wstring& wsTag)
|
||||
{
|
||||
m_arStopTags.insert(wsTag);
|
||||
}
|
||||
|
||||
void CHTMLReader::ClearStopTags()
|
||||
{
|
||||
m_arStopTags.clear();
|
||||
}
|
||||
|
||||
inline std::wstring GetArgumentValue(XmlUtils::CXmlLiteReader& oLiteReader, const std::wstring& wsArgumentName, const std::wstring& wsDefaultValue)
|
||||
{
|
||||
if (!oLiteReader.MoveToFirstAttribute())
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
#ifndef HTMLREADER_H
|
||||
#define HTMLREADER_H
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../Common/3dParty/html/css/src/CCssCalculator.h"
|
||||
#include "../DesktopEditor/xml/include/xmlutils.h"
|
||||
|
||||
@ -14,6 +11,8 @@
|
||||
#include "Tags/HTMLTags.h"
|
||||
#include "Table.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace HTML
|
||||
{
|
||||
class CHTMLReader
|
||||
@ -32,6 +31,8 @@ class CHTMLReader
|
||||
|
||||
CTableElement* m_pTableElement; // Table Converter
|
||||
|
||||
std::set<std::wstring> m_arStopTags;
|
||||
|
||||
THTMLTags m_oTags;
|
||||
public:
|
||||
CHTMLReader();
|
||||
@ -81,6 +82,9 @@ private:
|
||||
bool ReadText(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors);
|
||||
|
||||
bool ReadTable(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors);
|
||||
|
||||
void AddStopTag(const std::wstring& wsTag);
|
||||
void ClearStopTags();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -114,9 +114,23 @@ namespace HTML
|
||||
// }
|
||||
// }
|
||||
|
||||
ITableElementCell::ITableElementCell(size_t unColspan)
|
||||
: m_unColspan(unColspan)
|
||||
{}
|
||||
|
||||
CTableElementCell::CTableElementCell(bool bIsFilling)
|
||||
: m_eType{(bIsFilling) ? ETableElement::FillingCell : ETableElement::Cell}
|
||||
void ITableElementCell::SetColspan(size_t unColspan)
|
||||
{
|
||||
if (0 < unColspan)
|
||||
m_unColspan = unColspan;
|
||||
}
|
||||
|
||||
size_t ITableElementCell::GetColspan() const
|
||||
{
|
||||
return m_unColspan;
|
||||
}
|
||||
|
||||
CTableElementCell::CTableElementCell(bool bIsFilling, size_t unColspan)
|
||||
: ITableElementCell(unColspan), m_eType{(bIsFilling) ? ETableElement::FillingCell : ETableElement::Cell}
|
||||
{}
|
||||
|
||||
CTableElementCell::~CTableElementCell()
|
||||
@ -132,6 +146,16 @@ void CTableElementCell::IsFlatTable()
|
||||
m_eType = ETableElement::FlatTable;
|
||||
}
|
||||
|
||||
CTableElementCell* CTableElementCell::CreateCell(const size_t& unColspan)
|
||||
{
|
||||
return new CTableElementCell(false, unColspan);
|
||||
}
|
||||
|
||||
CTableElementCell* CTableElementCell::CreateFillingCell(const size_t& unColspan)
|
||||
{
|
||||
return new CTableElementCell(true, unColspan);
|
||||
}
|
||||
|
||||
CTableMatrix::CTableMatrix()
|
||||
{}
|
||||
|
||||
@ -157,7 +181,7 @@ void CTableMatrix::Clear()
|
||||
m_arCells.clear();
|
||||
}
|
||||
|
||||
bool CTableMatrix::SetCell(size_t unRowIndex, size_t unColumnIndex, ITableElementCell* pCell)
|
||||
bool CTableMatrix::SetCell(size_t unRowIndex, size_t unColumnIndex, ITableElementCell* pCell, bool bAutoClean)
|
||||
{
|
||||
if (nullptr == pCell)
|
||||
return false;
|
||||
@ -185,7 +209,12 @@ bool CTableMatrix::SetCell(size_t unRowIndex, size_t unColumnIndex, ITableElemen
|
||||
}
|
||||
|
||||
if (nullptr != m_arCells[unRowIndex][unColumnIndex])
|
||||
delete m_arCells[unRowIndex][unColumnIndex];
|
||||
{
|
||||
pCell->SetColspan(m_arCells[unRowIndex][unColumnIndex]->GetColspan());
|
||||
|
||||
if (bAutoClean)
|
||||
delete m_arCells[unRowIndex][unColumnIndex];
|
||||
}
|
||||
|
||||
m_arCells[unRowIndex][unColumnIndex] = pCell;
|
||||
|
||||
@ -255,6 +284,17 @@ const ITableElementCell* CTableMatrix::GetCell(size_t unRowIndex, size_t unColum
|
||||
return m_arCells[unRowIndex][unColumnIndex];
|
||||
}
|
||||
|
||||
ITableElementCell* CTableMatrix::GetCell(size_t unRowIndex, size_t unColumnIndex)
|
||||
{
|
||||
if (unRowIndex >= m_arCells.size())
|
||||
return nullptr;
|
||||
|
||||
if (unColumnIndex >= m_arCells[unRowIndex].size())
|
||||
return nullptr;
|
||||
|
||||
return m_arCells[unRowIndex][unColumnIndex];
|
||||
}
|
||||
|
||||
CTableElement::CTableElement(TExternalTableData &oExternalData)
|
||||
: m_pCaption(nullptr), m_oExternalData(oExternalData)
|
||||
{}
|
||||
@ -282,11 +322,6 @@ void CTableElement::Clear()
|
||||
m_oFoother.Clear();
|
||||
}
|
||||
|
||||
ETableElement CTableElement::GetType() const
|
||||
{
|
||||
return ETableElement::Table;
|
||||
}
|
||||
|
||||
bool CTableElement::Empty() const
|
||||
{
|
||||
return m_oHeader.Empty() && m_oBody.Empty() && m_oFoother.Empty();
|
||||
@ -351,6 +386,33 @@ bool MoveToNextTableCell(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::C
|
||||
return false;
|
||||
}
|
||||
|
||||
CTableContainer::CTableContainer()
|
||||
: ITableElementCell(1)
|
||||
{}
|
||||
|
||||
CTableContainer::~CTableContainer()
|
||||
{
|
||||
for (const CTableElement* pTable : m_arTables)
|
||||
if (nullptr != pTable)
|
||||
delete pTable;
|
||||
}
|
||||
|
||||
ETableElement CTableContainer::GetType() const
|
||||
{
|
||||
return ETableElement::TableContainer;
|
||||
}
|
||||
|
||||
void CTableContainer::AddTable(CTableElement* pTable)
|
||||
{
|
||||
if (nullptr != pTable)
|
||||
m_arTables.push_back(pTable);
|
||||
}
|
||||
|
||||
const std::vector<CTableElement*>& CTableContainer::GetTables() const
|
||||
{
|
||||
return m_arTables;
|
||||
}
|
||||
|
||||
CTableCol::CTableCol(NSCSS::CNode& oTableColNode)
|
||||
: m_pStyle(oTableColNode.m_pCompiledStyle)
|
||||
{
|
||||
|
||||
@ -29,28 +29,46 @@ enum class ETableElement
|
||||
FillingCell,
|
||||
Cell,
|
||||
FlatTable,
|
||||
Table
|
||||
TableContainer
|
||||
};
|
||||
|
||||
// !TODO!:: At the moment, I don't really like the implementation where there is a table inside a cell,
|
||||
// or when there are multiple nested tables inside a cell
|
||||
|
||||
// Perhaps it's worth doing it as follows:
|
||||
// ITableCell -> CTableCell (A regular cell that does not contain nested tables)
|
||||
// -> CTableCellContainer (Stores anything (like default, but has a container for storing nested tables))
|
||||
|
||||
class ITableElementCell
|
||||
{
|
||||
size_t m_unColspan;
|
||||
protected:
|
||||
ITableElementCell(size_t unColspan);
|
||||
public:
|
||||
ITableElementCell() = default;
|
||||
virtual ~ITableElementCell() = default;
|
||||
|
||||
virtual ETableElement GetType() const = 0;
|
||||
|
||||
void SetColspan(size_t unColspan);
|
||||
|
||||
size_t GetColspan() const;
|
||||
};
|
||||
|
||||
class CTableElementCell : public ITableElementCell
|
||||
{
|
||||
ETableElement m_eType;
|
||||
|
||||
protected:
|
||||
CTableElementCell(bool bIsFilling, size_t unColspan);
|
||||
public:
|
||||
CTableElementCell(bool bIsFilling = false);
|
||||
virtual ~CTableElementCell();
|
||||
|
||||
ETableElement GetType() const override;
|
||||
|
||||
void IsFlatTable();
|
||||
|
||||
static CTableElementCell* CreateCell(const size_t& unColspan = 1);
|
||||
static CTableElementCell* CreateFillingCell(const size_t& unColspan = 1);
|
||||
};
|
||||
|
||||
class ITag;
|
||||
@ -60,9 +78,15 @@ struct TExternalTableData
|
||||
{
|
||||
typedef std::function<bool(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors)> FuncReadStream;
|
||||
typedef std::function<void(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors)> FuncGetSubClass;
|
||||
typedef std::function<bool(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors)> FuncReadInside;
|
||||
typedef std::function<void(const std::wstring& wsTag)> FuncAddStopTag;
|
||||
typedef std::function<void()> FuncClearStopTags;
|
||||
|
||||
FuncReadStream ReadStream;
|
||||
FuncGetSubClass GetSubClass;
|
||||
FuncReadStream ReadStream;
|
||||
FuncGetSubClass GetSubClass;
|
||||
FuncReadInside ReadInside;
|
||||
FuncAddStopTag AddStopTag;
|
||||
FuncClearStopTags ClearStopTags;
|
||||
|
||||
IWriter* m_pWriter{nullptr};
|
||||
};
|
||||
@ -82,7 +106,7 @@ public:
|
||||
|
||||
void Clear();
|
||||
|
||||
bool SetCell(size_t unRowIndex, size_t unColumnIndex, ITableElementCell* pCell);
|
||||
bool SetCell(size_t unRowIndex, size_t unColumnIndex, ITableElementCell* pCell, bool bAutoClean = true);
|
||||
|
||||
void NormalizeNumberColumns(size_t unNumberColumns);
|
||||
|
||||
@ -94,7 +118,9 @@ public:
|
||||
|
||||
const Table& GetMatrixCells() const;
|
||||
Table& GetMatrixCells();
|
||||
|
||||
const ITableElementCell* GetCell(size_t unRowIndex, size_t unColumnIndex) const;
|
||||
ITableElementCell* GetCell(size_t unRowIndex, size_t unColumnIndex);
|
||||
protected:
|
||||
Table m_arCells;
|
||||
};
|
||||
@ -131,7 +157,7 @@ private:
|
||||
UINT m_unTotalSpans;
|
||||
};
|
||||
|
||||
class CTableElement : public ITableElementCell
|
||||
class CTableElement
|
||||
{
|
||||
protected:
|
||||
CTableElement(TExternalTableData &oExternalData);
|
||||
@ -140,8 +166,6 @@ public:
|
||||
|
||||
void Clear();
|
||||
|
||||
ETableElement GetType() const override;
|
||||
|
||||
bool Empty() const;
|
||||
bool HaveCaption() const;
|
||||
|
||||
@ -169,6 +193,31 @@ protected:
|
||||
inline bool ParseMatrix(XmlUtils::CXmlLiteReader& oReader, CTableMatrix* pMatrix, size_t& unRowIndex, size_t& unColumnIndex);
|
||||
};
|
||||
|
||||
class CTableContainer : public ITableElementCell
|
||||
{
|
||||
public:
|
||||
CTableContainer();
|
||||
virtual ~CTableContainer();
|
||||
|
||||
ETableElement GetType() const override;
|
||||
|
||||
void AddTable(CTableElement* pTable);
|
||||
const std::vector<CTableElement*>& GetTables() const;
|
||||
private:
|
||||
std::vector<CTableElement*> m_arTables;
|
||||
};
|
||||
|
||||
struct TTableData
|
||||
{
|
||||
CTableMatrix m_oHeader;
|
||||
CTableMatrix m_oBody;
|
||||
CTableMatrix m_oFoother;
|
||||
|
||||
XmlString *m_pCaption;
|
||||
|
||||
std::vector<CTableColgroup*> m_arColgroups;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline bool CTableElement::ParseTable(XmlUtils::CXmlLiteReader& oReader, T* pTable)
|
||||
{
|
||||
@ -208,7 +257,21 @@ inline bool CTableElement::ParseMatrix(XmlUtils::CXmlLiteReader& oReader, CTable
|
||||
if (nullptr == pNewTable)
|
||||
return false;
|
||||
|
||||
pMatrix->SetCell(unRowIndex - 1, unColumnIndex - 1, pNewTable);
|
||||
ITableElementCell* pTableElement{pMatrix->GetCell(unRowIndex - 1, unColumnIndex - 1)};
|
||||
CTableContainer *pContainer{nullptr};
|
||||
|
||||
if (nullptr != pTableElement && ETableElement::TableContainer == pTableElement->GetType())
|
||||
pContainer = dynamic_cast<CTableContainer*>(pTableElement);
|
||||
else
|
||||
{
|
||||
pContainer = new CTableContainer();
|
||||
pMatrix->SetCell(unRowIndex - 1, unColumnIndex - 1, pContainer);
|
||||
}
|
||||
|
||||
if (nullptr == pContainer)
|
||||
return false;
|
||||
|
||||
pContainer->AddTable(pNewTable);
|
||||
|
||||
ParseTable<T>(oReader, pNewTable);
|
||||
}
|
||||
@ -233,26 +296,26 @@ inline bool CTableElement::ParseMatrix(XmlUtils::CXmlLiteReader& oReader, CTable
|
||||
while (pMatrix->IsFillingCell(unRowIndex - 1, unColumnIndex - 1))
|
||||
++unColumnIndex;
|
||||
|
||||
if (!pMatrix->SetCell(unRowIndex - 1, unColumnIndex - 1, new CTableElementCell()))
|
||||
return false;
|
||||
size_t unRowspan{1}, unColspan{1};
|
||||
|
||||
if (oReader.MoveToFirstAttribute())
|
||||
{
|
||||
do
|
||||
{
|
||||
if (L"rowspan" == oReader.GetName())
|
||||
{
|
||||
const int nRowSpan{NSStringFinder::ToInt(oReader.GetText(), 1)};
|
||||
|
||||
for (int nRow = 1; nRow < nRowSpan; ++nRow)
|
||||
pMatrix->SetCell(unRowIndex + nRow - 1, unColumnIndex - 1, new CTableElementCell(true));
|
||||
}
|
||||
unRowspan = NSStringFinder::ToInt(oReader.GetText(), 1);
|
||||
else if (L"colspan" == oReader.GetName())
|
||||
unColumnIndex += NSStringFinder::ToInt(oReader.GetText(), 1) - 1;
|
||||
unColspan = NSStringFinder::ToInt(oReader.GetText(), 1);
|
||||
}while (oReader.MoveToNextAttribute());
|
||||
oReader.MoveToElement();
|
||||
}
|
||||
|
||||
if (!pMatrix->SetCell(unRowIndex - 1, unColumnIndex - 1, CTableElementCell::CreateCell(unColspan)))
|
||||
return false;
|
||||
|
||||
for (size_t unRow = 1; unRow < unRowspan; ++unRow)
|
||||
pMatrix->SetCell(unRowIndex + unRow - 1, unColumnIndex - 1, CTableElementCell::CreateFillingCell(unColspan));
|
||||
|
||||
const int nDepth{oReader.GetDepth()};
|
||||
while (oReader.ReadNextSiblingNode(nDepth))
|
||||
ParseMatrix<T>(oReader, pMatrix, unRowIndex, unColumnIndex);
|
||||
|
||||
@ -15,8 +15,6 @@
|
||||
#include "../../DesktopEditor/graphics/pro/Graphics.h"
|
||||
#include "../../DesktopEditor/raster/BgraFrame.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
namespace HTML
|
||||
{
|
||||
template<>
|
||||
@ -637,9 +635,9 @@ void CCodeTag<CMDWriter>::Close()
|
||||
m_pWriter->OutCode();
|
||||
}
|
||||
|
||||
bool IsTable(const ITableElementCell* pCell)
|
||||
bool IsTableContainer(const ITableElementCell* pCell)
|
||||
{
|
||||
return nullptr != pCell && ETableElement::Table == pCell->GetType();
|
||||
return nullptr != pCell && ETableElement::TableContainer == pCell->GetType();
|
||||
}
|
||||
|
||||
CMarkdownTable::CMarkdownTable(TExternalTableData &oExternalData)
|
||||
@ -665,10 +663,10 @@ void CMarkdownTable::Normalize()
|
||||
size_t unMaxColumns{m_oBody.GetColumnSize()};
|
||||
|
||||
if (!m_oHeader.Empty())
|
||||
unMaxColumns = std::max(unMaxColumns, m_oHeader.GetColumnSize());
|
||||
unMaxColumns = (std::max)(unMaxColumns, m_oHeader.GetColumnSize());
|
||||
|
||||
if (!m_oFoother.Empty())
|
||||
unMaxColumns = std::max(unMaxColumns, m_oFoother.GetColumnSize());
|
||||
unMaxColumns = (std::max)(unMaxColumns, m_oFoother.GetColumnSize());
|
||||
|
||||
#define NORMALIZE_NUMBER_COLUMN(table_variable)\
|
||||
if (!table_variable.Empty() && unMaxColumns != table_variable.GetColumnSize())\
|
||||
@ -679,7 +677,8 @@ void CMarkdownTable::Normalize()
|
||||
NORMALIZE_NUMBER_COLUMN(m_oFoother);
|
||||
}
|
||||
|
||||
typedef std::queue<std::pair<std::pair<size_t, size_t>, NSStringUtils::CStringBuilder*>> NestedCells;
|
||||
|
||||
typedef std::map<std::pair<size_t, size_t>, NSStringUtils::CStringBuilder*> NestedCells;
|
||||
|
||||
inline void WriteRowStart(CMDWriter& oWriter)
|
||||
{
|
||||
@ -697,21 +696,47 @@ inline void WriteCellSeparator(CMDWriter& oWriter)
|
||||
oWriter.WriteOpenSpecialString(L" | ");
|
||||
}
|
||||
|
||||
void ReadNestedCells(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors, TCurentTablePosition& oPosition, NestedCells& arNestedCells, const Table& oCells, CMDWriter* pWriter, const TExternalTableData& oExternalTableData)
|
||||
// TODO: Instead of handling the different parsing behavior for nested tables
|
||||
// (when a cell contains both a table and data),
|
||||
// you can set a specific parsing method in HTMLReader and replace
|
||||
// it with the desired one. As a result,
|
||||
// everything except the table will be parsed using HTMLReader,
|
||||
// while reading the nested table will be done using the newly set method.
|
||||
|
||||
void ReadNestedCells(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors, TCurentTablePosition& oPosition, NestedCells& arNestedCells, const Table& oCells, CMDWriter* pWriter, const TExternalTableData& oExternalTableData, NSStringUtils::CStringBuilder& oIntermediateData);
|
||||
|
||||
void ReadNestedTable(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors, TCurentTablePosition& oPosition, NestedCells& arNestedCells, const Table& oCells, CMDWriter* pWriter, const TExternalTableData& oExternalTableData, NSStringUtils::CStringBuilder& oIntermediateData)
|
||||
{
|
||||
TCurentTablePosition oNestedPosition{oPosition};
|
||||
|
||||
oNestedPosition.m_unStartRowIndex = oPosition.m_unRowIndex;
|
||||
oNestedPosition.m_unStartColumnIndex = oPosition.m_unColumnIndex;
|
||||
|
||||
std::vector<NSCSS::CNode> arNestedSelectors{arSelectors.back()};
|
||||
|
||||
ReadNestedCells(oReader, arNestedSelectors, oNestedPosition, arNestedCells, oCells, pWriter, oExternalTableData, oIntermediateData);
|
||||
|
||||
oPosition.m_unRowIndex = oNestedPosition.m_unRowIndex;
|
||||
}
|
||||
|
||||
void ReadNestedCells(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode>& arSelectors, TCurentTablePosition& oPosition, NestedCells& arNestedCells, const Table& oCells, CMDWriter* pWriter, const TExternalTableData& oExternalTableData, NSStringUtils::CStringBuilder& oIntermediateData)
|
||||
{
|
||||
const int nDepth{oReader.GetDepth()};
|
||||
|
||||
while(oReader.ReadNextSiblingNode(nDepth))
|
||||
while(oReader.ReadNextSiblingNode2(nDepth))
|
||||
{
|
||||
const std::wstring wsName = oReader.GetName();
|
||||
|
||||
oExternalTableData.GetSubClass(oReader, arSelectors);
|
||||
|
||||
if (L"td" == wsName || L"th" == wsName)
|
||||
{
|
||||
const ITableElementCell* pCell{oCells[oPosition.m_unRowIndex][oPosition.m_unColumnIndex]};
|
||||
|
||||
if ((oPosition.m_unRowIndex != oPosition.m_unStartRowIndex || oPosition.m_unColumnIndex != oPosition.m_unStartColumnIndex) &&
|
||||
ETableElement::FlatTable == oCells[oPosition.m_unRowIndex][oPosition.m_unColumnIndex]->GetType())
|
||||
(nullptr != pCell && ETableElement::FlatTable == pCell->GetType()))
|
||||
{
|
||||
ReadNestedCells(oReader, arSelectors, oPosition, arNestedCells, oCells, pWriter, oExternalTableData);
|
||||
ReadNestedCells(oReader, arSelectors, oPosition, arNestedCells, oCells, pWriter, oExternalTableData, oIntermediateData);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -719,14 +744,33 @@ void ReadNestedCells(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode
|
||||
|
||||
if (nullptr != pCellData)
|
||||
{
|
||||
pCellData->Write(oIntermediateData);
|
||||
oIntermediateData.Clear();
|
||||
|
||||
pWriter->SetDataOutput(pCellData);
|
||||
oExternalTableData.ReadStream(oReader, arSelectors);
|
||||
if (oPosition.m_unColumnIndex != oCells[oPosition.m_unRowIndex].size() - 1)
|
||||
WriteCellSeparator(*pWriter);
|
||||
pWriter->RevertDataOutput();
|
||||
}
|
||||
|
||||
arNestedCells.push(std::make_pair(std::make_pair(oPosition.m_unRowIndex, oPosition.m_unColumnIndex), pCellData));
|
||||
while (nullptr != oCells[oPosition.m_unRowIndex][oPosition.m_unColumnIndex])
|
||||
{
|
||||
if (ETableElement::FillingCell == oCells[oPosition.m_unRowIndex][oPosition.m_unColumnIndex]->GetType())
|
||||
oPosition.m_unColumnIndex += oCells[oPosition.m_unRowIndex][oPosition.m_unColumnIndex]->GetColspan();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
arNestedCells[{oPosition.m_unRowIndex, oPosition.m_unColumnIndex}] = pCellData;
|
||||
|
||||
if (oReader.MoveToFirstAttribute())
|
||||
{
|
||||
do
|
||||
{
|
||||
if (L"colspan" == oReader.GetName())
|
||||
oPosition.m_unColumnIndex += NSStringFinder::ToInt(oReader.GetText(), 1) - 1;
|
||||
}while (oReader.MoveToNextAttribute());
|
||||
oReader.MoveToElement();
|
||||
}
|
||||
|
||||
//READ and add to nested cells
|
||||
++oPosition.m_unColumnIndex;
|
||||
@ -735,25 +779,47 @@ void ReadNestedCells(XmlUtils::CXmlLiteReader& oReader, std::vector<NSCSS::CNode
|
||||
{
|
||||
oPosition.m_unColumnIndex = oPosition.m_unStartColumnIndex;
|
||||
|
||||
ReadNestedCells(oReader, arSelectors, oPosition, arNestedCells, oCells, pWriter, oExternalTableData);
|
||||
ReadNestedCells(oReader, arSelectors, oPosition, arNestedCells, oCells, pWriter, oExternalTableData, oIntermediateData);
|
||||
|
||||
++oPosition.m_unRowIndex;
|
||||
}
|
||||
else if (L"table" == wsName)
|
||||
{
|
||||
TCurentTablePosition oNestedPosition{oPosition};
|
||||
|
||||
oNestedPosition.m_unStartRowIndex = oPosition.m_unRowIndex;
|
||||
oNestedPosition.m_unStartColumnIndex = oPosition.m_unColumnIndex;
|
||||
|
||||
std::vector<NSCSS::CNode> arNestedSelectors{arSelectors.back()};
|
||||
|
||||
ReadNestedCells(oReader, arNestedSelectors, oNestedPosition, arNestedCells, oCells, pWriter, oExternalTableData);
|
||||
|
||||
oPosition.m_unRowIndex = oNestedPosition.m_unRowIndex;
|
||||
}
|
||||
ReadNestedTable(oReader, arSelectors, oPosition, arNestedCells, oCells, pWriter, oExternalTableData, oIntermediateData);
|
||||
else if (L"caption" == wsName)
|
||||
continue;
|
||||
else if (L"tbody" == wsName || L"thead" == wsName || L"tfoot" == wsName)
|
||||
ReadNestedCells(oReader, arSelectors, oPosition, arNestedCells, oCells, pWriter, oExternalTableData, oIntermediateData);
|
||||
else
|
||||
ReadNestedCells(oReader, arSelectors, oPosition, arNestedCells, oCells, pWriter, oExternalTableData);
|
||||
{
|
||||
const size_t unCurrentIntermediateDataSize{oIntermediateData.GetCurSize()};
|
||||
|
||||
pWriter->SetDataOutput(&oIntermediateData);
|
||||
oExternalTableData.ReadInside(oReader, arSelectors);
|
||||
pWriter->RevertDataOutput();
|
||||
|
||||
if (unCurrentIntermediateDataSize != oIntermediateData.GetCurSize())
|
||||
oIntermediateData.WriteString(L" ");
|
||||
|
||||
if (L"table" != oReader.GetName())
|
||||
continue;
|
||||
|
||||
ReadNestedTable(oReader, arSelectors, oPosition, arNestedCells, oCells, pWriter, oExternalTableData, oIntermediateData);
|
||||
|
||||
pWriter->SetDataOutput(&oIntermediateData);
|
||||
|
||||
const int nNewDepth{oReader.GetDepth()};
|
||||
while (oReader.ReadNextSiblingNode2(nNewDepth - 1))
|
||||
oExternalTableData.ReadInside(oReader, arSelectors);
|
||||
|
||||
pWriter->RevertDataOutput();
|
||||
|
||||
if (0 != oIntermediateData.GetCurSize())
|
||||
{
|
||||
arNestedCells.rbegin()->second->WriteString(L" ");
|
||||
arNestedCells.rbegin()->second->Write(oIntermediateData);
|
||||
oIntermediateData.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
arSelectors.pop_back();
|
||||
}
|
||||
@ -771,7 +837,7 @@ bool CMarkdownTable::Convert(XmlUtils::CXmlLiteReader& oReader, const NSCSS::CNo
|
||||
|
||||
std::vector<NSCSS::CNode> arTableSelectors{oTableNode};
|
||||
|
||||
pWriter->WriteBreakLine();
|
||||
pWriter->WriteBreakLine(false);
|
||||
|
||||
if (HaveCaption())
|
||||
WriteToStringBuilder(*m_pCaption, *pWriter->GetCurrentDocument());
|
||||
@ -806,6 +872,18 @@ bool CMarkdownTable::Convert(XmlUtils::CXmlLiteReader& oReader, const NSCSS::CNo
|
||||
WriteCellSeparator(*pWriter);
|
||||
|
||||
WriteRowEnd(*pWriter);
|
||||
|
||||
WriteRowStart(*pWriter);
|
||||
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < m_oBody.GetColumnSize(); ++unColumnIndex)
|
||||
{
|
||||
pWriter->WriteString(L"-", true);
|
||||
|
||||
if (unColumnIndex != m_oBody.GetColumnSize() - 1)
|
||||
WriteCellSeparator(*pWriter);
|
||||
}
|
||||
|
||||
WriteRowEnd(*pWriter);
|
||||
}
|
||||
//Convert body
|
||||
ConvertMatrix(oReader, arTableSelectors, m_oBody.GetMatrixCells(), pWriter);
|
||||
@ -861,46 +939,137 @@ bool CMarkdownTable::ConvertMatrix(XmlUtils::CXmlLiteReader& oReader, std::vecto
|
||||
{
|
||||
WriteRowStart(*pWriter);
|
||||
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < oMatrix[unRowIndex].size(); ++unColumnIndex)
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < oMatrix[unRowIndex].size();)
|
||||
{
|
||||
pTableCell = oMatrix[unRowIndex][unColumnIndex];
|
||||
|
||||
if (nullptr != pTableCell && ETableElement::FillingCell != pTableCell->GetType())
|
||||
{
|
||||
if (!arNestedCells.empty() && arNestedCells.front().first == std::make_pair(unRowIndex, unColumnIndex))
|
||||
if (!arNestedCells.empty())
|
||||
{
|
||||
if (nullptr != arNestedCells.front().second)
|
||||
NestedCells::const_iterator itElement{arNestedCells.find({unRowIndex, unColumnIndex})};
|
||||
|
||||
if (arNestedCells.end() != itElement)
|
||||
{
|
||||
m_oExternalData.m_pWriter->GetCurrentDocument()->Write(*arNestedCells.front().second);
|
||||
delete arNestedCells.front().second;
|
||||
if (nullptr != itElement->second)
|
||||
{
|
||||
m_oExternalData.m_pWriter->GetCurrentDocument()->Write(*itElement->second);
|
||||
delete itElement->second;
|
||||
|
||||
if (oMatrix[unRowIndex].size() - 1 != unColumnIndex)
|
||||
WriteCellSeparator(*pWriter);
|
||||
}
|
||||
arNestedCells.erase(itElement);
|
||||
|
||||
++unColumnIndex;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
MoveToNextTableCell(oReader, arSelectors, arDepths, m_oExternalData.GetSubClass);
|
||||
|
||||
if (ETableElement::FlatTable == pTableCell->GetType())
|
||||
{
|
||||
TCurentTablePosition oPosition{unRowIndex, unColumnIndex, unRowIndex, unColumnIndex};
|
||||
std::vector<NSCSS::CNode> arNestedSelectors;
|
||||
|
||||
const int nDepth{oReader.GetDepth()};
|
||||
|
||||
NSStringUtils::CStringBuilder oTempData(100);
|
||||
bool bSetedDataOutput{false};
|
||||
|
||||
const size_t unDepthSize{arDepths.size()};
|
||||
|
||||
arDepths.push(oReader.GetDepth());
|
||||
|
||||
m_oExternalData.AddStopTag(L"table");
|
||||
|
||||
NSStringUtils::CStringBuilder oIntermediateData(100);
|
||||
|
||||
while(oReader.ReadNextSiblingNode2(nDepth))
|
||||
{
|
||||
if (L"table" == oReader.GetName())
|
||||
{
|
||||
if (bSetedDataOutput)
|
||||
{
|
||||
if (!arNestedCells.empty() && 0 != oTempData.GetCurSize())
|
||||
{
|
||||
arNestedCells.rbegin()->second->WriteString(L" ");
|
||||
arNestedCells.rbegin()->second->Write(oTempData);
|
||||
oTempData.Clear();
|
||||
}
|
||||
|
||||
pWriter->RevertDataOutput();
|
||||
bSetedDataOutput = false;
|
||||
}
|
||||
|
||||
m_oExternalData.GetSubClass(oReader, arNestedSelectors);
|
||||
ReadNestedCells(oReader, arNestedSelectors, oPosition, arNestedCells, oMatrix, pWriter, m_oExternalData, oIntermediateData);
|
||||
|
||||
oPosition.m_unColumnIndex = oPosition.m_unStartColumnIndex;
|
||||
oPosition.m_unStartRowIndex = oPosition.m_unRowIndex;
|
||||
|
||||
if (0 != oTempData.GetCurSize() && !arNestedCells.empty())
|
||||
{
|
||||
oTempData.WriteString(L" ");
|
||||
arNestedCells.begin()->second->WriteBefore(oTempData);
|
||||
oTempData.Clear();
|
||||
}
|
||||
|
||||
if (0 != oIntermediateData.GetCurSize() && !arNestedCells.empty())
|
||||
{
|
||||
arNestedCells.rbegin()->second->WriteString(L" ");
|
||||
arNestedCells.rbegin()->second->Write(oIntermediateData);
|
||||
oIntermediateData.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bSetedDataOutput)
|
||||
{
|
||||
pWriter->SetDataOutput(&oTempData);
|
||||
bSetedDataOutput = true;
|
||||
}
|
||||
|
||||
m_oExternalData.ReadInside(oReader, arSelectors);
|
||||
}
|
||||
}
|
||||
|
||||
while (arDepths.size() > unDepthSize)
|
||||
{
|
||||
arDepths.pop();
|
||||
arSelectors.pop_back();
|
||||
}
|
||||
|
||||
m_oExternalData.ClearStopTags();
|
||||
|
||||
if (bSetedDataOutput)
|
||||
{
|
||||
if (!arNestedCells.empty())
|
||||
{
|
||||
arNestedCells.rbegin()->second->WriteString(L" ");
|
||||
arNestedCells.rbegin()->second->Write(oTempData);
|
||||
}
|
||||
|
||||
pWriter->RevertDataOutput();
|
||||
}
|
||||
arNestedCells.pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveToNextTableCell(oReader, arSelectors, arDepths, m_oExternalData.GetSubClass);
|
||||
m_oExternalData.ReadStream(oReader, arSelectors);
|
||||
if (oMatrix[unRowIndex].size() - 1 != unColumnIndex)
|
||||
WriteCellSeparator(*pWriter);
|
||||
|
||||
if (ETableElement::FlatTable == pTableCell->GetType())
|
||||
{
|
||||
TCurentTablePosition oPosition{unRowIndex, unColumnIndex, unRowIndex, unColumnIndex};
|
||||
std::vector<NSCSS::CNode> arNestedSelectors;
|
||||
|
||||
ReadNestedCells(oReader, arNestedSelectors, oPosition, arNestedCells, oMatrix, pWriter, m_oExternalData);
|
||||
--unColumnIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_oExternalData.ReadStream(oReader, arSelectors);
|
||||
if (oMatrix[unRowIndex].size() - 1 != unColumnIndex)
|
||||
WriteCellSeparator(*pWriter);
|
||||
}
|
||||
arSelectors.pop_back();
|
||||
++unColumnIndex;
|
||||
}
|
||||
arSelectors.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oMatrix[unRowIndex].size() - 1 != unColumnIndex)
|
||||
WriteCellSeparator(*pWriter);
|
||||
|
||||
++unColumnIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -910,8 +1079,13 @@ bool CMarkdownTable::ConvertMatrix(XmlUtils::CXmlLiteReader& oReader, std::vecto
|
||||
{
|
||||
WriteRowStart(*pWriter);
|
||||
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < oMatrix[unRowIndex].size() - 1; ++unColumnIndex)
|
||||
pWriter->WriteString(L"-|-", true);
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < m_oBody.GetColumnSize(); ++unColumnIndex)
|
||||
{
|
||||
pWriter->WriteString(L"-", true);
|
||||
|
||||
if (unColumnIndex != m_oBody.GetColumnSize() - 1)
|
||||
WriteCellSeparator(*pWriter);
|
||||
}
|
||||
|
||||
WriteRowEnd(*pWriter);
|
||||
}
|
||||
@ -926,7 +1100,39 @@ Table CMarkdownTable::Flatten(Table&& srcTable)
|
||||
return {};
|
||||
|
||||
const size_t unRows{srcTable.size()};
|
||||
const size_t unColumns{srcTable[0].size()};
|
||||
|
||||
size_t unColumns{0}, unRowColumns{0};
|
||||
|
||||
for (const Row& oRow : srcTable)
|
||||
{
|
||||
for (ITableElementCell* pCell : oRow)
|
||||
unRowColumns += (nullptr != pCell) ? ((CTableElementCell*)pCell)->GetColspan() : 1;
|
||||
|
||||
unColumns = (std::max)(unColumns, unRowColumns);
|
||||
|
||||
unRowColumns = 0;
|
||||
}
|
||||
|
||||
size_t unColspan{1};
|
||||
|
||||
for (Row& oRow : srcTable)
|
||||
{
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < oRow.size(); ++ unColumnIndex)
|
||||
{
|
||||
if (nullptr == oRow[unColumnIndex])
|
||||
continue;
|
||||
|
||||
unColspan = oRow[unColumnIndex]->GetColspan();
|
||||
|
||||
if (1 != unColspan)
|
||||
oRow.insert(oRow.begin() + unColumnIndex + 1, unColspan - 1, nullptr);
|
||||
|
||||
unColumnIndex += unColspan - 1;
|
||||
}
|
||||
|
||||
if (oRow.size() != unColumns)
|
||||
oRow.resize(unColumns);
|
||||
}
|
||||
|
||||
std::vector<std::vector<TElementInfo>> oInfos{unRows, std::vector<TElementInfo>{unColumns}};
|
||||
|
||||
@ -941,8 +1147,8 @@ Table CMarkdownTable::Flatten(Table&& srcTable)
|
||||
{
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < unColumns; ++unColumnIndex)
|
||||
{
|
||||
arRowHeights[unRowIndex] = (std::max)(arRowHeights[unRowIndex], oInfos[unRowIndex][unColumnIndex].unRows);
|
||||
arColumnWidths[unColumnIndex] = (std::max)(arColumnWidths[unColumnIndex], oInfos[unRowIndex][unColumnIndex].unColumns);
|
||||
arRowHeights[unRowIndex] = (std::max)(arRowHeights[unRowIndex], oInfos[unRowIndex][unColumnIndex].m_unRows);
|
||||
arColumnWidths[unColumnIndex] = (std::max)(arColumnWidths[unColumnIndex], oInfos[unRowIndex][unColumnIndex].m_unColumns);
|
||||
}
|
||||
}
|
||||
|
||||
@ -971,68 +1177,229 @@ Table CMarkdownTable::Flatten(Table&& srcTable)
|
||||
if (nullptr == pCell)
|
||||
continue;
|
||||
|
||||
const TElementInfo oInfo{oInfos[unRowIndex][unColumnIndex]};
|
||||
|
||||
unBaseRow = arRowStart[unRowIndex];
|
||||
unBaseColumn = arColumnStart[unColumnIndex];
|
||||
|
||||
if (!IsTable(pCell))
|
||||
if (!IsTableContainer(pCell))
|
||||
{
|
||||
oResult[unBaseRow][unBaseColumn] = pCell;
|
||||
pCell = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
CMarkdownTable *pTable{dynamic_cast<CMarkdownTable*>(pCell)};
|
||||
|
||||
CTableContainer* pContainer{dynamic_cast<CTableContainer*>(pCell)};
|
||||
std::vector<CTableElement*> arTables{pContainer->GetTables()};
|
||||
size_t unCurrentRowOffset{0};
|
||||
|
||||
pCell = nullptr;
|
||||
|
||||
Table& oChild{pTable->m_oBody.GetMatrixCells()};
|
||||
Table oFlatChild{Flatten(std::move(oChild))};
|
||||
for (CTableElement* pTable : arTables)
|
||||
{
|
||||
TElementInfo oSubInfo{ComputeInfo(pTable)};
|
||||
|
||||
for (size_t unChildRowIndex = 0; unChildRowIndex < oInfo.unRows; ++unChildRowIndex)
|
||||
for (size_t unChildColumnIndex = 0; unChildColumnIndex < oInfo.unColumns; ++unChildColumnIndex)
|
||||
oResult[unBaseRow + unChildRowIndex][unBaseColumn + unChildColumnIndex] = oFlatChild[unChildRowIndex][unChildColumnIndex];
|
||||
Table& oChild{dynamic_cast<CMarkdownTable*>(pTable)->m_oBody.GetMatrixCells()};
|
||||
Table oFlatChild{Flatten(std::move(oChild))};
|
||||
|
||||
CTableElementCell* pFlatCell{dynamic_cast<CTableElementCell*>(oResult[unBaseRow][unBaseColumn])};
|
||||
for (size_t unChildRowIndex = 0; unChildRowIndex < oSubInfo.m_unRows; ++unChildRowIndex)
|
||||
for (size_t unChildColumnIndex = 0; unChildColumnIndex < oSubInfo.m_unColumns; ++unChildColumnIndex)
|
||||
oResult[unBaseRow + unCurrentRowOffset + unChildRowIndex][unBaseColumn + unChildColumnIndex] = oFlatChild[unChildRowIndex][unChildColumnIndex];
|
||||
|
||||
if(nullptr != pFlatCell)
|
||||
pFlatCell->IsFlatTable();
|
||||
CTableElementCell* pFlatCell{dynamic_cast<CTableElementCell*>(oResult[unBaseRow + unCurrentRowOffset][unBaseColumn])};
|
||||
|
||||
delete pTable;
|
||||
if(nullptr != pFlatCell)
|
||||
pFlatCell->IsFlatTable();
|
||||
|
||||
unCurrentRowOffset += oSubInfo.m_unRows;
|
||||
}
|
||||
|
||||
delete pContainer;
|
||||
}
|
||||
}
|
||||
|
||||
return oResult;
|
||||
}
|
||||
|
||||
// Table CMarkdownTable::Flatten(Table&& srcTable)
|
||||
// {
|
||||
// if (srcTable.empty())
|
||||
// return {};
|
||||
|
||||
// const size_t unRows = srcTable.size();
|
||||
|
||||
// // ---------- 1. Разворачиваем строки с учётом colspan ----------
|
||||
// std::vector<std::vector<ITableElementCell*>> expandedRows;
|
||||
// expandedRows.reserve(unRows);
|
||||
// size_t unColumns = 0;
|
||||
|
||||
// for (Row& oRow : srcTable)
|
||||
// {
|
||||
// std::vector<ITableElementCell*> expandedRow;
|
||||
// for (ITableElementCell* pCell : oRow)
|
||||
// {
|
||||
// if (pCell != nullptr)
|
||||
// {
|
||||
// expandedRow.push_back(pCell);
|
||||
// size_t colspan = pCell->GetColspan();
|
||||
// // Добавляем (colspan - 1) пустых ячеек справа
|
||||
// for (size_t i = 1; i < colspan; ++i)
|
||||
// expandedRow.push_back(nullptr);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// expandedRow.push_back(nullptr);
|
||||
// }
|
||||
// }
|
||||
// unColumns = std::max(unColumns, expandedRow.size());
|
||||
// expandedRows.push_back(std::move(expandedRow));
|
||||
// }
|
||||
|
||||
// // Приводим все строки к одинаковой длине
|
||||
// for (auto& row : expandedRows)
|
||||
// row.resize(unColumns, nullptr);
|
||||
|
||||
// // ---------- 2. Вычисляем информацию о размерах каждой ячейки ----------
|
||||
// std::vector<std::vector<TElementInfo>> oInfos(unRows, std::vector<TElementInfo>(unColumns));
|
||||
// for (size_t r = 0; r < unRows; ++r)
|
||||
// for (size_t c = 0; c < unColumns; ++c)
|
||||
// oInfos[r][c] = ComputeInfo(expandedRows[r][c]);
|
||||
|
||||
// // ---------- 3. Вычисляем высоты строк и ширины столбцов ----------
|
||||
// std::vector<size_t> arRowHeights(unRows, 1);
|
||||
// std::vector<size_t> arColumnWidths(unColumns, 1);
|
||||
|
||||
// for (size_t r = 0; r < unRows; ++r)
|
||||
// {
|
||||
// for (size_t c = 0; c < unColumns; ++c)
|
||||
// {
|
||||
// arRowHeights[r] = std::max(arRowHeights[r], oInfos[r][c].m_unRows);
|
||||
// arColumnWidths[c] = std::max(arColumnWidths[c], oInfos[r][c].m_unColumns);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // ---------- 4. Вычисляем смещения строк и столбцов в результирующей сетке ----------
|
||||
// std::vector<size_t> arRowStart(unRows + 1, 0);
|
||||
// std::vector<size_t> arColumnStart(unColumns + 1, 0);
|
||||
|
||||
// for (size_t r = 0; r < unRows; ++r)
|
||||
// arRowStart[r + 1] = arRowStart[r] + arRowHeights[r];
|
||||
|
||||
// for (size_t c = 0; c < unColumns; ++c)
|
||||
// arColumnStart[c + 1] = arColumnStart[c] + arColumnWidths[c];
|
||||
|
||||
// const size_t unTotalRows = arRowStart[unRows];
|
||||
// const size_t unTotalColumns = arColumnStart[unColumns];
|
||||
|
||||
// Table oResult(unTotalRows, Row(unTotalColumns, nullptr));
|
||||
|
||||
// // ---------- 5. Заполняем результат ----------
|
||||
// for (size_t r = 0; r < unRows; ++r)
|
||||
// {
|
||||
// for (size_t c = 0; c < unColumns; ++c)
|
||||
// {
|
||||
// ITableElementCell*& pCell = expandedRows[r][c];
|
||||
// if (pCell == nullptr)
|
||||
// continue;
|
||||
|
||||
// const size_t unBaseRow = arRowStart[r];
|
||||
// const size_t unBaseColumn = arColumnStart[c];
|
||||
|
||||
// // Обычная ячейка (не контейнер)
|
||||
// if (!IsTableContainer(pCell))
|
||||
// {
|
||||
// oResult[unBaseRow][unBaseColumn] = pCell;
|
||||
// pCell = nullptr;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// // Контейнер таблиц
|
||||
// CTableContainer* pContainer = dynamic_cast<CTableContainer*>(pCell);
|
||||
// std::vector<CTableElement*> arTables = pContainer->GetTables();
|
||||
// pCell = nullptr; // владение передано
|
||||
|
||||
// size_t unCurrentRowOffset = 0;
|
||||
// for (CTableElement* pTableElem : arTables)
|
||||
// {
|
||||
// // Предполагаем, что в контейнере лежат только CMarkdownTable
|
||||
// CMarkdownTable* pMarkdownTable = dynamic_cast<CMarkdownTable*>(pTableElem);
|
||||
// if (pMarkdownTable == nullptr)
|
||||
// continue;
|
||||
|
||||
// TElementInfo oSubInfo = ComputeInfo(pMarkdownTable);
|
||||
// Table& oChild = pMarkdownTable->m_oBody.GetMatrixCells();
|
||||
// Table oFlatChild = Flatten(std::move(oChild));
|
||||
|
||||
// for (size_t cr = 0; cr < oSubInfo.m_unRows; ++cr)
|
||||
// for (size_t cc = 0; cc < oSubInfo.m_unColumns; ++cc)
|
||||
// oResult[unBaseRow + unCurrentRowOffset + cr][unBaseColumn + cc] = oFlatChild[cr][cc];
|
||||
|
||||
// // Если первая ячейка сплющенной таблицы является CTableElementCell, помечаем её
|
||||
// if (auto* pFlatCell = dynamic_cast<CTableElementCell*>(oResult[unBaseRow + unCurrentRowOffset][unBaseColumn]))
|
||||
// pFlatCell->IsFlatTable();
|
||||
|
||||
// unCurrentRowOffset += oSubInfo.m_unRows;
|
||||
// }
|
||||
|
||||
// delete pContainer;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return oResult;
|
||||
// }
|
||||
|
||||
TElementInfo CMarkdownTable::ComputeInfo(const ITableElementCell* pCell)
|
||||
{
|
||||
if (!IsTable(pCell))
|
||||
if (IsTableContainer(pCell))
|
||||
{
|
||||
const std::vector<CTableElement*> arTables{((CTableContainer*)pCell)->GetTables()};
|
||||
|
||||
TElementInfo oElementInfo, oTempInfo;
|
||||
|
||||
for (CTableElement* pTable : arTables)
|
||||
{
|
||||
oTempInfo = ComputeInfo(pTable);
|
||||
|
||||
oElementInfo.m_unColumns = std::max(oElementInfo.m_unColumns, oTempInfo.m_unColumns);
|
||||
oElementInfo.m_unRows += oTempInfo.m_unRows;
|
||||
}
|
||||
|
||||
return oElementInfo;
|
||||
}
|
||||
|
||||
return {1, 1};
|
||||
}
|
||||
|
||||
TElementInfo CMarkdownTable::ComputeInfo(const CTableElement* pTable)
|
||||
{
|
||||
if (nullptr == pTable)
|
||||
return {1, 1};
|
||||
|
||||
const CMarkdownTable *pMarkdownTable{dynamic_cast<const CMarkdownTable*>(pCell)};
|
||||
const CMarkdownTable *pMarkdownTable{dynamic_cast<const CMarkdownTable*>(pTable)};
|
||||
|
||||
if (nullptr == pMarkdownTable)
|
||||
return {1, 1};
|
||||
|
||||
const CTableMatrix *pTable{&pMarkdownTable->m_oBody};
|
||||
const CTableMatrix *pTableMaxtix{&pMarkdownTable->m_oBody};
|
||||
|
||||
const size_t unRows{pTable->GetRowSize()};
|
||||
const size_t unColumns{pTable->GetColumnSize()};
|
||||
const size_t unRows{pTableMaxtix->GetRowSize()};
|
||||
const size_t unColumns{pTableMaxtix->GetColumnSize()};
|
||||
|
||||
std::vector<size_t> arRowHeights(unRows, 1);
|
||||
std::vector<size_t> arColumnWidths(unColumns, 1);
|
||||
|
||||
const Table& arCells{pTable->GetMatrixCells()};
|
||||
const Table& arCells{pTableMaxtix->GetMatrixCells()};
|
||||
|
||||
for (size_t unRowIndex = 0; unRowIndex < unRows; ++unRowIndex)
|
||||
{
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < unColumns; ++unColumnIndex)
|
||||
{
|
||||
TElementInfo oInfo{ComputeInfo(arCells[unRowIndex][unColumnIndex])};
|
||||
TElementInfo oInfo{1, arCells[unRowIndex][unColumnIndex]->GetColspan()};
|
||||
|
||||
arRowHeights[unRowIndex] = (std::max)(arRowHeights[unRowIndex], oInfo.unRows);
|
||||
arColumnWidths[unColumnIndex] = (std::max)(arColumnWidths[unColumnIndex], oInfo.unColumns);
|
||||
if (IsTableContainer(arCells[unRowIndex][unColumnIndex]))
|
||||
oInfo = ComputeInfo(arCells[unRowIndex][unColumnIndex]);
|
||||
|
||||
arRowHeights[unRowIndex] = (std::max)(arRowHeights[unRowIndex], oInfo.m_unRows);
|
||||
arColumnWidths[unColumnIndex] = (std::max)(arColumnWidths[unColumnIndex], oInfo.m_unColumns);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -55,8 +55,16 @@ void CCodeTag<CMDWriter>::Close();
|
||||
|
||||
struct TElementInfo
|
||||
{
|
||||
size_t unRows;
|
||||
size_t unColumns;
|
||||
size_t m_unRows;
|
||||
size_t m_unColumns;
|
||||
|
||||
TElementInfo()
|
||||
: m_unRows{0}, m_unColumns{0}
|
||||
{}
|
||||
|
||||
TElementInfo(const size_t& unRows, const size_t& m_unColumns)
|
||||
: m_unRows{unRows}, m_unColumns{m_unColumns}
|
||||
{}
|
||||
};
|
||||
|
||||
class CMarkdownTable : public CTableElement
|
||||
@ -76,6 +84,7 @@ private:
|
||||
|
||||
static Table Flatten(Table&& srcTable);
|
||||
static TElementInfo ComputeInfo(const ITableElementCell* pCell);
|
||||
static TElementInfo ComputeInfo(const CTableElement* pTable);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1403,14 +1403,14 @@ void COOXMLTable::CloseRow(XmlString& oXmlString)
|
||||
oXmlString.WriteNodeEnd(L"w:tr");
|
||||
}
|
||||
|
||||
void COOXMLTable::OpenCell(XmlString& oXmlString, size_t unColumnIndex)
|
||||
void COOXMLTable::OpenCell(XmlString& oXmlString)
|
||||
{
|
||||
oXmlString.WriteNodeBegin(L"w:tc");
|
||||
}
|
||||
|
||||
void COOXMLTable::OpenCell(XmlString& oXmlString, const NSCSS::CNode& oCellNode, CTableElementCell* pCell, size_t unColumnIndex, ERowParseMode eRowParseMode, ERowPosition eRowPosition, size_t& unHeight, const TTableStyles& oTableStyles)
|
||||
void COOXMLTable::OpenCell(XmlString& oXmlString, const NSCSS::CNode& oCellNode, ITableElementCell* pCell, size_t unColumnIndex, ERowParseMode eRowParseMode, ERowPosition eRowPosition, size_t& unHeight, const TTableStyles& oTableStyles, std::unordered_map<size_t, NSCSS::CNode>& mFillingColumn)
|
||||
{
|
||||
OpenCell(oXmlString, unColumnIndex);
|
||||
OpenCell(oXmlString);
|
||||
|
||||
if (nullptr == pCell)
|
||||
return;
|
||||
@ -1450,25 +1450,8 @@ void COOXMLTable::OpenCell(XmlString& oXmlString, const NSCSS::CNode& oCellNode,
|
||||
else
|
||||
oXmlString += L"<w:tcW w:w=\"0\" w:type=\"auto\"/>";
|
||||
|
||||
std::wstring wsValue;
|
||||
|
||||
if (oCellNode.GetAttributeValue(L"colspan", wsValue))
|
||||
{
|
||||
const int nColspan{NSStringFinder::ToInt(wsValue, 1)};
|
||||
|
||||
if (1 < nColspan)
|
||||
oXmlString += L"<w:gridSpan w:val=\"" + std::to_wstring(nColspan) + L"\"/>";
|
||||
}
|
||||
|
||||
if (ETableElement::FillingCell == pCell->GetType())
|
||||
oXmlString += L"<w:vMerge w:val=\"continue\"/>";
|
||||
else if (oCellNode.GetAttributeValue(L"rowspan", wsValue))
|
||||
{
|
||||
const int nRowspan{NSStringFinder::ToInt(wsValue, 1)};
|
||||
|
||||
if (1 < nRowspan)
|
||||
oXmlString += L"<w:vMerge w:val=\"restart\"/>";
|
||||
}
|
||||
if (1 != pCell->GetColspan())
|
||||
oXmlString += L"<w:gridSpan w:val=\"" + std::to_wstring(pCell->GetColspan()) + L"\"/>";
|
||||
|
||||
const NSCSS::NSProperties::CBorder* pBorder{&oCellNode.m_pCompiledStyle->m_oBorder};
|
||||
|
||||
@ -1493,6 +1476,22 @@ void COOXMLTable::OpenCell(XmlString& oXmlString, const NSCSS::CNode& oCellNode,
|
||||
oXmlString += L"<w:tcBorders>" + wsBorders + L"</w:tcBorders>";
|
||||
}
|
||||
|
||||
std::wstring wsValue;
|
||||
|
||||
if (ETableElement::FillingCell == pCell->GetType())
|
||||
oXmlString += L"<w:vMerge w:val=\"continue\"/>";
|
||||
else if (oCellNode.GetAttributeValue(L"rowspan", wsValue))
|
||||
{
|
||||
const int nRowspan{NSStringFinder::ToInt(wsValue, 1)};
|
||||
|
||||
if (1 < nRowspan)
|
||||
{
|
||||
oXmlString += L"<w:vMerge w:val=\"restart\"/>";
|
||||
mFillingColumn[unColumnIndex] = oCellNode;
|
||||
mFillingColumn[unColumnIndex].m_pCompiledStyle = new NSCSS::CCompiledStyle(*oCellNode.m_pCompiledStyle);
|
||||
}
|
||||
}
|
||||
|
||||
const NSCSS::NSProperties::CColor* pBackground{&oCellNode.m_pCompiledStyle->m_oBackground.GetColor()};
|
||||
|
||||
if (nullptr != pColStyle && pBackground->LessSignificantThen(pColStyle->m_oBackground.GetColor()))
|
||||
@ -1594,65 +1593,122 @@ void COOXMLTable::ConvertMatrix(XmlUtils::CXmlLiteReader& oReader, COOXMLWriter&
|
||||
|
||||
ITableElementCell* pTableCell{nullptr};
|
||||
size_t unCellHeight{0}, unMaxCellHeight{0};
|
||||
std::unordered_map<size_t, NSCSS::CNode> mFillingColumn;
|
||||
|
||||
for (size_t unRowIndex = 0; unRowIndex < oMatrix.size(); ++unRowIndex)
|
||||
{
|
||||
XmlString oCellsData;
|
||||
oWriter.SetDataOutput(&oCellsData);
|
||||
bool bEmptyRow{true};
|
||||
|
||||
for (size_t unColumnIndex = 0; unColumnIndex < oMatrix[unRowIndex].size(); ++unColumnIndex)
|
||||
{
|
||||
pTableCell = oMatrix[unRowIndex][unColumnIndex];
|
||||
|
||||
if (nullptr != pTableCell)
|
||||
{
|
||||
MoveToNextTableCell(oReader, arSelectors, arDepths, m_oExternalData.GetSubClass);
|
||||
|
||||
if (ETableElement::Table == pTableCell->GetType())
|
||||
{
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE)
|
||||
OpenCell(oCellsData, unColumnIndex);
|
||||
|
||||
const COOXMLTable* pTable{dynamic_cast<const COOXMLTable*>(pTableCell)};
|
||||
|
||||
if (nullptr == pTableCell)
|
||||
oWriter.WriteEmptyParagraph();
|
||||
else
|
||||
{
|
||||
arDepths.push(oReader.GetDepth());
|
||||
MoveToNextTableCell(oReader, arSelectors, arDepths, m_oExternalData.GetSubClass);
|
||||
ConvertTable(oReader, oWriter, *pTable, arSelectors.back());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE)
|
||||
OpenCell(oCellsData, arSelectors.back(), (CTableElementCell*)pTableCell, unColumnIndex, eRowParseMode,
|
||||
((0 == unRowIndex) ? ERowPosition::First : ((oMatrix.size() - 1 == unRowIndex) ? ERowPosition::Last : ERowPosition::Middle)),
|
||||
unCellHeight, oTableStyles);
|
||||
|
||||
unMaxCellHeight = (std::max)(unMaxCellHeight, unCellHeight);
|
||||
|
||||
m_oExternalData.ReadStream(oReader, arSelectors);
|
||||
}
|
||||
|
||||
oWriter.CloseP();
|
||||
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE - 1)
|
||||
CloseCell(oCellsData);
|
||||
|
||||
arSelectors.pop_back();
|
||||
}
|
||||
else
|
||||
if (nullptr == pTableCell)
|
||||
{
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE)
|
||||
OpenCell(oCellsData, unColumnIndex);
|
||||
OpenCell(oCellsData);
|
||||
|
||||
oWriter.WriteEmptyParagraph();
|
||||
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE - 1)
|
||||
CloseCell(oCellsData);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ETableElement::FillingCell == pTableCell->GetType())
|
||||
{
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE)
|
||||
{
|
||||
OpenCell(oCellsData, mFillingColumn.at(unColumnIndex), (CTableElementCell*)pTableCell, unColumnIndex, eRowParseMode,
|
||||
((0 == unRowIndex) ? ERowPosition::First : ((oMatrix.size() - 1 == unRowIndex) ? ERowPosition::Last : ERowPosition::Middle)),
|
||||
unCellHeight, oTableStyles, mFillingColumn);
|
||||
}
|
||||
|
||||
oWriter.WriteEmptyParagraph();
|
||||
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE - 1)
|
||||
CloseCell(oCellsData);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
MoveToNextTableCell(oReader, arSelectors, arDepths, m_oExternalData.GetSubClass);
|
||||
|
||||
bEmptyRow = false;
|
||||
|
||||
if (ETableElement::TableContainer == pTableCell->GetType())
|
||||
{
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE)
|
||||
OpenCell(oCellsData, arSelectors.back(), (CTableElementCell*)pTableCell, unColumnIndex, eRowParseMode,
|
||||
((0 == unRowIndex) ? ERowPosition::First : ((oMatrix.size() - 1 == unRowIndex) ? ERowPosition::Last : ERowPosition::Middle)),
|
||||
unCellHeight, oTableStyles, mFillingColumn);
|
||||
|
||||
std::vector<CTableElement*> arTables{((CTableContainer*)pTableCell)->GetTables()};
|
||||
std::vector<CTableElement*>::const_iterator itTable = arTables.cbegin();
|
||||
|
||||
const size_t unDepthSize{arDepths.size()};
|
||||
|
||||
arDepths.push(oReader.GetDepth());
|
||||
|
||||
m_oExternalData.AddStopTag(L"table");
|
||||
|
||||
#define READ_TABLE()\
|
||||
m_oExternalData.GetSubClass(oReader, arSelectors);\
|
||||
oWriter.CloseP();\
|
||||
ConvertTable(oReader, oWriter, *(COOXMLTable*)*itTable++, arSelectors.back());\
|
||||
oWriter.WriteEmptyParagraph(true);\
|
||||
arSelectors.pop_back()
|
||||
|
||||
while (oReader.ReadNextSiblingNode2(arDepths.top()))
|
||||
{
|
||||
if (L"table" == oReader.GetName())
|
||||
{
|
||||
READ_TABLE();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_oExternalData.ReadInside(oReader, arSelectors);
|
||||
|
||||
if (L"table" == oReader.GetName())
|
||||
{
|
||||
READ_TABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (arDepths.size() > unDepthSize)
|
||||
{
|
||||
arDepths.pop();
|
||||
arSelectors.pop_back();
|
||||
}
|
||||
|
||||
m_oExternalData.ClearStopTags();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE)
|
||||
OpenCell(oCellsData, arSelectors.back(), (CTableElementCell*)pTableCell, unColumnIndex, eRowParseMode,
|
||||
((0 == unRowIndex) ? ERowPosition::First : ((oMatrix.size() - 1 == unRowIndex) ? ERowPosition::Last : ERowPosition::Middle)),
|
||||
unCellHeight, oTableStyles, mFillingColumn);
|
||||
|
||||
unMaxCellHeight = (std::max)(unMaxCellHeight, unCellHeight);
|
||||
|
||||
const size_t unSelectorsSize{arSelectors.size()};
|
||||
|
||||
m_oExternalData.ReadStream(oReader, arSelectors);
|
||||
|
||||
arSelectors.resize(unSelectorsSize);
|
||||
|
||||
arSelectors.pop_back();
|
||||
}
|
||||
|
||||
oWriter.CloseP();
|
||||
|
||||
if (unColumnIndex < MAX_COLUMNS_IN_TABLE - 1)
|
||||
CloseCell(oCellsData);
|
||||
}
|
||||
|
||||
if (oMatrix[unRowIndex].size() >= MAX_COLUMNS_IN_TABLE)
|
||||
@ -1664,34 +1720,68 @@ void COOXMLTable::ConvertMatrix(XmlUtils::CXmlLiteReader& oReader, COOXMLWriter&
|
||||
WriteToStringBuilder(oCellsData, *oWriter.GetCurrentDocument());
|
||||
CloseRow(*oWriter.GetCurrentDocument());
|
||||
|
||||
arSelectors.pop_back();
|
||||
arDepths.pop();
|
||||
if (!bEmptyRow)
|
||||
{
|
||||
arSelectors.pop_back();
|
||||
arDepths.pop();
|
||||
}
|
||||
}
|
||||
|
||||
arSelectors.pop_back();
|
||||
arDepths.pop();
|
||||
}
|
||||
|
||||
inline void CalculateMaxRowSize(const Table& oMatrix, size_t& unMaxRowSize)
|
||||
{
|
||||
for (const Row& oRow : oMatrix)
|
||||
{
|
||||
size_t unCurrentSize{0};
|
||||
for (ITableElementCell* pCell : oRow)
|
||||
{
|
||||
if (nullptr == pCell || ETableElement::TableContainer == pCell->GetType())
|
||||
unCurrentSize += 1;
|
||||
else
|
||||
unCurrentSize += ((CTableElementCell*)pCell)->GetColspan();
|
||||
}
|
||||
unMaxRowSize = (std::max)(unMaxRowSize, unCurrentSize);
|
||||
}
|
||||
}
|
||||
|
||||
inline void NormalizeMatrix(Table& oMatrix, const size_t& unMaxMatrixColumns, const size_t& unMaxColumns)
|
||||
{
|
||||
for (Row& oRow : oMatrix)
|
||||
{
|
||||
for (ITableElementCell* pCell : oRow)
|
||||
{
|
||||
if (nullptr == pCell)
|
||||
continue;
|
||||
|
||||
if (ETableElement::TableContainer == pCell->GetType())
|
||||
{
|
||||
for (CTableElement* pTable : ((CTableContainer*)pCell)->GetTables())
|
||||
if (nullptr != pTable)
|
||||
pTable->Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
if (unMaxMatrixColumns != unMaxColumns)
|
||||
oRow.resize(oRow.size() + (unMaxColumns - unMaxMatrixColumns));
|
||||
}
|
||||
}
|
||||
|
||||
void COOXMLTable::Normalize()
|
||||
{
|
||||
size_t unMaxColumn{0};
|
||||
size_t unMaxColumns{0}, unHeaderRowSize{0}, unBodyRowSize{0}, unFootherRowSize{0};
|
||||
|
||||
#define CHECK_TABLE(table_variable)\
|
||||
for (const Row& oRow : table_variable.GetMatrixCells())\
|
||||
unMaxColumn = (std::max)(unMaxColumn, oRow.size())
|
||||
CalculateMaxRowSize(m_oHeader.GetMatrixCells(), unHeaderRowSize);
|
||||
CalculateMaxRowSize(m_oBody.GetMatrixCells(), unBodyRowSize);
|
||||
CalculateMaxRowSize(m_oFoother.GetMatrixCells(), unFootherRowSize);
|
||||
|
||||
CHECK_TABLE(m_oHeader);
|
||||
CHECK_TABLE(m_oBody);
|
||||
CHECK_TABLE(m_oFoother);
|
||||
unMaxColumns = (std::max)((std::max)(unHeaderRowSize, unBodyRowSize), unFootherRowSize);
|
||||
|
||||
#define NORMALIZE_TABLE(table_variable)\
|
||||
for (Row& oRow : table_variable.GetMatrixCells())\
|
||||
if (oRow.size() != unMaxColumn)\
|
||||
oRow.resize(unMaxColumn)
|
||||
|
||||
NORMALIZE_TABLE(m_oHeader);
|
||||
NORMALIZE_TABLE(m_oBody);
|
||||
NORMALIZE_TABLE(m_oFoother);
|
||||
NormalizeMatrix(m_oHeader.GetMatrixCells(), unHeaderRowSize, unMaxColumns);
|
||||
NormalizeMatrix(m_oBody.GetMatrixCells(), unBodyRowSize, unMaxColumns);
|
||||
NormalizeMatrix(m_oFoother.GetMatrixCells(), unFootherRowSize, unMaxColumns);
|
||||
}
|
||||
|
||||
bool COOXMLTable::Convert(XmlUtils::CXmlLiteReader& oReader, const NSCSS::CNode& oTableNode)
|
||||
|
||||
@ -117,7 +117,7 @@ private:
|
||||
NSCSS::NSProperties::CIndent m_oPadding;
|
||||
|
||||
TTableStyles()
|
||||
: m_unCellSpacing{0}, m_enRules{ETableRules::All}, m_pTable{nullptr}
|
||||
: m_unCellSpacing{0}, m_enRules{ETableRules::All}, m_pTable{nullptr}
|
||||
{}
|
||||
};
|
||||
|
||||
@ -141,8 +141,8 @@ private:
|
||||
void OpenRow(XmlString& oXmlString, bool bIsHeader, size_t unMaxHeight, size_t unCellSpacing);
|
||||
void CloseRow(XmlString& oXmlString);
|
||||
|
||||
void OpenCell(XmlString& oXmlString, size_t unColumnIndex);
|
||||
void OpenCell(XmlString& oXmlString, const NSCSS::CNode& oCellNode, CTableElementCell* pCell, size_t unColumnIndex, ERowParseMode eRowParseMode, ERowPosition eRowPosition, size_t& unHeight, const TTableStyles& oTableStyles);
|
||||
void OpenCell(XmlString& oXmlString);
|
||||
void OpenCell(XmlString& oXmlString, const NSCSS::CNode& oCellNode, ITableElementCell* pCell, size_t unColumnIndex, ERowParseMode eRowParseMode, ERowPosition eRowPosition, size_t& unHeight, const TTableStyles& oTableStyles, std::unordered_map<size_t, NSCSS::CNode>& mFillingColumn);
|
||||
void CloseCell(XmlString& oXmlString);
|
||||
|
||||
void ConvertTable(XmlUtils::CXmlLiteReader& oReader, COOXMLWriter& oWriter, const COOXMLTable& oTable, const NSCSS::CNode& oTableNode);
|
||||
|
||||
Reference in New Issue
Block a user