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;
|
|
|
|
|
|
}
|