Files

1055 lines
28 KiB
C++
Raw Permalink Normal View History

2026-10-04 00:04:20 +08:00
#include "StdAfx.h"
2026-09-28 15:28:50 +08:00
#include <io.h>
#include "makeCADTable.h"
#include "CoreTools.h"
#include "shJson.h"
#include "SelectHeaderDlg.h"
using namespace SHJson;
using namespace TABLE;
#define JSON_TABLE_TEMPLATE_PATH _T("\\tableFormat.json")
namespace
{
bool parseCellMargin(WCValue &vCell, CellMargin &margin)
{
bool bUse(false);
MCIt it = vCell.FindMember(_T("Left"));
if (it != vCell.MemberEnd() && it->value.IsNumber())
{
margin.setLeft(it->value.GetDouble());
bUse = true;
}
it = vCell.FindMember(_T("Right"));
if (it != vCell.MemberEnd() && it->value.IsNumber())
{
margin.setRight(it->value.GetDouble());
bUse = true;
}
it = vCell.FindMember(_T("Top"));
if (it != vCell.MemberEnd() && it->value.IsNumber())
{
margin.setTop(it->value.GetDouble());
bUse = true;
}
it = vCell.FindMember(_T("Bottom"));
if (it != vCell.MemberEnd() && it->value.IsNumber())
{
margin.setBottom(it->value.GetDouble());
bUse = true;
}
it = vCell.FindMember(_T("HorzSpacing"));
if (it != vCell.MemberEnd() && it->value.IsNumber())
{
margin.setHorzSpacing(it->value.GetDouble());
bUse = true;
}
it = vCell.FindMember(_T("VertSpacing"));
if (it != vCell.MemberEnd() && it->value.IsNumber())
{
margin.setVertSpacing(it->value.GetDouble());
bUse = true;
}
return bUse;
}
bool parseCellStyle(WCValue &vCell, CellStyle &cell)
{
MCIt it = vCell.FindMember(_T("textStyle"));
if (it != vCell.MemberEnd() && it->value.IsString())
{
cell.setTextStyle(it->value.GetString());
}
it = vCell.FindMember(_T("textHeight"));
if (it != vCell.MemberEnd() && it->value.IsNumber())
{
cell.setTextHeight(it->value.GetDouble());
}
it = vCell.FindMember(_T("color"));
if (it != vCell.MemberEnd() && it->value.IsInt())
{
cell.setColor(it->value.GetInt());
}
it = vCell.FindMember(_T("backgroundColor"));
if (it != vCell.MemberEnd() && it->value.IsInt())
{
cell.setBackgroundColor(it->value.GetInt());
}
it = vCell.FindMember(_T("rotation"));
if (it != vCell.MemberEnd() && it->value.IsNumber())
{
cell.setRotation(it->value.GetDouble());
}
it = vCell.FindMember(_T("alignment"));
if (it != vCell.MemberEnd() && it->value.IsInt())
{
cell.setAlignment(static_cast<AcDb::CellAlignment>(it->value.GetInt()));
}
it = vCell.FindMember(_T("margin"));
if (it != vCell.MemberEnd() && it->value.IsObject())
{
cell.m_bUseMargin = parseCellMargin(it->value, cell.m_Margin);
}
it = vCell.FindMember(_T("enableMergeAll"));
if (it != vCell.MemberEnd() && it->value.IsBool())
{
cell.m_enableMergeAll = it->value.GetBool();
cell.m_bUseenableMergeAll = true;
}
return true;
}
void parseCell(WCValue &v, Cell &cell, LPCTSTR defCellStyle)
{
if (v.IsObject())
{
MCIt sub = v.FindMember(_T("text"));
if (sub != v.MemberEnd() && sub->value.IsString())
cell.text = sub->value.GetString();
else
2026-10-04 00:04:20 +08:00
cell.text = _T(""); // 占位
2026-09-28 15:28:50 +08:00
sub = v.FindMember(_T("cellstyle"));
if (sub != v.MemberEnd() && sub->value.IsString())
cell.style = sub->value.GetString();
}
else
{
cell.text = v.GetString();
cell.style = defCellStyle ? defCellStyle : _T("");
}
}
// ["", "", "",{...}]
void parseData(const CArr &ar
, const int &iRow
, std::vector<Cell> &cells
, LPCTSTR defCellStyle)
{
Cell cell;
for (int j(0); j < ar.Size(); ++j)
{
cell.row = iRow;
cell.col = j;
parseCell(ar[j], cell, defCellStyle);
cells.push_back(cell);
}
}
void parseDatas(const CArr &ar, CellTableData &tbldata, LPCTSTR defCellStyle)
{
Cells cells;
for (int i(0); i < ar.Size(); ++i)
{
cells.clear();
WCValue &v = ar[i];
if (v.IsArray())
{
parseData(v.GetArray(), i, cells, defCellStyle);
tbldata.push_back(cells);
}
else if (v.IsObject())
{
CString cellstyle(_T(""));
WCValue *pCellStyle = WPointer(_T("/cellstyle")).Get(v);
if (pCellStyle && pCellStyle->IsString())
{
cellstyle = pCellStyle->GetString();
}
WCValue *pData = WPointer(_T("/data")).Get(v);
if (pData && pData->IsArray())
{
parseData(pData->GetArray(), i, cells, cellstyle.IsEmpty() ? defCellStyle : (LPCTSTR)cellstyle);
tbldata.push_back(cells);
}
}
}
}
void parseMerges(const CArr &ar, std::vector<CellMergeRange> &merges)
{
CellMergeRange mg;
for (int i(0); i < ar.Size(); ++i)
{
WCValue &v = ar[i];
WCValue *pRStart = WPointer(_T("/row/start")).Get(v);
if (pRStart)
mg.m_minRow = pRStart->GetInt();
WCValue *pREnd = WPointer(_T("/row/end")).Get(v);
if (pREnd)
mg.m_maxRow = pREnd->GetInt();
WCValue *pCStart = WPointer(_T("/col/start")).Get(v);
if (pCStart)
mg.m_minCol = pCStart->GetInt();
WCValue *pCEnd = WPointer(_T("/col/end")).Get(v);
if (pCEnd)
mg.m_maxCol = pCEnd->GetInt();
merges.push_back(mg);
}
}
2026-10-04 00:04:20 +08:00
// 解析 json 中的 data,title,header,tail等定义字段
2026-09-28 15:28:50 +08:00
void parseDataContent(WCValue &v, DataContent &content)
{
WCValue *pCellStyle = WPointer(_T("/cellstyle")).Get(v);
if (pCellStyle && pCellStyle->IsString())
{
content.m_defCellStyle = pCellStyle->GetString();
}
WCValue *pDatas = WPointer(_T("/datas")).Get(v);
if (pDatas && pDatas->IsArray())
{
parseDatas(pDatas->GetArray(), content.m_tableData, content.m_defCellStyle);
}
}
2026-10-04 00:04:20 +08:00
// 解析 cellstyle_list
2026-09-28 15:28:50 +08:00
void parseCellStyleList(WDocument &doc, CellStyles &css)
{
WCValue *pList = WPointer(_T("/cellstyle_list")).Get(doc);
MCIt it = pList->MemberBegin();
for (; it != pList->MemberEnd(); ++it)
{
CellStyle cell;
if (parseCellStyle(it->value, cell))
{
cell.m_sName = it->name.GetString();
css[cell.m_sName] = cell;
}
}
}
2026-10-04 00:04:20 +08:00
// 解析 tablestyle_list
2026-09-28 15:28:50 +08:00
void parseTableStyleList(WDocument &doc , TableStyles &tss)
{
CellStyles css;
parseCellStyleList(doc, css);
WCValue *pList = WPointer(_T("/tablestyle_list")).Get(doc);
MCIt it = pList->MemberBegin();
TableStyle ts;
for (; it != pList->MemberEnd(); ++it)
{
ts.m_sName = it->name.GetString();
ts.m_cellStyles.clear();
MCIt subIt = it->value.MemberBegin();
for (; subIt != it->value.MemberEnd(); ++subIt)
{
CellStyles::iterator csIt(css.find(subIt->value.GetString()));
if (csIt == css.end())
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\ntablestyle:%s,使用了未在cellstyle_list中定以的cellstyle:%s")
2026-09-28 15:28:50 +08:00
, ts.m_sName
, subIt->value.GetString());
continue;
}
2026-10-04 00:04:20 +08:00
// 修改为AcDbTableStyle内的名称
2026-09-28 15:28:50 +08:00
csIt->second.m_sName = subIt->name.GetString();
ts.m_cellStyles.insert(std::make_pair(subIt->name.GetString(), csIt->second));
}
tss[ts.m_sName] = ts;
}
}
2026-10-04 00:04:20 +08:00
// 解析 TableStyle 并且新建
2026-09-28 15:28:50 +08:00
AcDbObjectId parseTableStyle(WDocument &doc, LPCTSTR pszStyle, const double &dPScale)
{
AcDbObjectId id = MKTABLE::getTableStyle(_T("Standard"));
if (!pszStyle) return id;
TableStyles tss;
parseTableStyleList(doc, tss);
2026-10-04 00:04:20 +08:00
// 先检查是否在tablestyle_list中存在
2026-09-28 15:28:50 +08:00
std::map<CString, TableStyle>::const_iterator it(tss.find(pszStyle));
2026-10-04 00:04:20 +08:00
if (it == tss.end()) // 不存在,直接返回Standard
2026-09-28 15:28:50 +08:00
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n表格样式:%s未在tablestyle_list中出现。将使用Standard表格样式"), pszStyle);
2026-09-28 15:28:50 +08:00
return id;
}
TableStyle ts = it->second;
2026-10-04 00:04:20 +08:00
// 得到tablestyle的id
2026-09-28 15:28:50 +08:00
id = MKTABLE::getTableStyle(ts.m_sName);
AcDbObjectPointer<AcDbTableStyle> tblStyle(id, AcDb::kForWrite);
if (tblStyle.openStatus() != Acad::eOk) return id;
AcStringArray names;
for (CellStyles::iterator it = ts.m_cellStyles.begin(); it != ts.m_cellStyles.end(); ++it)
{
CellStyle &cs(it->second);
2026-10-04 00:04:20 +08:00
// 如果cs不在tblStyle中,apply2CellStyle函数会自动新建
2026-09-28 15:28:50 +08:00
cs.apply2CellStyle(tblStyle, dPScale);
}
return id;
}
void getHeaders(CHeaderCtrl *pHeader, const std::vector<int> &idxs, MKTABLE::RowData &hdrs)
{
if (!pHeader) return;
CString sHeader;
HDITEM hdItem;
hdItem.mask = HDI_TEXT;
hdItem.cchTextMax = 512;
hdItem.pszText = sHeader.GetBuffer(hdItem.cchTextMax);
for (size_t j(0); j < idxs.size(); ++j)
{
if (pHeader->GetItem(idxs[j], &hdItem))
hdrs.push_back(hdItem.pszText);
else
2026-10-04 00:04:20 +08:00
hdrs.push_back(_T("")); // 即使获取失败也要占位
2026-09-28 15:28:50 +08:00
}
sHeader.ReleaseBuffer();
}
void rowData2CellRowData(const MKTABLE::RowData &rowdata
, CellRowData &cellRowData
, const int &nRow
, LPCTSTR defCellStyle)
{
Cell cell;
for (size_t nCol(0); nCol < rowdata.size(); ++nCol)
{
cell.row = nRow;
cell.col = (int)nCol;
cell.text = rowdata[nCol];
cell.style = defCellStyle ? defCellStyle : _T("");
cellRowData.push_back(cell);
}
}
2026-10-04 00:04:20 +08:00
// 对齐 CellTableData 内的列数,补齐空单元格
2026-09-28 15:28:50 +08:00
void AlignCellTableData(CellTableData &datas)
{
int nCol = 0;
for (size_t i(0); i < datas.size(); ++i)
{
if (nCol < (int)datas[i].size())
nCol = (int)datas[i].size();
}
CString cs(_T("_DATA"));
for (size_t i(0); i < datas.size(); ++i)
{
CellRowData &rowData = datas[i];
if (!rowData.empty())
cs = rowData[0].style;
while ((int)rowData.size() < nCol)
{
Cell cell;
cell.row = (int)i;
cell.col = (int)rowData.size();
cell.text = _T("");
cell.style = _T("");
rowData.push_back(cell);
}
}
}
2026-10-04 00:04:20 +08:00
// 整体解析title,header,data,tail等内容,并且汇总在一个 TableCellData 结构中
2026-09-28 15:28:50 +08:00
void parseTableContent(WCValue &tbl, const CString &title
, const MKTABLE::RowData &header
2026-10-04 00:04:20 +08:00
// 保存了分表数据
2026-09-28 15:28:50 +08:00
, const std::vector<MKTABLE::TableData> &datas
, std::vector<CellTableData> &tbldatas )
{
if (datas.empty()) return;
typedef MKTABLE::RowData RowData;
typedef MKTABLE::TableData TableData;
DataContent titleContent(_T("_TITLE"))
, headerContent(_T("_HEADER"))
, dataContent(_T("_DATA"))
, tailContent(_T("_TITLE"));
WCValue *pTitle = WPointer(_T("/title")).Get(tbl);
if (pTitle)
{
parseDataContent(*pTitle, titleContent);
}
2026-10-04 00:04:20 +08:00
// 如果没有 title 字段,或者有title制度,但内容为空,则使用传入的 title 参数
2026-09-28 15:28:50 +08:00
if (titleContent.m_tableData.empty() && !title.IsEmpty())
{
RowData rd(1, title);
CellRowData cellRowData;
rowData2CellRowData(rd, cellRowData, 0, titleContent.m_defCellStyle);
titleContent.m_tableData.push_back(cellRowData);
}
WCValue *pHeader = WPointer(_T("/header")).Get(tbl);
if (pHeader)
{
parseDataContent(*pHeader, headerContent);
}
if (headerContent.m_tableData.empty() && !header.empty())
{
CellRowData cellRowData;
rowData2CellRowData(header, cellRowData, titleContent.m_tableData.size(), headerContent.m_defCellStyle);
headerContent.m_tableData.push_back(cellRowData);
}
2026-10-04 00:04:20 +08:00
// data字段处了cellstyle被模板内定义外,其他的不应该定以,由界面传入的数据填充
2026-09-28 15:28:50 +08:00
WCValue *pData = WPointer(_T("/data")).Get(tbl);
if (pData)
{
parseDataContent(*pData, dataContent);
}
WCValue *pTail = WPointer(_T("/tail")).Get(tbl);
if (pTail)
{
parseDataContent(*pTail, tailContent);
}
2026-10-04 00:04:20 +08:00
// 这里要处理分表情况
2026-09-28 15:28:50 +08:00
tbldatas.resize(datas.size());
int startRow = (int)(titleContent.m_tableData.size() + headerContent.m_tableData.size());
for (size_t nPage(0); nPage < datas.size(); ++nPage)
{
dataContent.m_tableData.clear();
const TableData &page = datas[nPage];
2026-10-04 00:04:20 +08:00
// 每一个 td 都是一个分表
2026-09-28 15:28:50 +08:00
TableData::const_iterator it(page.begin());
CellRowData cellRowData;
for (int nRow(startRow); it != page.end(); ++it, ++nRow)
{
cellRowData.clear();
const RowData &rowdata = *it;
rowData2CellRowData(rowdata, cellRowData, nRow, dataContent.m_defCellStyle);
dataContent.m_tableData.push_back(cellRowData);
}
2026-10-04 00:04:20 +08:00
// 这里要处理一下tailContent的行号
2026-09-28 15:28:50 +08:00
for (size_t i(0); i < tailContent.m_tableData.size(); ++i)
{
CellRowData &rowData = tailContent.m_tableData[i];
for (size_t j(0); j < rowData.size(); ++j)
rowData[j].row = (int)(startRow + dataContent.m_tableData.size() + i);
}
2026-10-04 00:04:20 +08:00
// 分表的数据填充好后,和titleContent,headerContent,tailContent合并为一个完整的表格
2026-09-28 15:28:50 +08:00
CellTableData &tbldata = tbldatas[nPage];
if (!titleContent.m_tableData.empty())
tbldata.insert(tbldata.end(), titleContent.m_tableData.begin(), titleContent.m_tableData.end());
if (!headerContent.m_tableData.empty())
tbldata.insert(tbldata.end(), headerContent.m_tableData.begin(), headerContent.m_tableData.end());
if (!dataContent.m_tableData.empty())
tbldata.insert(tbldata.end(), dataContent.m_tableData.begin(), dataContent.m_tableData.end());
if (!tailContent.m_tableData.empty())
tbldata.insert(tbldata.end(), tailContent.m_tableData.begin(), tailContent.m_tableData.end());
2026-10-04 00:04:20 +08:00
// 对齐元素
2026-09-28 15:28:50 +08:00
AlignCellTableData(tbldata);
}
}
bool parseGridLineTypeProperty(WCValue &vLtp, GridLineTypeProperty &prop)
{
bool bUse(false);
MCIt it = vLtp.FindMember(_T("LineStyle"));
if (it != vLtp.MemberEnd() && it->value.IsInt())
{
prop.setLineStyle(static_cast<AcDb::GridLineStyle>(it->value.GetInt()));
bUse = true;
}
it = vLtp.FindMember(_T("LineWeight"));
if (it != vLtp.MemberEnd() && it->value.IsInt())
{
prop.setLineWeight(static_cast<AcDb::LineWeight>(it->value.GetInt()));
bUse = true;
}
it = vLtp.FindMember(_T("Linetype"));
if (it != vLtp.MemberEnd() && it->value.IsString())
{
prop.setLinetype(it->value.GetString());
bUse = true;
}
it = vLtp.FindMember(_T("Color"));
if (it != vLtp.MemberEnd() && it->value.IsInt())
{
prop.setColor(it->value.GetInt());
bUse = true;
}
it = vLtp.FindMember(_T("Visibility"));
if (it != vLtp.MemberEnd() && it->value.IsInt())
{
prop.setVisibility(static_cast<AcDb::Visibility>(it->value.GetInt()));
bUse = true;
}
it = vLtp.FindMember(_T("DoubleLineSpacing"));
if (it != vLtp.MemberEnd() && it->value.IsNumber())
{
prop.setDoubleLineSpacing(it->value.GetDouble());
bUse = true;
}
return bUse;
}
void parseGridLineTypePropertys(WCValue *pVLineType
, const AcDb::GridLineType &type
, GridLineTypePropertys &props
, const double &dPScale)
{
props.clear();
if (!pVLineType) return;
if (!pVLineType->IsArray()) return;
const CArr &ar = pVLineType->GetArray();
for (int i(0); i < ar.Size(); ++i)
{
WCValue &v = ar[i];
WCValue *pRS = WPointer(_T("/row/start")).Get(v);
if (!pRS || !pRS->IsInt()) continue;
WCValue *pRE = WPointer(_T("/row/end")).Get(v);
if (!pRE || !pRE->IsInt()) continue;
WCValue *pCS = WPointer(_T("/col/start")).Get(v);
if (!pCS || !pCS->IsInt()) continue;
WCValue *pCE = WPointer(_T("/col/end")).Get(v);
if (!pCE || !pCE->IsInt()) continue;
GridLineTypeProperty prop(type
, pRS->GetInt()
, pRE->GetInt()
, pCS->GetInt()
, pCE->GetInt()
, dPScale);
WCValue *pProps = WPointer(_T("/Property")).Get(v);
if (!pProps || !pProps->IsObject()) continue;
if (parseGridLineTypeProperty(*pProps, prop))
props.push_back(prop);
}
return;
}
#define PARSE_GLTP(v) parseGridLineTypePropertys(\
WPointer(CString(_T("/grid/"))+L#v).Get(tbl)\
, AcDb::k##v\
, gridLineType.m_##v, dPScale)
void parseGridLineType(WCValue &tbl, GridLineType &gridLineType, const double &dPScale)
{
PARSE_GLTP(HorzTop);
PARSE_GLTP(HorzInside);
PARSE_GLTP(HorzBottom);
PARSE_GLTP(VertLeft);
PARSE_GLTP(VertInside);
PARSE_GLTP(VertRight);
PARSE_GLTP(HorzGridLineTypes);
PARSE_GLTP(VertGridLineTypes);
PARSE_GLTP(InnerGridLineTypes);
PARSE_GLTP(OuterGridLineTypes);
PARSE_GLTP(AllGridLineTypes);
}
2026-10-04 00:04:20 +08:00
bool parseTableTemplage(LPCTSTR pszTemplate // 模板名称
// 传入的数据,可以是多张表的数据
2026-09-28 15:28:50 +08:00
, std::vector<MKTABLE::TableData> &datas
2026-10-04 00:04:20 +08:00
// 标题
2026-09-28 15:28:50 +08:00
, const CString &title
2026-10-04 00:04:20 +08:00
// 表头
2026-09-28 15:28:50 +08:00
, const MKTABLE::RowData &header
2026-10-04 00:04:20 +08:00
// 输出的表格数据,以TABLE::CellTableData形式保存
2026-09-28 15:28:50 +08:00
, std::vector<TABLE::CellTableData> &tabls
2026-10-04 00:04:20 +08:00
// 输出的合并单元格信息
2026-09-28 15:28:50 +08:00
, CellMerges &merges
2026-10-04 00:04:20 +08:00
// 输出的GridLineType信息
2026-09-28 15:28:50 +08:00
, GridLineType &gridLineType
2026-10-04 00:04:20 +08:00
// 表格样式ID
2026-09-28 15:28:50 +08:00
, AcDbObjectId &idTableStyle
2026-10-04 00:04:20 +08:00
// 出图比例
2026-09-28 15:28:50 +08:00
, const double &dPScale )
{
if (!pszTemplate) return false;
if (datas.empty())
{
2026-10-04 00:04:20 +08:00
AfxMessageBox(_T("数据为空!"), MB_OK | MB_ICONERROR);
2026-09-28 15:28:50 +08:00
return false;
}
CString jsonPath(FilePath::GetSysDir() + JSON_TABLE_TEMPLATE_PATH);
if (_taccess(jsonPath, 0x0) != 0x0)
{
2026-10-04 00:04:20 +08:00
AfxMessageBox(_T("表格模板文件未找到!") + jsonPath, MB_OK | MB_ICONERROR);
2026-09-28 15:28:50 +08:00
return false;
}
WDocument doc;
file2Json(jsonPath, doc);
if (doc.HasParseError())
{
2026-10-04 00:04:20 +08:00
AfxMessageBox(_T("表格模板文件json格式解析错误!") + jsonPath, MB_OK | MB_ICONERROR);
2026-09-28 15:28:50 +08:00
return false;
}
CString path(_T("/table_list/"));
path += (pszTemplate);
WCValue *pTbl = WPointer(path).Get(doc);
if (!pTbl)
{
2026-10-04 00:04:20 +08:00
AfxMessageBox(CString(_T("模板内的表格列表中未找到表格:")) + pszTemplate, MB_OK | MB_ICONERROR);
2026-09-28 15:28:50 +08:00
return NULL;
}
WCValue &tbl = *pTbl;
2026-10-04 00:04:20 +08:00
// 解析table style
2026-09-28 15:28:50 +08:00
idTableStyle = AcDbObjectId::kNull;
WCValue *pTs = WPointer(_T("/tablestyle")).Get(tbl);
if (!pTs)
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("表格模板%s缺少tablestyle定义! 表格将使用Standard表格样式。"), pszTemplate);
2026-09-28 15:28:50 +08:00
idTableStyle = MKTABLE::getTableStyle(_T("Standard"));
}
else
idTableStyle = parseTableStyle(doc, pTs->GetString(), dPScale);
2026-10-04 00:04:20 +08:00
// 解析合并单元格
2026-09-28 15:28:50 +08:00
WCValue *pMerge = WPointer(_T("/merge")).Get(tbl);
if (pMerge && pMerge->IsArray())
{
parseMerges(pMerge->GetArray(), merges);
}
2026-10-04 00:04:20 +08:00
// 解析GridLineType
2026-09-28 15:28:50 +08:00
parseGridLineType(tbl, gridLineType, dPScale);
2026-10-04 00:04:20 +08:00
// 解析表格内容
2026-09-28 15:28:50 +08:00
parseTableContent(tbl, title, header, datas, tabls);
return !tabls.empty();
}
void makeTables(const std::vector<TABLE::CellTableData> &tbls
, AcDbObjectId idTableStyle
, const TABLE::CellMerges &merges
, const TABLE::GridLineType &gridLineType
, std::vector<AcDbTable *> &dbTbls)
{
int nRow, nCol;
for (size_t pg(0); pg < tbls.size(); ++pg)
{
TABLE::CellTableData tblData = tbls[pg];
nRow = (int)tblData.size();
if (nRow == 0) continue;
nCol = (int)tblData[0].size();
if (nCol == 0) continue;
AcDbTable *pTable = new AcDbTable();
pTable->setSize(nRow, nCol);
pTable->setTableStyle(idTableStyle);
for (size_t r(0); r < tblData.size(); ++r)
{
TABLE::CellRowData &rowData = tblData[r];
for (size_t c(0); c < rowData.size(); ++c)
rowData[c].apply2Table(pTable);
}
2026-10-04 00:04:20 +08:00
// 处理合并单元格
2026-09-28 15:28:50 +08:00
TABLE::CellMergeRange mg;
for (size_t i(0); i < merges.size(); ++i)
{
mg = merges[i];
mg.apply2Table(pTable);
}
2026-10-04 00:04:20 +08:00
// 处理GridLineType
2026-09-28 15:28:50 +08:00
gridLineType.apply2Table(pTable);
dbTbls.push_back(pTable);
}
}
}
AcDbObjectId MKTABLE::getLinetype(LPCTSTR pszLinetypeName)
{
AcDbObjectId id(AcDbObjectId::kNull);
if (!pszLinetypeName) return id;
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
if (!pDb) return id;
// open linetype table
AcDbObjectId idTbl = pDb->linetypeTableId();
AcDbObjectPointer<AcDbLinetypeTable> ltt(idTbl, AcDb::kForWrite);
if (ltt.openStatus() != Acad::eOk) return id;
// if already exists, return it
if (ltt->getAt(pszLinetypeName, id) == Acad::eOk)
return id;
// try to find the Continuous linetype to clone
AcDbObjectId idStd = pDb->continuousLinetype();
if (idStd.isNull())
{
// fallback: try to lookup by name
if (ltt->getAt(_T("Continuous"), idStd) != Acad::eOk)
return AcDbObjectId::kNull;
}
AcDbObjectPointer<AcDbLinetypeTableRecord> stdRec(idStd, AcDb::kForRead);
if (stdRec.openStatus() != Acad::eOk) return id;
// clone standard, rename and add to table
AcDbLinetypeTableRecord *pNew = (AcDbLinetypeTableRecord *)stdRec->clone();
if (!pNew) return id;
pNew->setName(pszLinetypeName);
Acad::ErrorStatus es = ltt->add(id, pNew);
// close the newly added record (or the clone if add failed)
pNew->close();
if (es != Acad::eOk)
{
id = AcDbObjectId::kNull;
}
return id;
}
AcDbObjectId MKTABLE::getTextStyle(LPCTSTR pszTSName)
{
AcDbObjectId id(AcDbObjectId::kNull);
if (!pszTSName) return id;
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
if (!pDb) return id;
// open text style table
AcDbObjectId idTbl = pDb->textStyleTableId();
AcDbObjectPointer<AcDbTextStyleTable> tbl(idTbl, AcDb::kForWrite);
if (tbl.openStatus() != Acad::eOk) return id;
// if already exists, return it
if (tbl->getAt(pszTSName, id) == Acad::eOk)
return id;
// find Standard style to clone
AcDbObjectId idStd;
if (tbl->getAt(_T("Standard"), idStd) != Acad::eOk) return id;
AcDbObjectPointer<AcDbTextStyleTableRecord> stdRec(idStd, AcDb::kForRead);
if (stdRec.openStatus() != Acad::eOk) return id;
// clone standard, rename and add to table
AcDbTextStyleTableRecord *pNew = (AcDbTextStyleTableRecord*)stdRec->clone();
if (!pNew) return id;
pNew->setName(pszTSName);
Acad::ErrorStatus es = tbl->add(id, pNew);
// close the newly added record (or the clone if add failed)
pNew->close();
if (es != Acad::eOk)
{
id = AcDbObjectId::kNull;
}
return id;
}
AcDbObjectId MKTABLE::getTableStyle(LPCTSTR pszTSName)
{
AcDbObjectId id(AcDbObjectId::kNull);
if (!pszTSName) return id;
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
if (!pDb) return id;
AcDbObjectId idDict = pDb->tableStyleDictionaryId();
AcDbObjectPointer<AcDbDictionary> dict(idDict, AcDb::kForWrite);
if (dict.openStatus() != Acad::eOk) return id;
if (dict->getAt(pszTSName, id) == Acad::eOk)
{
2026-10-04 00:04:20 +08:00
return id; // 已存在
2026-09-28 15:28:50 +08:00
}
2026-10-04 00:04:20 +08:00
// Standard 是默认样式,目前CAD无法删除它
2026-09-28 15:28:50 +08:00
if (dict->getAt(_T("Standard"), id) != Acad::eOk) return id;
AcDbObjectPointer<AcDbTableStyle> ts(id, AcDb::kForRead);
if (ts.openStatus() != Acad::eOk) return id;
AcDbTableStyle *pNewTS = (AcDbTableStyle*)ts->clone();
pNewTS->setName(pszTSName);
dict->setAt(pszTSName, pNewTS, id);
pNewTS->close();
return id;
}
bool MKTABLE::extractDatasFromListCtrl(CListCtrl &listCtrl
, std::vector<TableData> &outDatas
, RowData &outHeaderData
, const std::vector<int> &idxs
, const int &maxRow)
{
int count(listCtrl.GetItemCount());
if (!count) return false;
std::vector<CString> rowRec;
getHeaders(listCtrl.GetHeaderCtrl(), idxs, outHeaderData);
int nMaxRow = maxRow <= 0 ? count : maxRow;
int tableNum = (int)((double)count / nMaxRow);
int theRest = count % nMaxRow;
if (theRest > 0)
++tableNum;
TableData data;
for (int t(0); t < tableNum; ++t)
{
data.clear();
for (int i(t * nMaxRow); i < (t + 1) * nMaxRow; ++i)
{
rowRec.clear();
data.push_back(rowRec);
for (size_t j(0); j < idxs.size(); ++j)
{
if (i >= count)
data.rbegin()->push_back(_T(""));
else
data.rbegin()->push_back(listCtrl.GetItemText(i, idxs[j]));
}
}
outDatas.push_back(data);
}
return !outDatas.empty();
}
void MKTABLE::selectColumnsFromListCtrl(CHeaderCtrl &headerCtrl
, std::vector<int> &idxs
, double &dPScale
, CString &sTemplate)
{
CAcModuleResourceOverride resOverride;
CSelectHeaderDlg selHdrDlg(&headerCtrl);
selHdrDlg.DoModal();
idxs = selHdrDlg.m_idxOfColumns;
sTemplate = selHdrDlg.m_sTemplate;
dPScale = selHdrDlg.m_dPScale;
}
void MKTABLE::autoSizeTable(AcDbTable *pTable)
{
if (!pTable) return;
// Get table size
int nRows = pTable->numRows();
int nCols = pTable->numColumns();
if (nRows <= 0 || nCols <= 0) return;
AcDbObjectId idStyle = pTable->tableStyle();
AcDbObjectPointer<AcDbTableStyle> pTableStyle(idStyle, AcDb::kForRead);
if (pTableStyle.openStatus() != Acad::eOk) return;
std::vector<double> colWidths(nCols, .0);
std::vector<double> rowHeights(nRows, .0);
AcDbText dbText;
AcDbExtents ext;
AcDbObjectId cellTextStyleId;
CString sCellStyle, sContent;
double dTop, dBottom, dLeft, dRight, dHorzSpacing, dVertSpacing;
double dTextHeight;
double dCellWidth, dCellHeight;
for (int r = 0; r < nRows; ++r)
{
for (int c = 0; c < nCols; ++c)
{
sCellStyle = pTable->cellStyle(r, c);
if (sCellStyle.IsEmpty()) continue;
cellTextStyleId = pTableStyle->textStyle(sCellStyle);
if (!cellTextStyleId.isValid()) continue;
dLeft = pTableStyle->margin(AcDb::kCellMarginLeft, sCellStyle);
dRight = pTableStyle->margin(AcDb::kCellMarginRight, sCellStyle);
dTop = pTableStyle->margin(AcDb::kCellMarginTop, sCellStyle);
dBottom = pTableStyle->margin(AcDb::kCellMarginBottom, sCellStyle);
dHorzSpacing = pTableStyle->margin(AcDb::kCellMarginHorzSpacing, sCellStyle);
dVertSpacing = pTableStyle->margin(AcDb::kCellMarginVertSpacing, sCellStyle);
sContent = pTable->textString(r, c);
dTextHeight = pTable->textHeight(r, c);
dbText.setTextString(sContent);
dbText.setTextStyle(cellTextStyleId);
dbText.setHeight(dTextHeight);
ext.set(AcGePoint3d::kOrigin, AcGePoint3d::kOrigin);
dbText.getGeomExtents(ext);
dCellWidth = (ext.maxPoint().x - ext.minPoint().x) + (dLeft + dRight + dHorzSpacing);
dCellHeight = (ext.maxPoint().y - ext.minPoint().y) + (dTop + dBottom + dVertSpacing);
2026-10-04 00:04:20 +08:00
// 如果是合并单元格,则不调整列宽
2026-09-28 15:28:50 +08:00
if (!pTable->isMergeAllEnabled(r, -1))
{
if (dCellWidth > colWidths[c])
colWidths[c] = dCellWidth;
}
if (dCellHeight > rowHeights[r])
rowHeights[r] = dCellHeight;
}
}
const double minColWidth = 0.1;
const double minRowHeight = 0.1;
for (int c = 0; c < nCols; ++c)
{
double w = colWidths[c];
if (w < minColWidth) w = minColWidth;
pTable->setColumnWidth(c, w);
}
for (int r = 0; r < nRows; ++r)
{
double h = rowHeights[r];
if (h < minRowHeight) h = minRowHeight;
pTable->setRowHeight(r, h);
}
pTable->recomputeTableBlock(true);
}
void MKTABLE::getTableTemplateList(std::vector<CString>& outTemplates)
{
CString jsonPath(FilePath::GetSysDir() + JSON_TABLE_TEMPLATE_PATH);
if (_taccess(jsonPath, 0x0) != 0x0)
{
2026-10-04 00:04:20 +08:00
AfxMessageBox(_T("表格模板文件未找到!") + jsonPath, MB_OK | MB_ICONERROR);
2026-09-28 15:28:50 +08:00
return;
}
WDocument doc;
file2Json(jsonPath, doc);
if (doc.HasParseError())
{
2026-10-04 00:04:20 +08:00
AfxMessageBox(_T("表格模板文件json格式解析错误!") + jsonPath, MB_OK | MB_ICONERROR);
2026-09-28 15:28:50 +08:00
return;
}
CString path(_T("/table_list"));
WCValue *pTblList = WPointer(path).Get(doc);
if (!pTblList)
{
2026-10-04 00:04:20 +08:00
AfxMessageBox(_T("未找到表格列表!") + jsonPath, MB_OK | MB_ICONERROR);
2026-09-28 15:28:50 +08:00
return;
}
for (MCIt it = pTblList->MemberBegin(); it != pTblList->MemberEnd(); ++it)
{
outTemplates.push_back(it->name.GetString());
}
}
bool MKTABLE::makeTable(CListCtrl &listCtrl, LPCTSTR pszTitle, const int &maxRow)
{
if (maxRow <= 0) return false;
ads_point pt;
2026-10-04 00:04:20 +08:00
int nRes = acedGetPoint(NULL, _T("选择表格插入点:"), pt);
2026-09-28 15:28:50 +08:00
if (nRes != RTNORM)
return false;
if (!listCtrl.GetHeaderCtrl()) return false;
CString sTemplate(_T(""));
double dPScale(100.0);
std::vector<int> selCols;
MKTABLE::selectColumnsFromListCtrl(*listCtrl.GetHeaderCtrl()
, selCols
, dPScale
, sTemplate);
if (selCols.empty()) return false;
if (sTemplate.IsEmpty()) return false;
MKTABLE::RowData header;
std::vector<MKTABLE::TableData> datas;
MKTABLE::extractDatasFromListCtrl(listCtrl, datas, header, selCols, maxRow);
AcDbObjectId idTableStyle;
std::vector<TABLE::CellTableData> tabls;
TABLE::CellMerges merges;
GridLineType gridLineType;
parseTableTemplage(sTemplate
, datas
, pszTitle
, header
, tabls
, merges
, gridLineType
, idTableStyle
2026-10-04 00:04:20 +08:00
// 直接在生成的时候放大,不在idTableStyle里面放大
// 不然,使用同样tablestyle的表格如果出图比例不同,会互相影响
2026-09-28 15:28:50 +08:00
, 1.);
std::vector<AcDbTable*> dbTables;
makeTables(tabls, idTableStyle, merges,gridLineType, dbTables);
AcGeMatrix3d mat;
AcDbExtents ext;
AcGePoint3d ptPos(asPnt3d(pt));
for (size_t i(0); i < dbTables.size(); ++i)
{
AcDbTable *pTbl(dbTables[i]);
if (pTbl)
{
autoSizeTable(pTbl);
2026-10-04 00:04:20 +08:00
// 根据出图比例放大
2026-09-28 15:28:50 +08:00
mat.setToScaling(dPScale, ptPos);
pTbl->transformBy(mat);
pTbl->setPosition(ptPos);
CoreTools::AddToModelSpace(pTbl);
pTbl->getGeomExtents(ext);
2026-10-04 00:04:20 +08:00
ptPos.x += ext.maxPoint().x - ext.minPoint().x + 20. * CoreTools::getPScale(); //间隔100
2026-09-28 15:28:50 +08:00
}
}
return true;
}