Files
envi-code/SourceCode/Code2026/CoreCommand/makeCADTable.cpp
T
gjm 164968b62e chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
2026-10-04 00:04:20 +08:00

1056 lines
28 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "StdAfx.h"
#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
cell.text = _T(""); // 占位
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);
}
}
// 解析 json 中的 data,title,header,tail等定义字段
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);
}
}
// 解析 cellstyle_list
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;
}
}
}
// 解析 tablestyle_list
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())
{
acutPrintf(_T("\ntablestyle:%s,使用了未在cellstyle_list中定以的cellstyle:%s")
, ts.m_sName
, subIt->value.GetString());
continue;
}
// 修改为AcDbTableStyle内的名称
csIt->second.m_sName = subIt->name.GetString();
ts.m_cellStyles.insert(std::make_pair(subIt->name.GetString(), csIt->second));
}
tss[ts.m_sName] = ts;
}
}
// 解析 TableStyle 并且新建
AcDbObjectId parseTableStyle(WDocument &doc, LPCTSTR pszStyle, const double &dPScale)
{
AcDbObjectId id = MKTABLE::getTableStyle(_T("Standard"));
if (!pszStyle) return id;
TableStyles tss;
parseTableStyleList(doc, tss);
// 先检查是否在tablestyle_list中存在
std::map<CString, TableStyle>::const_iterator it(tss.find(pszStyle));
if (it == tss.end()) // 不存在,直接返回Standard
{
acutPrintf(_T("\n表格样式:%s未在tablestyle_list中出现。将使用Standard表格样式"), pszStyle);
return id;
}
TableStyle ts = it->second;
// 得到tablestyle的id
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);
// 如果cs不在tblStyle中,apply2CellStyle函数会自动新建
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
hdrs.push_back(_T("")); // 即使获取失败也要占位
}
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);
}
}
// 对齐 CellTableData 内的列数,补齐空单元格
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);
}
}
}
// 整体解析title,header,data,tail等内容,并且汇总在一个 TableCellData 结构中
void parseTableContent(WCValue &tbl, const CString &title
, const MKTABLE::RowData &header
// 保存了分表数据
, 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);
}
// 如果没有 title 字段,或者有title制度,但内容为空,则使用传入的 title 参数
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);
}
// data字段处了cellstyle被模板内定义外,其他的不应该定以,由界面传入的数据填充
WCValue *pData = WPointer(_T("/data")).Get(tbl);
if (pData)
{
parseDataContent(*pData, dataContent);
}
WCValue *pTail = WPointer(_T("/tail")).Get(tbl);
if (pTail)
{
parseDataContent(*pTail, tailContent);
}
// 这里要处理分表情况
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];
// 每一个 td 都是一个分表
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);
}
// 这里要处理一下tailContent的行号
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);
}
// 分表的数据填充好后,和titleContent,headerContent,tailContent合并为一个完整的表格
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());
// 对齐元素
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);
}
bool parseTableTemplage(LPCTSTR pszTemplate // 模板名称
// 传入的数据,可以是多张表的数据
, std::vector<MKTABLE::TableData> &datas
// 标题
, const CString &title
// 表头
, const MKTABLE::RowData &header
// 输出的表格数据,以TABLE::CellTableData形式保存
, std::vector<TABLE::CellTableData> &tabls
// 输出的合并单元格信息
, CellMerges &merges
// 输出的GridLineType信息
, GridLineType &gridLineType
// 表格样式ID
, AcDbObjectId &idTableStyle
// 出图比例
, const double &dPScale )
{
if (!pszTemplate) return false;
if (datas.empty())
{
AfxMessageBox(_T("数据为空!"), MB_OK | MB_ICONERROR);
return false;
}
CString jsonPath(FilePath::GetSysDir() + JSON_TABLE_TEMPLATE_PATH);
if (_taccess(jsonPath, 0x0) != 0x0)
{
AfxMessageBox(_T("表格模板文件未找到!") + jsonPath, MB_OK | MB_ICONERROR);
return false;
}
WDocument doc;
file2Json(jsonPath, doc);
if (doc.HasParseError())
{
AfxMessageBox(_T("表格模板文件json格式解析错误!") + jsonPath, MB_OK | MB_ICONERROR);
return false;
}
CString path(_T("/table_list/"));
path += (pszTemplate);
WCValue *pTbl = WPointer(path).Get(doc);
if (!pTbl)
{
AfxMessageBox(CString(_T("模板内的表格列表中未找到表格:")) + pszTemplate, MB_OK | MB_ICONERROR);
return NULL;
}
WCValue &tbl = *pTbl;
// 解析table style
idTableStyle = AcDbObjectId::kNull;
WCValue *pTs = WPointer(_T("/tablestyle")).Get(tbl);
if (!pTs)
{
acutPrintf(_T("表格模板%s缺少tablestyle定义! 表格将使用Standard表格样式。"), pszTemplate);
idTableStyle = MKTABLE::getTableStyle(_T("Standard"));
}
else
idTableStyle = parseTableStyle(doc, pTs->GetString(), dPScale);
// 解析合并单元格
WCValue *pMerge = WPointer(_T("/merge")).Get(tbl);
if (pMerge && pMerge->IsArray())
{
parseMerges(pMerge->GetArray(), merges);
}
// 解析GridLineType
parseGridLineType(tbl, gridLineType, dPScale);
// 解析表格内容
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);
}
// 处理合并单元格
TABLE::CellMergeRange mg;
for (size_t i(0); i < merges.size(); ++i)
{
mg = merges[i];
mg.apply2Table(pTable);
}
// 处理GridLineType
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)
{
return id; // 已存在
}
// Standard 是默认样式,目前CAD无法删除它
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);
// 如果是合并单元格,则不调整列宽
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)
{
AfxMessageBox(_T("表格模板文件未找到!") + jsonPath, MB_OK | MB_ICONERROR);
return;
}
WDocument doc;
file2Json(jsonPath, doc);
if (doc.HasParseError())
{
AfxMessageBox(_T("表格模板文件json格式解析错误!") + jsonPath, MB_OK | MB_ICONERROR);
return;
}
CString path(_T("/table_list"));
WCValue *pTblList = WPointer(path).Get(doc);
if (!pTblList)
{
AfxMessageBox(_T("未找到表格列表!") + jsonPath, MB_OK | MB_ICONERROR);
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;
int nRes = acedGetPoint(NULL, _T("选择表格插入点:"), pt);
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
// 直接在生成的时候放大,不在idTableStyle里面放大
// 不然,使用同样tablestyle的表格如果出图比例不同,会互相影响
, 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);
// 根据出图比例放大
mat.setToScaling(dPScale, ptPos);
pTbl->transformBy(mat);
pTbl->setPosition(ptPos);
CoreTools::AddToModelSpace(pTbl);
pTbl->getGeomExtents(ext);
ptPos.x += ext.maxPoint().x - ext.minPoint().x + 20. * CoreTools::getPScale(); //间隔100
}
}
return true;
}