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

599 lines
14 KiB
C++

#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<PropertySetByIndex> &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<PropertySetByIndex> &proSets, PropertySetByIndex &output)
{
typedef std::set<Property, compare_properties> 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 &currentInputSet = 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<LPTSTR>(_T("属性"));
lvcolumn.iSubItem = 0;
lvcolumn.cx = 0;
m_wndList.InsertColumn(0, &lvcolumn);
lvcolumn.pszText = const_cast<LPTSTR>(_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<PropertySetByIndex> 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);
}