#include "stdafx.h" #include "QuickModifyDlg.h" #include "coretools.h" #include "aecdbcurvebase.h" #include "aecdbEntityBase.h" #include "COMPARE_DOUBLE.h" #include "KTCadUtility.h" #define DIFF_VALUE _T("<多值>") using namespace SimpleProperty; namespace { void getEntityProperty(AcDbEntity *pEnt, PropertySetByIndex &properties) { AecDbCurveBase *pCurveBase = AecDbCurveBase::cast(pEnt); AecDbEntityBase *pEntBase = AecDbEntityBase::cast(pEnt); if (pCurveBase) { pCurveBase->GetProperties(properties); } else if (pEntBase) { pEntBase->GetProperties(properties); } return; } void getEntityProperty(const AcDbObjectId &id, PropertySetByIndex &properties) { AcDbEntityPointer ent(id, AcDb::kForRead); if (ent.openStatus() != Acad::eOk) return; getEntityProperty(ent, properties); } void setEntityProperty(AcDbEntity *pEnt, PropertySetByName &properties) { AecDbCurveBase *pCurveBase = AecDbCurveBase::cast(pEnt); AecDbEntityBase *pEntBase = AecDbEntityBase::cast(pEnt); if (pCurveBase) { pCurveBase->SetProperties(properties); } else if (pEntBase) { pEntBase->SetProperties(properties); } return; } CString getPropertyValueString(const Property &prop) { CString sVal; switch (prop.m_type) { case eInt: sVal.Format(_T("%d"), prop.m_iValueInt); break; case eDouble: // 如果需要统一调整精度(如改为 3 位小数),只需修改此处 sVal.Format(_T("%.2f"), prop.m_dValueDouble); break; case eString: sVal = prop.m_sValueString; break; default: break; } return sVal; } CString getUIContent(const PropertySetByIndex &props, LPCTSTR pszProp) { const Property *prop(NULL); props.find(pszProp, prop); if (prop) { return getPropertyValueString(*prop); } return _T(""); } // prosets 是所有实体的属性列表,pszProp要保证一定会在每个属性表里面现 CString getUIContent(const std::vector &proSets, LPCTSTR pszProp) { if (!pszProp) return _T(""); if (proSets.empty()) return _T(""); CString str(getUIContent(proSets[0], pszProp)); for (size_t i(1); i < proSets.size(); ++i) { const PropertySetByIndex &props(proSets[i]); if (str != getUIContent(props, pszProp)) { str = DIFF_VALUE; return str; } } return str; } // 求出所有实体属性表的交集 void getIntersection(const std::vector &proSets, PropertySetByIndex &output) { typedef std::set PropIntersectionSet; typedef PropertySetByIndex::SetType::const_iterator PorpIndexSetIter; output.m_set.clear(); if (proSets.empty()) return; PropIntersectionSet candidates; const PropertySetByIndex &firstSet = proSets[0]; //for (PorpIndexSetIter it = firstSet.m_set.begin() // ; it != firstSet.m_set.end() // ; ++it) //{ // candidates.insert(*it); //} candidates.insert(proSets[0].m_set.begin(), proSets[0].m_set.end()); PropIntersectionSet currentCompSet, resultSet; for (size_t i = 1; i < proSets.size(); ++i) { if (candidates.empty()) break; currentCompSet.clear(); resultSet.clear(); //const PropertySetByIndex ¤tInputSet = proSets[i]; //for (PorpIndexSetIter it = currentInputSet.m_set.begin() // ; it != currentInputSet.m_set.end() // ; ++it) //{ // currentCompSet.insert(*it); //} currentCompSet.insert(proSets[i].m_set.begin(), proSets[i].m_set.end()); std::set_intersection(candidates.begin(), candidates.end(), currentCompSet.begin(), currentCompSet.end(), std::inserter(resultSet, resultSet.begin()), compare_properties()); candidates = resultSet; } Property prop; i = (0); for (PropIntersectionSet::const_iterator it = candidates.begin() ; it != candidates.end() ; ++it, ++i) { prop = *it; prop.m_iIndex = i; // 在这里把 output 里面property内的m_sUIContent设置一下 // 到了外面就没有机会了 prop.m_sUIContent = getUIContent(proSets, prop.m_sPropertyName); output.m_set.insert(prop); } } bool verifyIntger(LPCTSTR pszStr, int *pInt = NULL) { if (pszStr == NULL || *pszStr == _T('\0')) return false; // 空字符串无效 TCHAR *pEnd = NULL; long lVal = _tcstol(pszStr, &pEnd, 10); if (*pEnd == _T('\0')) { if (pInt) *pInt = (int)lVal; return true; // 成功识别为整数 } return false; } bool verifyDouble(LPCTSTR pszStr, double *pDouble = NULL) { if (pszStr == NULL || *pszStr == _T('\0')) return false; // 空字符串无效 TCHAR *pEnd = NULL; double dVal = _tcstod(pszStr, &pEnd); if (*pEnd == _T('\0')) { if (pDouble) *pDouble = dVal; return true; // 成功识别为浮点数 } return false; } // 判断用户的输入是否符合 PropertyType bool verifyUserInput(const PropertyType &tp, LPCTSTR pszStr) { if (pszStr == NULL || *pszStr == _T('\0')) return false; // 空字符串无效 if (tp == eInt && verifyIntger(pszStr)) return true; // 如果是浮点数类型,那么整型也可以 if (tp == eDouble && (verifyIntger(pszStr) || verifyDouble(pszStr))) return true; return false; } bool isSameValue(Property &prop, LPCTSTR psz) { if (!psz) return false; bool bDiffValue(false); if (prop.m_sUIContent == DIFF_VALUE) bDiffValue = true; if (prop.m_type == eString) return prop.m_sUIContent == psz; double dV; int iV; bool bDouble(verifyDouble(psz, &dV)); bool bInt(verifyIntger(psz, &iV)); if (prop.m_type == eInt && bInt) { // 目前是"多值"情况,输入什么都算是有效修改,只要格式正确 if (bDiffValue) return false; return iV == prop.m_iValueInt; } if (prop.m_type == eDouble) { // 目前是"多值"情况,输入什么都算是有效修改,只要格式正确 if (bDiffValue) return false; if (bDouble) return COMPARE_DOUBLE::equal(dV, prop.m_dValueDouble, .01); if (bInt) return COMPARE_DOUBLE::equal(iV * 1., prop.m_dValueDouble, .01); } return false; } } extern UINT WM_XLISTCTRL_COMBO_SELECTION; extern UINT WM_XLISTCTRL_EDIT_END; extern UINT WM_XLISTCTRL_CHECKBOX_CLICKED; IMPLEMENT_DYNAMIC(CQuickModifyDlg, CDialog) BEGIN_MESSAGE_MAP(CQuickModifyDlg, CDialog) ON_MESSAGE( WM_ACAD_KEEPFOCUS, &CQuickModifyDlg::onAcadKeepFocus) ON_BN_CLICKED(IDOK, &CQuickModifyDlg::OnBnClickedOk) ON_WM_SIZE() ON_WM_GETMINMAXINFO() ON_REGISTERED_MESSAGE(WM_XLISTCTRL_COMBO_SELECTION, &CQuickModifyDlg::OnComboSelection) ON_REGISTERED_MESSAGE(WM_XLISTCTRL_EDIT_END, &CQuickModifyDlg::OnEditItemEnd) END_MESSAGE_MAP() CQuickModifyDlg::CQuickModifyDlg(const AcDbObjectIdArray &ids, CWnd *pParent /*=nullptr*/) : CDialog(CQuickModifyDlg::IDD, pParent) , m_arIds(ids) { } CQuickModifyDlg::~CQuickModifyDlg() { } void CQuickModifyDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_OBJECTS, m_wndList); } BOOL CQuickModifyDlg::OnInitDialog() { CDialog::OnInitDialog(); if (!m_arIds.isEmpty()) { CString strTitle; strTitle.Format(_T("共选择了%d个<%s>实体"), m_arIds.length(), m_arIds.first().objectClass()->dxfName()); SetWindowText(strTitle); } m_wndList.SetFont(GetFont()); m_wndList.SetExtendedStyle( m_wndList.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_SINGLEROW); initColumns(); CRect rc; GetWindowRect(rc); m_szMinDlgSize = rc.Size(); layoutControls(0, 0); refreshList(); UpdateData(FALSE); return TRUE; } void CQuickModifyDlg::initColumns() { // 第一列,选择列 LV_COLUMN lvcolumn; ::memset(&lvcolumn, 0, sizeof(lvcolumn)); lvcolumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvcolumn.fmt = LVCFMT_CENTER; lvcolumn.pszText = const_cast(_T("属性")); lvcolumn.iSubItem = 0; lvcolumn.cx = 0; m_wndList.InsertColumn(0, &lvcolumn); lvcolumn.pszText = const_cast(_T("值")); lvcolumn.iSubItem = 1; m_wndList.InsertColumn(1, &lvcolumn); } void CQuickModifyDlg::resetWidthOfColumnHeader(const int &width) { int w = int(width * .5); m_wndList.CListCtrl::SetColumnWidth(0, w); m_wndList.CListCtrl::SetColumnWidth(1, w); } void CQuickModifyDlg::refreshList() { m_wndList.DeleteAllItems(); m_properties.m_set.clear(); std::vector proSets; PropertySetByIndex _properties; for (int i(0); i < m_arIds.length(); ++i) { _properties.m_set.clear(); getEntityProperty(m_arIds[i], _properties); if (_properties.m_set.empty()) continue; proSets.push_back(_properties); } getIntersection(proSets, m_properties); // 将 properties 显示到列表控件中 int idx(0), nHeight(1), nCurSel(0); PropertySetByIndex::SetType::const_iterator it(m_properties.m_set.begin()); for (; it != m_properties.m_set.end(); ++it) { if (!it->m_bCanModify) continue; if (it->m_iColor == -1) idx = m_wndList.InsertItem(++idx, it->m_sPropertyName); else idx = m_wndList.InsertItem(++idx, it->m_sPropertyName, 0, acedGetRGB(it->m_iColor)); if (!it->m_arOptions.empty()) { nCurSel = 0; CStringArray *pArr = new CStringArray; for (size_t i = 0; i < it->m_arOptions.size(); ++i) { const CString &s(it->m_arOptions[i]); if (s == it->m_sUIContent) nCurSel = i; pArr->Add(s); } // 如果数量量大于10,则取10 nHeight = pArr->GetCount() > 10 ? 10 : pArr->GetCount(); m_wndList.SetComboBox(idx, 1, TRUE, pArr, nHeight, nCurSel, 0); } else { m_wndList.SetEdit(idx, 1); } m_wndList.SetItemText(idx, 1, it->m_sUIContent); m_wndList.SetItemData(idx, (DWORD_PTR)&(*it)); if (idx % 2 && it->m_iColor == -1) { m_wndList.SetItemColors(idx, 0, RGB(0,0,0), RGB(255, 255, 225)); m_wndList.SetItemColors(idx, 1, RGB(0,0,0), RGB(255, 255, 225)); m_wndList.SetItemColors(idx, 2, RGB(0,0,0), RGB(255, 255, 225)); } } return; } void CQuickModifyDlg::OnGetMinMaxInfo(MINMAXINFO *lpMMI) { CDialog::OnGetMinMaxInfo(lpMMI); // 只有当 m_minSize 有效(即 OnInitDialog 运行过)时才限制 // 防止窗口创建初期 m_minSize 为 0 导致窗口无法显示 if (m_szMinDlgSize.cx > 0 && m_szMinDlgSize.cy > 0) { // ptMinTrackSize 代表窗口允许的最小“追踪”尺寸 (拖拽时的尺寸) lpMMI->ptMinTrackSize.x = m_szMinDlgSize.cx; // 限制最小宽度 lpMMI->ptMinTrackSize.y = m_szMinDlgSize.cy; // 限制最小高度 } } LRESULT CQuickModifyDlg::OnComboSelection(WPARAM nItem, LPARAM nSubItem) { Property* pItemData = (Property*)m_wndList.GetItemData((int)nItem); if (pItemData) { CString sValue = m_wndList.GetItemText((int)nItem, (int)nSubItem); if (pItemData->m_sUIContent != sValue) { pItemData->m_sUIContent = m_wndList.GetItemText((int)nItem, (int)nSubItem); pItemData->m_bIsChange = true; } } return 0; } LRESULT CQuickModifyDlg::OnEditItemEnd(WPARAM nItem, LPARAM nSubItem) { Property* pItemData = (Property*)m_wndList.GetItemData((int)nItem); if (pItemData) { CString sValue = m_wndList.GetItemText((int)nItem, (int)nSubItem); if (pItemData->m_type != eString) { if (!verifyUserInput(pItemData->m_type, sValue)) { AfxMessageBox(_T("无效的输入,请输入数字!")); m_wndList.SetItemText(nItem, nSubItem, pItemData->m_sUIContent); return 0; } } // 判断两个字符串是否相同,从而决定是否标记为修改 if (!isSameValue(*pItemData, sValue)) { pItemData->m_bIsChange = true; pItemData->m_sUIContent = sValue; } else { m_wndList.SetItemText(nItem, nSubItem, pItemData->m_sUIContent); } } return 0; } void CQuickModifyDlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); layoutControls(cx, cy); } LONG_PTR CQuickModifyDlg::onAcadKeepFocus(UINT_PTR, LONG_PTR) { POINT pt; ::GetCursorPos(&pt); CRect rect; GetWindowRect(&rect); if(!(rect.PtInRect(pt))) { return FALSE; } return TRUE; } void CQuickModifyDlg::OnBnClickedOk() { OnOK(); if (!UpdateData(TRUE)) return; } void CQuickModifyDlg::layoutControls(const int &cx, const int &cy) { if (!m_wndList.GetSafeHwnd()) return; double dDpiScale = CoreTools::GetDPIScale(); int leftMargin(20), bottomMargin(20), rightMargin(20); leftMargin = int((leftMargin * 1. * dDpiScale) + .5); rightMargin = int((rightMargin * 1. * dDpiScale) + .5); bottomMargin = int((bottomMargin * 1. * dDpiScale) + .5); CRect rcDlg; GetWindowRect(rcDlg); ScreenToClient(rcDlg); // 先排列下面三个控件 CWnd *pBtnOK = GetDlgItem(IDOK); if (!pBtnOK) return; // 1. 获取各个按钮当前的尺寸 (宽和高) // 我们只关心尺寸,不关心它当前的位置,所以获取后计算 Width/Height CRect rcOK; pBtnOK->GetWindowRect(&rcOK); CSize szOK = rcOK.Size(); int okLeft = int((rcDlg.Width() - szOK.cx) * .5); int okTop = rcDlg.bottom - bottomMargin - szOK.cy; CRect rcOKTarget(okLeft, okTop, okLeft + szOK.cx, okTop + szOK.cy); pBtnOK->MoveWindow(&rcOKTarget); CRect rcList; rcList.top = 0; rcList.left = rcDlg.left + leftMargin; rcList.right = rcDlg.right - rightMargin; rcList.bottom = rcOKTarget.top - bottomMargin; m_wndList.MoveWindow(rcList); resetWidthOfColumnHeader(rcList.Width()); Invalidate(); } void CQuickModifyDlg::getMoidfiedProperties(PropertySetByName & properties) const { properties.m_set.clear(); PropertySetByIndex::SetType::const_iterator it = m_properties.m_set.begin(); for (; it != m_properties.m_set.end(); ++it) { if (!it->m_bIsChange) continue; properties.m_set.insert(*it); } } void CQuickModifyDlg::setPropertiesOfEntities() const { PropertySetByName properties; getMoidfiedProperties(properties); for (int i(0); i < m_arIds.length(); ++i) { AcDbEntityPointer ent(m_arIds[i], AcDb::kForWrite); if (ent.openStatus() != Acad::eOk) continue; setEntityProperty(ent, properties); } } void CQuickModifyDlg::start(const AcDbObjectIdArray &ids) { CAcModuleResourceOverride myResources; CQuickModifyDlg dlg(ids); if (dlg.DoModal() == IDOK) dlg.setPropertiesOfEntities(); } void CQuickModifyDlg::command() { ads_name ss, ent; struct resbuf* pRb = acutBuildList(RTDXF0, _T("AEC*"), 0); int nRes = CKTCadUtility::SelectEntities(_T("\n选择上华实体:"), ss, pRb); acutRelRb(pRb); if (nRes != RTNORM) return; Adesk::Int32 nLen = 0; acedSSLength(ss, &nLen); AcDbObjectId id; AcDbObjectIdArray arIds; for (int i = 0; i < nLen; ++i) { acedSSName(ss, i, ent); acdbGetObjectId(id, ent); if (id.isValid()) arIds.append(id); } acedSSFree(ss); start(arIds); }