#include "StdAfx.h" #include #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(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 &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 &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::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 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 &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 &datas , std::vector &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(it->value.GetInt())); bUse = true; } it = vLtp.FindMember(_T("LineWeight")); if (it != vLtp.MemberEnd() && it->value.IsInt()) { prop.setLineWeight(static_cast(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(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 &datas // 标题 , const CString &title // 表头 , const MKTABLE::RowData &header // 输出的表格数据,以TABLE::CellTableData形式保存 , std::vector &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 &tbls , AcDbObjectId idTableStyle , const TABLE::CellMerges &merges , const TABLE::GridLineType &gridLineType , std::vector &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 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 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 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 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 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 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 &outDatas , RowData &outHeaderData , const std::vector &idxs , const int &maxRow) { int count(listCtrl.GetItemCount()); if (!count) return false; std::vector 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 &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 pTableStyle(idStyle, AcDb::kForRead); if (pTableStyle.openStatus() != Acad::eOk) return; std::vector colWidths(nCols, .0); std::vector 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& 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 selCols; MKTABLE::selectColumnsFromListCtrl(*listCtrl.GetHeaderCtrl() , selCols , dPScale , sTemplate); if (selCols.empty()) return false; if (sTemplate.IsEmpty()) return false; MKTABLE::RowData header; std::vector datas; MKTABLE::extractDatasFromListCtrl(listCtrl, datas, header, selCols, maxRow); AcDbObjectId idTableStyle; std::vector tabls; TABLE::CellMerges merges; GridLineType gridLineType; parseTableTemplage(sTemplate , datas , pszTitle , header , tabls , merges , gridLineType , idTableStyle // 直接在生成的时候放大,不在idTableStyle里面放大 // 不然,使用同样tablestyle的表格如果出图比例不同,会互相影响 , 1.); std::vector 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; }