XTPMarkupObject.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:32k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // XTPMarkupObject.cpp: implementation of the CXTPMarkupObject class.
  2. //
  3. // This file is a part of the XTREME TOOLKIT PRO MFC class library.
  4. // (c)1998-2008 Codejock Software, All Rights Reserved.
  5. //
  6. // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
  7. // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
  8. // CONSENT OF CODEJOCK SOFTWARE.
  9. //
  10. // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
  11. // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
  12. // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
  13. // SINGLE COMPUTER.
  14. //
  15. // CONTACT INFORMATION:
  16. // support@codejock.com
  17. // http://www.codejock.com
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "Common/XTPVc80Helpers.h"
  22. #include "XTPMarkupObject.h"
  23. #include "XTPMarkupBuilder.h"
  24. #include "XTPMarkupContext.h"
  25. #ifdef _DEBUG
  26. #undef THIS_FILE
  27. static char THIS_FILE[]=__FILE__;
  28. #define new DEBUG_NEW
  29. #endif
  30. CXTPMarkupPropertyChangedEventArgs::CXTPMarkupPropertyChangedEventArgs(CXTPMarkupDependencyProperty* pProperty, CXTPMarkupObject* pOldValue, CXTPMarkupObject* pNewValue)
  31. {
  32. m_pProperty = pProperty;
  33. m_pOldValue = pOldValue;
  34. m_pNewValue = pNewValue;
  35. }
  36. struct CXTPMarkupFromNameKey
  37. {
  38. public:
  39. CXTPMarkupFromNameKey(LPCWSTR lpszName = 0, CXTPMarkupType* pOwnerType = 0)
  40. {
  41. m_lpszName = lpszName;
  42. m_pOwnerType = pOwnerType;
  43. }
  44. BOOL operator==(const CXTPMarkupFromNameKey& key) const
  45. {
  46. return m_pOwnerType == key.m_pOwnerType && wcscmp(m_lpszName, key.m_lpszName) == 0;
  47. }
  48. LPCWSTR m_lpszName;
  49. CXTPMarkupType* m_pOwnerType;
  50. };
  51. class CXTPMarkupPropertyFromNameMap : public CMap<CXTPMarkupFromNameKey, CXTPMarkupFromNameKey&, CXTPMarkupDependencyProperty*, CXTPMarkupDependencyProperty*>
  52. {
  53. public:
  54. CXTPMarkupPropertyFromNameMap();
  55. ~CXTPMarkupPropertyFromNameMap();
  56. };
  57. CXTPMarkupPropertyFromNameMap::CXTPMarkupPropertyFromNameMap()
  58. {
  59. }
  60. CXTPMarkupPropertyFromNameMap::~CXTPMarkupPropertyFromNameMap()
  61. {
  62. POSITION pos = GetStartPosition();
  63. while (pos)
  64. {
  65. CXTPMarkupFromNameKey key;
  66. CXTPMarkupDependencyProperty* dp;
  67. GetNextAssoc(pos, key, dp);
  68. dp->Release();
  69. }
  70. RemoveAll();
  71. }
  72. template<>
  73. AFX_INLINE UINT AFXAPI HashKey<CXTPMarkupFromNameKey&>(CXTPMarkupFromNameKey& key)
  74. {
  75. // default identity hash - works for most primitive values
  76. return HashKey<LPCWSTR>(key.m_lpszName) & ((UINT)(DWORD)(DWORD_PTR)key.m_pOwnerType) >> 16;
  77. }
  78. CXTPMarkupPropertyFromNameMap* CXTPMarkupDependencyProperty::GetPropertyMap()
  79. {
  80. static CXTPMarkupPropertyFromNameMap m_PropertyFromName;
  81. return &m_PropertyFromName;
  82. }
  83. //////////////////////////////////////////////////////////////////////////
  84. // CXTPMarkupPropertyMetadata
  85. CXTPMarkupPropertyMetadata::CXTPMarkupPropertyMetadata(CXTPMarkupObject* pDefaultValue, DWORD dwFlags)
  86. {
  87. m_pDefaultValue = pDefaultValue;
  88. m_pConverter = NULL;
  89. m_dwFlags = dwFlags;
  90. m_pPropertyChanged = NULL;
  91. }
  92. CXTPMarkupPropertyMetadata::CXTPMarkupPropertyMetadata(CXTPMarkupObject* pDefaultValue, PFNCONVERTFROM pConverter, DWORD dwFlags)
  93. {
  94. m_pDefaultValue = pDefaultValue;
  95. m_pConverter = pConverter;
  96. m_dwFlags = dwFlags;
  97. m_pPropertyChanged = NULL;
  98. }
  99. CXTPMarkupPropertyMetadata::CXTPMarkupPropertyMetadata(CXTPMarkupObject* pDefaultValue, PFNPROPERTYCHANGED pPropertyChanged, DWORD dwFlags)
  100. {
  101. m_pDefaultValue = pDefaultValue;
  102. m_pConverter = NULL;
  103. m_dwFlags = dwFlags;
  104. m_pPropertyChanged = pPropertyChanged;
  105. }
  106. CXTPMarkupPropertyMetadata::CXTPMarkupPropertyMetadata(CXTPMarkupObject* pDefaultValue, PFNCONVERTFROM pConverter, PFNPROPERTYCHANGED pPropertyChanged, DWORD dwFlags)
  107. {
  108. m_pDefaultValue = pDefaultValue;
  109. m_pConverter = pConverter;
  110. m_dwFlags = dwFlags;
  111. m_pPropertyChanged = pPropertyChanged;
  112. }
  113. CXTPMarkupPropertyMetadata::~CXTPMarkupPropertyMetadata()
  114. {
  115. if (m_pDefaultValue)
  116. {
  117. MARKUP_RELEASE(m_pDefaultValue);
  118. }
  119. }
  120. //////////////////////////////////////////////////////////////////////////
  121. // CXTPMarkupDependencyProperty
  122. int CXTPMarkupDependencyProperty::s_nCount = 0;
  123. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupDependencyProperty, CXTPMarkupObject);
  124. void CXTPMarkupDependencyProperty::RegisterMarkupClass()
  125. {
  126. }
  127. CXTPMarkupDependencyProperty::CXTPMarkupDependencyProperty()
  128. {
  129. m_lpszName = 0;
  130. m_pPropetyType = 0;
  131. m_pOwnerType = 0;
  132. m_bAttached = FALSE;
  133. m_pMetadata = NULL;
  134. m_nIndex = -1;
  135. }
  136. CXTPMarkupDependencyProperty::~CXTPMarkupDependencyProperty()
  137. {
  138. if (m_pMetadata)
  139. {
  140. delete m_pMetadata;
  141. }
  142. }
  143. CXTPMarkupDependencyProperty* CXTPMarkupDependencyProperty::RegisterCommon(CXTPMarkupDependencyProperty* dp, LPCWSTR lpszName, CXTPMarkupType* pPropetyType, CXTPMarkupType* pOwnerType, BOOL bAttached)
  144. {
  145. CXTPMarkupFromNameKey key(lpszName, pOwnerType);
  146. dp->m_lpszName = lpszName;
  147. dp->m_pPropetyType = pPropetyType;
  148. dp->m_pOwnerType = pOwnerType;
  149. dp->m_bAttached = bAttached;
  150. CXTPMarkupPropertyFromNameMap* pPropertyFromNameMap = GetPropertyMap();
  151. if (!dp->IsEvent())
  152. {
  153. dp->m_nIndex = s_nCount++;
  154. }
  155. pPropertyFromNameMap->SetAt(key, dp);
  156. return dp;
  157. }
  158. CXTPMarkupDependencyProperty* CXTPMarkupDependencyProperty::RegisterAttached(LPCWSTR lpszName, CXTPMarkupType* pPropetyType, CXTPMarkupType* pOwnerType, CXTPMarkupPropertyMetadata* pMetadata)
  159. {
  160. CXTPMarkupDependencyProperty* dp =  RegisterCommon(new CXTPMarkupDependencyProperty(), lpszName, pPropetyType, pOwnerType, TRUE);
  161. dp->m_pMetadata = pMetadata;
  162. return dp;
  163. }
  164. CXTPMarkupDependencyProperty* CXTPMarkupDependencyProperty::Register(LPCWSTR lpszName, CXTPMarkupType* pPropetyType, CXTPMarkupType* pOwnerType, CXTPMarkupPropertyMetadata* pMetadata)
  165. {
  166. CXTPMarkupDependencyProperty* dp = RegisterCommon(new CXTPMarkupDependencyProperty(), lpszName, pPropetyType, pOwnerType, FALSE);
  167. dp->m_pMetadata = pMetadata;
  168. return dp;
  169. }
  170. CXTPMarkupDependencyProperty* CXTPMarkupDependencyProperty::AddOwner(CXTPMarkupType* pOwnerType)
  171. {
  172. CXTPMarkupFromNameKey key(m_lpszName, pOwnerType);
  173. CXTPMarkupPropertyFromNameMap* pPropertyFromNameMap = GetPropertyMap();
  174. pPropertyFromNameMap->SetAt(key, this);
  175. AddRef();
  176. return this;
  177. }
  178. CXTPMarkupDependencyProperty* CXTPMarkupDependencyProperty::FindProperty(CXTPMarkupType* pRuntimeClass, LPCWSTR lpszAttribute)
  179. {
  180. CXTPMarkupPropertyFromNameMap* pMap = CXTPMarkupDependencyProperty::GetPropertyMap();
  181. while (pRuntimeClass != NULL)
  182. {
  183. CXTPMarkupFromNameKey nameKey(lpszAttribute, pRuntimeClass);
  184. CXTPMarkupDependencyProperty* pProperty = NULL;
  185. if (pMap->Lookup(nameKey, pProperty))
  186. return pProperty;
  187. pRuntimeClass = pRuntimeClass->GetBaseType();
  188. }
  189. return NULL;
  190. }
  191. //////////////////////////////////////////////////////////////////////////
  192. // CXTPMarkupType
  193. class CXTPMarkupType::CClassList
  194. {
  195. public:
  196. CClassList();
  197. ~CClassList();
  198. public:
  199. void Add(LPCWSTR lpszTag, CXTPMarkupType* pClass);
  200. CXTPMarkupType* Lookup(LPCWSTR lpszTag);
  201. public:
  202. CMap<LPCWSTR, LPCWSTR, CXTPMarkupType*, CXTPMarkupType*> m_mapTypes;
  203. CTypedSimpleList<CXTPMarkupType*> m_classList;
  204. };
  205. template<> inline BOOL AFXAPI CompareElements(const LPCWSTR* pElement1, const LPCWSTR* pElement2)
  206. {
  207. return wcscmp(*pElement1, *pElement2) == 0;
  208. }
  209. CXTPMarkupType::CClassList::CClassList()
  210. {
  211. m_classList.Construct(offsetof(CXTPMarkupType, m_pNextType));
  212. }
  213. CXTPMarkupType::CClassList::~CClassList()
  214. {
  215. CXTPMarkupType* pType = m_classList.GetHead();
  216. while (pType)
  217. {
  218. CXTPMarkupType* pTypeDelete = pType;
  219. pType = pType->m_pNextType;
  220. MARKUP_RELEASE(pTypeDelete);
  221. }
  222. }
  223. void CXTPMarkupType::CClassList::Add(LPCWSTR lpszTag, CXTPMarkupType* pClass)
  224. {
  225. if (lpszTag && lpszTag[0] != '')
  226. {
  227. ASSERT(Lookup(lpszTag) == NULL);
  228. m_mapTypes.SetAt(lpszTag, pClass);
  229. }
  230. m_classList.AddHead(pClass);
  231. }
  232. CXTPMarkupType* CXTPMarkupType::CClassList::Lookup(LPCWSTR lpszTag)
  233. {
  234. CXTPMarkupType* pType = NULL;
  235. if (m_mapTypes.Lookup(lpszTag, pType))
  236. {
  237. return pType;
  238. }
  239. return NULL;
  240. }
  241. CXTPMarkupType::CClassList* CXTPMarkupType::GetClassList()
  242. {
  243. static CClassList list;
  244. return &list;
  245. }
  246. CXTPMarkupType* CXTPMarkupType::LookupTag(LPCWSTR lpszTag)
  247. {
  248. return GetClassList()->Lookup(lpszTag);
  249. }
  250. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupType, CXTPMarkupObject)
  251. void CXTPMarkupType::RegisterMarkupClass()
  252. {
  253. }
  254. CXTPMarkupType::CXTPMarkupType()
  255. {
  256. m_lpszTag = NULL;
  257. m_lpszClassName = NULL;
  258. m_pfnCreateObject = NULL;
  259. m_pfnGetBaseType = NULL;
  260. m_pfnRegisterMarkupClass = NULL;
  261. m_pNextType = NULL;
  262. m_bRegister = FALSE;
  263. m_pTypeStyle = NULL;
  264. }
  265. CXTPMarkupType::CXTPMarkupType(LPCWSTR lpszTag, LPCWSTR lpszClassName, PFNCREATEOBJECT pfnCreateObject, PFNGETBASETYPE pfnGetBaseType, PFNREGISTERMARKUPCLASS pfnRegisterMarkupClass)
  266. {
  267. m_lpszTag = lpszTag;
  268. m_lpszClassName = lpszClassName;
  269. m_pfnCreateObject = pfnCreateObject;
  270. m_pfnGetBaseType = pfnGetBaseType;
  271. m_pfnRegisterMarkupClass = pfnRegisterMarkupClass;
  272. m_pNextType = NULL;
  273. m_bRegister = FALSE;
  274. m_pTypeStyle = NULL;
  275. GetClassList()->Add(lpszTag, this);
  276. }
  277. CXTPMarkupObject* CXTPMarkupType::ConvertFrom(CXTPMarkupObject* pObject) const
  278. {
  279. if (IsStringObject(pObject))
  280. {
  281. LPCWSTR lpszValue = *((CXTPMarkupString*)pObject);
  282. CXTPMarkupType* pType = GetClassList()->Lookup(lpszValue);
  283. if (pType)
  284. {
  285. pType->AddRef();
  286. return pType;
  287. }
  288. }
  289. return NULL;
  290. }
  291. CXTPMarkupType::~CXTPMarkupType()
  292. {
  293. if (m_pTypeStyle)
  294. {
  295. ((CXTPMarkupObject*)m_pTypeStyle)->Release();
  296. }
  297. }
  298. CXTPMarkupObject* CXTPMarkupType::CreateObject() const
  299. {
  300. return (*m_pfnCreateObject)();
  301. }
  302. CXTPMarkupType* CXTPMarkupType::GetBaseType() const
  303. {
  304. return (*m_pfnGetBaseType)();
  305. }
  306. void CXTPMarkupType::Register()
  307. {
  308. if (m_bRegister)
  309. return;
  310. CXTPMarkupType* pType = GetBaseType();
  311. if (pType && !pType->m_bRegister)
  312. pType->Register();
  313. m_bRegister = TRUE;
  314. (*m_pfnRegisterMarkupClass)();
  315. }
  316. void AFX_CDECL CXTPMarkupType::RegisterAll()
  317. {
  318. CXTPMarkupType* pType = GetClassList()->m_classList.GetHead();
  319. while (pType)
  320. {
  321. pType->Register();
  322. pType = pType->m_pNextType;
  323. }
  324. }
  325. BOOL CXTPMarkupType::IsDerivedFrom(const CXTPMarkupType* pBaseClass) const
  326. {
  327. const CXTPMarkupType* pClassThis = this;
  328. while (pClassThis != NULL)
  329. {
  330. if (pClassThis == pBaseClass)
  331. return TRUE;
  332. pClassThis = pClassThis->GetBaseType();
  333. }
  334. return FALSE;
  335. }
  336. CXTPMarkupObject* CXTPMarkupType::DynamicDownCast(CXTPMarkupType* pType, CXTPMarkupObject* pObject)
  337. {
  338. if (pObject != NULL && pObject->IsKindOf(pType))
  339. return pObject;
  340. else
  341. return NULL;
  342. }
  343. CXTPMarkupObject* CXTPMarkupType::StaticDownCast(CXTPMarkupType* pType, CXTPMarkupObject* pObject)
  344. {
  345. pType;
  346. ASSERT(pObject == NULL || pObject->IsKindOf(pType));
  347. return pObject;
  348. }
  349. //////////////////////////////////////////////////////////////////////////
  350. // CXTPMarkupProperties
  351. CXTPMarkupProperties::CXTPMarkupProperties(CXTPMarkupObject* pOwner)
  352. {
  353. m_pOwner = pOwner;
  354. m_nTableSize = CXTPMarkupDependencyProperty::s_nCount;
  355. m_pTable = new CXTPMarkupObject*[m_nTableSize];
  356. ZeroMemory(m_pTable, m_nTableSize * sizeof(CXTPMarkupObject*));
  357. }
  358. CXTPMarkupProperties::~CXTPMarkupProperties()
  359. {
  360. for (int i = 0; i < m_nTableSize; i++)
  361. {
  362. if (m_pTable[i]) m_pTable[i]->Release();
  363. }
  364. delete[] m_pTable;
  365. }
  366. BOOL CXTPMarkupProperties::IsPropertyValid(CXTPMarkupDependencyProperty* pProperty) const
  367. {
  368. if (pProperty->m_nIndex == -1)
  369. {
  370. ASSERT(FALSE);
  371. return FALSE;
  372. }
  373. if (pProperty->m_nIndex >= m_nTableSize)
  374. {
  375. ASSERT(FALSE);
  376. return FALSE;
  377. }
  378. return TRUE;
  379. }
  380. CXTPMarkupObject* CXTPMarkupProperties::Lookup(CXTPMarkupDependencyProperty* pProperty) const
  381. {
  382. if (!IsPropertyValid(pProperty))
  383. return NULL;
  384. return m_pTable[pProperty->m_nIndex];
  385. }
  386. void CXTPMarkupProperties::Copy(CXTPMarkupProperties* pOwner)
  387. {
  388. ASSERT(pOwner->m_nTableSize == m_nTableSize);
  389. for (int i = 0; i < pOwner->m_nTableSize; i++)
  390. {
  391. if (pOwner->m_pTable[i])
  392. {
  393. m_pTable[i] = pOwner->m_pTable[i];
  394. m_pTable[i]->AddRef();
  395. }
  396. }
  397. }
  398. void CXTPMarkupProperties::Set(CXTPMarkupDependencyProperty* pProperty, CXTPMarkupObject* pValue)
  399. {
  400. if (!IsPropertyValid(pProperty))
  401. return;
  402. int nIndex = pProperty->m_nIndex;
  403. if (m_pTable[nIndex])
  404. {
  405. if (m_pOwner) m_pTable[nIndex]->SetLogicalParent(NULL);
  406. MARKUP_RELEASE(m_pTable[nIndex]);
  407. m_pTable[nIndex] = NULL;
  408. }
  409. if (pValue)
  410. {
  411. m_pTable[nIndex] = pValue;
  412. if (m_pOwner) pValue->SetLogicalParent(m_pOwner);
  413. }
  414. }
  415. //////////////////////////////////////////////////////////////////////////
  416. // CXTPMarkupObject
  417. CXTPMarkupDependencyProperty* CXTPMarkupObject::m_pNameProperty = NULL;
  418. CXTPMarkupDependencyProperty* CXTPMarkupObject::m_pKeyProperty = NULL;
  419. CXTPMarkupObject* AFX_CDECL CXTPMarkupObject::CreateMarkupObject()
  420. {
  421. return new CXTPMarkupObject();
  422. }
  423. CXTPMarkupType* CXTPMarkupObject::GetMarkupBaseType()
  424. {
  425. return NULL;
  426. }
  427. const CXTPMarkupType* CXTPMarkupObject::typeCXTPMarkupObject = new CXTPMarkupType(
  428. NULL, L"CXTPMarkupObject", &CXTPMarkupObject::CreateMarkupObject, &CXTPMarkupObject::GetMarkupBaseType, &CXTPMarkupObject::RegisterMarkupClass);
  429. CXTPMarkupType* CXTPMarkupObject::GetType() const
  430. {
  431. return MARKUP_TYPE(CXTPMarkupObject);
  432. }
  433. void CXTPMarkupObject::RegisterMarkupClass()
  434. {
  435. m_pNameProperty = CXTPMarkupDependencyProperty::Register(L"x:Name", MARKUP_TYPE(CXTPMarkupString), MARKUP_TYPE(CXTPMarkupObject));
  436. m_pKeyProperty = CXTPMarkupDependencyProperty::Register(L"x:Key", MARKUP_TYPE(CXTPMarkupObject), MARKUP_TYPE(CXTPMarkupObject));
  437. }
  438. CXTPMarkupObject::CXTPMarkupObject()
  439. {
  440. m_dwRef = 1;
  441. m_pLogicalParent = NULL;
  442. m_lpMarkupTag = NULL;
  443. m_pProperties = NULL;
  444. }
  445. CXTPMarkupObject::~CXTPMarkupObject()
  446. {
  447. ASSERT(m_dwRef <= 1);
  448. SAFE_DELETE(m_pProperties);
  449. if (m_lpMarkupTag) delete[] m_lpMarkupTag;
  450. }
  451. DWORD CXTPMarkupObject::AddRef()
  452. {
  453. return InterlockedIncrement(&m_dwRef);
  454. }
  455. void CXTPMarkupObject::OnFinalRelease()
  456. {
  457. delete this;
  458. }
  459. DWORD CXTPMarkupObject::Release()
  460. {
  461. if (m_dwRef == 0)
  462. return 0;
  463. LONG lResult = InterlockedDecrement(&m_dwRef);
  464. if (lResult == 0)
  465. {
  466. OnFinalRelease();
  467. }
  468. return lResult;
  469. }
  470. CXTPMarkupObject* CXTPMarkupObject::ConvertFrom(CXTPMarkupObject* /*pObject*/) const
  471. {
  472. return NULL;
  473. }
  474. void CXTPMarkupObject::SetValue(CXTPMarkupDependencyProperty* pProperty, CXTPMarkupObject* pValue)
  475. {
  476. if (!pProperty)
  477. return;
  478. if (pValue != NULL && !pValue->GetType()->IsDerivedFrom(pProperty->GetPropetyType()))
  479. {
  480. ASSERT(FALSE);
  481. return;
  482. }
  483. if (pValue && !m_pProperties)
  484. {
  485. m_pProperties = new CXTPMarkupProperties(this);
  486. }
  487. CXTPMarkupObject* pOldValue = GetValue(pProperty);
  488. if (m_pProperties)
  489. {
  490. m_pProperties->Set(pProperty, pValue);
  491. }
  492. CXTPMarkupObject* pNewValue = GetValue(pProperty);
  493. if (::IsEqual(pNewValue, pOldValue))
  494. return;
  495. OnPropertyChanged(pProperty, pOldValue, pNewValue);
  496. if (pProperty->GetFlags() & CXTPMarkupPropertyMetadata::flagInherited)
  497. {
  498. RecursePropertyChanged(pProperty, pOldValue, pNewValue);
  499. }
  500. }
  501. void CXTPMarkupObject::RecursePropertyChanged(CXTPMarkupDependencyProperty* pProperty, CXTPMarkupObject* pOldValue, CXTPMarkupObject* pNewValue)
  502. {
  503. int nCount = GetLogicalChildrenCount();
  504. for (int i = 0; i < nCount; i++)
  505. {
  506. CXTPMarkupObject* pObject = GetLogicalChild(i);
  507. if (!pObject)
  508. continue;
  509. if (pObject->IsKindOf(pProperty->GetOwnerType()))
  510. {
  511. pObject->OnPropertyChanged(pProperty, pOldValue, pNewValue);
  512. }
  513. pObject->RecursePropertyChanged(pProperty, pOldValue, pNewValue);
  514. }
  515. }
  516. void CXTPMarkupObject::OnPropertyChanged(CXTPMarkupDependencyProperty* pProperty, CXTPMarkupObject* pOldValue, CXTPMarkupObject* pNewValue)
  517. {
  518. if (pProperty->GetMetadata() && pProperty->GetMetadata()->m_pPropertyChanged != NULL)
  519. {
  520. CXTPMarkupPropertyChangedEventArgs e(pProperty, pOldValue, pNewValue);
  521. (*pProperty->GetMetadata()->m_pPropertyChanged)(this, &e);
  522. }
  523. }
  524. CXTPMarkupObject* CXTPMarkupObject::GetValueSource(CXTPMarkupDependencyProperty* pProperty) const
  525. {
  526. CXTPMarkupObject* pValue = GetValueCore(pProperty);
  527. if (pValue)
  528. {
  529. return (CXTPMarkupObject*)this;
  530. }
  531. if (pProperty->GetFlags() & CXTPMarkupPropertyMetadata::flagInherited)
  532. {
  533. CXTPMarkupObject* pLogicalParent = GetLogicalParent();
  534. while (pLogicalParent)
  535. {
  536. pValue = pLogicalParent->GetValueCore(pProperty);
  537. if (pValue)
  538. return pLogicalParent;
  539. pLogicalParent = pLogicalParent->GetLogicalParent();
  540. }
  541. }
  542. return NULL;
  543. }
  544. CXTPMarkupObject* CXTPMarkupObject::GetValueCore(CXTPMarkupDependencyProperty* pProperty) const
  545. {
  546. CXTPMarkupObject* pValue = m_pProperties ? m_pProperties->Lookup(pProperty) : NULL;
  547. return pValue;
  548. }
  549. CXTPMarkupObject* CXTPMarkupObject::GetValue(CXTPMarkupDependencyProperty* pProperty) const
  550. {
  551. CXTPMarkupObject* pValue = GetValueCore(pProperty);
  552. if (pValue)
  553. return pValue;
  554. if (pProperty->GetFlags() & CXTPMarkupPropertyMetadata::flagInherited)
  555. {
  556. CXTPMarkupObject* pLogicalParent = GetLogicalParent();
  557. while (pLogicalParent)
  558. {
  559. pValue = pLogicalParent->GetValueCore(pProperty);
  560. if (pValue)
  561. return pValue;
  562. pLogicalParent = pLogicalParent->GetLogicalParent();
  563. }
  564. }
  565. if (pProperty->GetMetadata() && pProperty->GetMetadata()->m_pDefaultValue)
  566. return pProperty->GetMetadata()->m_pDefaultValue;
  567. return NULL;
  568. }
  569. void CXTPMarkupObject::SetLogicalParent(CXTPMarkupObject* pObject)
  570. {
  571. m_pLogicalParent = pObject;
  572. }
  573. CXTPMarkupObject* CXTPMarkupObject::GetLogicalParent() const
  574. {
  575. return m_pLogicalParent;
  576. }
  577. void CXTPMarkupObject::SetContentObject(CXTPMarkupBuilder* pBuilder, CXTPMarkupObject* pContent)
  578. {
  579. if (IsStringObject(pContent))
  580. {
  581. pBuilder->ThrowBuilderException(CXTPMarkupBuilder::FormatString(
  582. _T("Cannot convert the string '%ls' into a '%ls' object"),
  583. (LPCTSTR)(LPCWSTR)*((CXTPMarkupString*)pContent), (LPCTSTR)GetType()->m_lpszClassName));
  584. }
  585. else
  586. {
  587. pBuilder->ThrowBuilderException(CXTPMarkupBuilder::FormatString(_T("Cannot add content to an object of type '%ls'"),
  588. (LPCTSTR)GetType()->m_lpszClassName));
  589. }
  590. }
  591. BOOL CXTPMarkupObject::HasContentObject() const
  592. {
  593. return FALSE;
  594. }
  595. BOOL CXTPMarkupObject::AllowWhiteSpaceContent() const
  596. {
  597. return FALSE;
  598. }
  599. void CXTPMarkupObject::SetPropertyObject(CXTPMarkupBuilder* pBuilder, CXTPMarkupDependencyProperty* pProperty, CXTPMarkupObject* pValue)
  600. {
  601. ASSERT(pValue);
  602. if (pValue != NULL && !pValue->IsKindOf(pProperty->GetPropetyType()))
  603. {
  604. CXTPMarkupObject* pNewValue = pBuilder->ConvertValue(pProperty, pValue);
  605. MARKUP_RELEASE(pValue);
  606. pValue = pNewValue;
  607. }
  608. SetValue(pProperty, pValue);
  609. }
  610. CXTPMarkupObject* CXTPMarkupObject::FindName(LPCWSTR lpszName)
  611. {
  612. CXTPMarkupString* pName = MARKUP_STATICCAST(CXTPMarkupString, GetValue(m_pNameProperty));
  613. if (pName && (wcscmp(*pName, lpszName) == 0))
  614. return this;
  615. int nCount = GetLogicalChildrenCount();
  616. for (int i = 0; i < nCount; i++)
  617. {
  618. CXTPMarkupObject* pResult = GetLogicalChild(i)->FindName(lpszName);
  619. if (pResult)
  620. {
  621. return pResult;
  622. }
  623. }
  624. return NULL;
  625. }
  626. int CXTPMarkupObject::GetLogicalChildrenCount() const
  627. {
  628. return 0;
  629. }
  630. CXTPMarkupObject* CXTPMarkupObject::GetLogicalChild(int /*nIndex*/) const
  631. {
  632. ASSERT(FALSE);
  633. return NULL;
  634. }
  635. BOOL CXTPMarkupObject::IsKindOf(const CXTPMarkupType* pClass) const
  636. {
  637. CXTPMarkupType* pTypeThis = GetType();
  638. return pTypeThis->IsDerivedFrom(pClass);
  639. }
  640. //////////////////////////////////////////////////////////////////////////
  641. // CXTPMarkupAutoPtr
  642. class CXTPMarkupAutoPtr
  643. {
  644. public:
  645. CXTPMarkupAutoPtr(CXTPMarkupObject* pObject = NULL)
  646. {
  647. m_pObject = pObject;
  648. }
  649. ~CXTPMarkupAutoPtr()
  650. {
  651. MARKUP_RELEASE(m_pObject);
  652. }
  653. CXTPMarkupObject* AddRef() const
  654. {
  655. m_pObject->AddRef();
  656. return m_pObject;
  657. }
  658. public:
  659. CXTPMarkupObject* m_pObject;
  660. };
  661. //////////////////////////////////////////////////////////////////////////
  662. // CXTPMarkupThickness
  663. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupThickness, CXTPMarkupObject);
  664. void CXTPMarkupThickness::RegisterMarkupClass()
  665. {
  666. }
  667. CXTPMarkupThickness* CXTPMarkupThickness::CreateValue()
  668. {
  669. static CXTPMarkupAutoPtr defaultValues(new CXTPMarkupThickness());
  670. return (CXTPMarkupThickness*)defaultValues.AddRef();
  671. }
  672. CXTPMarkupThickness::CXTPMarkupThickness(long uniformLength)
  673. {
  674. left = top = right = bottom = uniformLength;
  675. }
  676. CXTPMarkupThickness::CXTPMarkupThickness(long l, long t, long r, long b)
  677. {
  678. left = l;
  679. top = t;
  680. right = r;
  681. bottom = b;
  682. }
  683. CRect CXTPMarkupThickness::HelperDeflateRect(CRect rt, CXTPMarkupThickness* thick)
  684. {
  685. if (!thick)
  686. return rt;
  687. return CRect(CPoint(rt.left + thick->left, rt.top + thick->top),
  688. CSize(max(0, (rt.Width() - thick->left) - thick->right), max(0, (rt.Height() - thick->top) - thick->bottom)));
  689. }
  690. CXTPMarkupObject* CXTPMarkupThickness::ConvertFrom(CXTPMarkupObject* pObject) const
  691. {
  692. if (IsStringObject(pObject))
  693. {
  694. LPCWSTR lpszValue = *((CXTPMarkupString*)pObject);
  695. if (wcschr(lpszValue, L',') == NULL)
  696. {
  697. int nThickness = _wtoi(lpszValue);
  698. return new CXTPMarkupThickness(nThickness);
  699. }
  700. else
  701. {
  702. int left = 0, top = 0, right = 0, bottom = 0;
  703. if ( WSCANF_S(lpszValue, L"%i, %i, %i, %i", &left, &top, &right, &bottom) != 4)
  704. return NULL;
  705. return new CXTPMarkupThickness(left, top, right, bottom);
  706. }
  707. }
  708. return NULL;
  709. }
  710. BOOL CXTPMarkupThickness::IsEqual(const CXTPMarkupObject* pObject) const
  711. {
  712. if (!pObject)
  713. return FALSE;
  714. if (pObject->GetType() != MARKUP_TYPE(CXTPMarkupThickness))
  715. return FALSE;
  716. return left == ((CXTPMarkupThickness*)pObject)->left &&
  717. top == ((CXTPMarkupThickness*)pObject)->top &&
  718. right == ((CXTPMarkupThickness*)pObject)->right &&
  719. bottom == ((CXTPMarkupThickness*)pObject)->bottom;
  720. }
  721. //////////////////////////////////////////////////////////////////////////
  722. // CXTPMarkupInt
  723. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupInt, CXTPMarkupObject);
  724. void CXTPMarkupInt::RegisterMarkupClass()
  725. {
  726. }
  727. CXTPMarkupInt::CXTPMarkupInt(int nValue)
  728. {
  729. m_nValue = nValue;
  730. }
  731. CXTPMarkupObject* CXTPMarkupInt::ConvertFrom(CXTPMarkupObject* pObject) const
  732. {
  733. if (IsStringObject(pObject))
  734. {
  735. return new CXTPMarkupInt(_wtoi(*((CXTPMarkupString*)pObject)));
  736. }
  737. return NULL;
  738. }
  739. BOOL CXTPMarkupInt::IsEqual(const CXTPMarkupObject* pObject) const
  740. {
  741. if (!pObject)
  742. return FALSE;
  743. if (pObject->GetType() != MARKUP_TYPE(CXTPMarkupInt))
  744. return FALSE;
  745. return m_nValue == ((CXTPMarkupInt*)pObject)->m_nValue;
  746. }
  747. //////////////////////////////////////////////////////////////////////////
  748. // CXTPMarkupDouble
  749. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupDouble, CXTPMarkupObject);
  750. void CXTPMarkupDouble::RegisterMarkupClass()
  751. {
  752. }
  753. CXTPMarkupDouble::CXTPMarkupDouble(double dValue)
  754. {
  755. m_dValue = dValue;
  756. }
  757. CXTPMarkupObject* CXTPMarkupDouble::ConvertFrom(CXTPMarkupObject* pObject) const
  758. {
  759. if (IsStringObject(pObject))
  760. {
  761. LPCWSTR lpszValue = *(CXTPMarkupString*)pObject;
  762. float x = 0;
  763. if (WSCANF_S(lpszValue, L"%f", &x) == 1)
  764. return new CXTPMarkupDouble((double)x);
  765. }
  766. return NULL;
  767. }
  768. BOOL CXTPMarkupDouble::IsEqual(const CXTPMarkupObject* pObject) const
  769. {
  770. if (!pObject)
  771. return FALSE;
  772. if (pObject->GetType() != MARKUP_TYPE(CXTPMarkupDouble))
  773. return FALSE;
  774. return m_dValue == ((CXTPMarkupDouble*)pObject)->m_dValue;
  775. }
  776. //////////////////////////////////////////////////////////////////////////
  777. // CXTPMarkupEnum
  778. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupEnum, CXTPMarkupObject);
  779. void CXTPMarkupEnum::RegisterMarkupClass()
  780. {
  781. }
  782. CXTPMarkupEnum::CXTPMarkupEnum(int nValue)
  783. {
  784. m_nValue = nValue;
  785. }
  786. CXTPMarkupObject* CXTPMarkupEnum::ConvertFrom(CXTPMarkupObject* /*pObject*/) const
  787. {
  788. return NULL;
  789. }
  790. BOOL CXTPMarkupEnum::IsEqual(const CXTPMarkupObject* pObject) const
  791. {
  792. if (!pObject)
  793. return FALSE;
  794. if (pObject->GetType() != MARKUP_TYPE(CXTPMarkupEnum))
  795. return FALSE;
  796. return m_nValue == ((CXTPMarkupEnum*)pObject)->m_nValue;
  797. }
  798. CXTPMarkupEnum* CXTPMarkupEnum::CreateValue(int nValue)
  799. {
  800. static CXTPMarkupAutoPtr defaultValues[8];
  801. if (nValue > 7 || nValue < 0)
  802. return new CXTPMarkupEnum(nValue);
  803. CXTPMarkupObject*& pObject = defaultValues[nValue].m_pObject;
  804. if (pObject == NULL)
  805. pObject = new CXTPMarkupEnum(nValue);
  806. pObject->AddRef();
  807. return (CXTPMarkupEnum*)pObject;
  808. }
  809. //////////////////////////////////////////////////////////////////////////
  810. // CXTPMarkupBool
  811. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupBool, CXTPMarkupObject);
  812. void CXTPMarkupBool::RegisterMarkupClass()
  813. {
  814. }
  815. CXTPMarkupBool::CXTPMarkupBool(BOOL bValue)
  816. {
  817. m_bValue = bValue;
  818. }
  819. CXTPMarkupBool* CXTPMarkupBool::CreateTrueValue()
  820. {
  821. static CXTPMarkupAutoPtr defaultValue(new CXTPMarkupBool(TRUE));
  822. return (CXTPMarkupBool*)defaultValue.AddRef();
  823. }
  824. CXTPMarkupBool* CXTPMarkupBool::CreateFalseValue()
  825. {
  826. static CXTPMarkupAutoPtr defaultValue(new CXTPMarkupBool(FALSE));
  827. return (CXTPMarkupBool*)defaultValue.AddRef();
  828. }
  829. CXTPMarkupObject* CXTPMarkupBool::ConvertFrom(CXTPMarkupObject* pObject) const
  830. {
  831. if (IsStringObject(pObject))
  832. {
  833. if (_wcsicmp(*((CXTPMarkupString*)pObject), L"True") == 0)
  834. {
  835. return CreateTrueValue();
  836. }
  837. if (_wcsicmp(*((CXTPMarkupString*)pObject), L"False") == 0)
  838. {
  839. return CreateFalseValue();
  840. }
  841. }
  842. return FALSE;
  843. }
  844. UINT CXTPMarkupBool::GetHashKey() const
  845. {
  846. return m_bValue;
  847. }
  848. BOOL CXTPMarkupBool::IsEqual(const CXTPMarkupObject* pObject) const
  849. {
  850. if (!pObject)
  851. return FALSE;
  852. if (pObject->GetType() != MARKUP_TYPE(CXTPMarkupBool))
  853. return FALSE;
  854. if (m_bValue != ((CXTPMarkupBool*)pObject)->m_bValue)
  855. return FALSE;
  856. return TRUE;
  857. }
  858. //////////////////////////////////////////////////////////////////////////
  859. // CXTPMarkupColor
  860. IMPLEMENT_MARKUPCLASS(L"Color", CXTPMarkupColor, CXTPMarkupObject);
  861. void CXTPMarkupColor::RegisterMarkupClass()
  862. {
  863. }
  864. CXTPMarkupColor::CXTPMarkupColor(COLORREF nValue)
  865. {
  866. m_nValue = nValue;
  867. }
  868. BOOL CXTPMarkupColor::ConvertFromString(LPCWSTR lpszValue, COLORREF& clr)
  869. {
  870. if (lpszValue[0] == '#' && wcslen(lpszValue) == 7)
  871. {
  872. COLORREF clrRed = 0, clrGreen = 0, clrBlue = 0;
  873. if (WSCANF_S(lpszValue, L"#%2x%2x%2x", &clrRed, &clrGreen, &clrBlue) != 3)
  874. return FALSE;
  875. clr = RGB(clrRed, clrGreen, clrBlue);
  876. return TRUE;
  877. }
  878. if (lpszValue[0] == '#' && wcslen(lpszValue) == 9)
  879. {
  880. COLORREF clrRed = 0, clrGreen = 0, clrBlue = 0, clrAlpha = 0;
  881. if (WSCANF_S(lpszValue, L"#%2x%2x%2x%2x", &clrAlpha, &clrRed, &clrGreen, &clrBlue) != 4)
  882. return FALSE;
  883. clr = RGB(clrRed, clrGreen, clrBlue);
  884. return TRUE;
  885. }
  886. if (lpszValue[0] != '#')
  887. {
  888. if (CXTPMarkupBuilder::ColorStringToKnownColor(lpszValue, clr))
  889. {
  890. return TRUE;
  891. }
  892. }
  893. return FALSE;
  894. }
  895. CXTPMarkupObject* CXTPMarkupColor::ConvertFrom(CXTPMarkupObject* pObject) const
  896. {
  897. if (IsStringObject(pObject))
  898. {
  899. COLORREF clr;
  900. if (ConvertFromString(*((CXTPMarkupString*)pObject), clr))
  901. {
  902. return new CXTPMarkupColor(clr);
  903. }
  904. }
  905. return NULL;
  906. }
  907. BOOL CXTPMarkupColor::IsEqual(const CXTPMarkupObject* pObject) const
  908. {
  909. if (!pObject)
  910. return FALSE;
  911. if (pObject->GetType() != MARKUP_TYPE(CXTPMarkupColor))
  912. return FALSE;
  913. return m_nValue == ((CXTPMarkupColor*)pObject)->m_nValue;
  914. }
  915. void CXTPMarkupColor::SetContentObject(CXTPMarkupBuilder* pBuilder, CXTPMarkupObject* pContent)
  916. {
  917. if (IsStringObject(pContent))
  918. {
  919. COLORREF clr;
  920. if (ConvertFromString(*((CXTPMarkupString*)pContent), clr))
  921. {
  922. m_nValue = clr;
  923. MARKUP_RELEASE(pContent);
  924. return;
  925. }
  926. }
  927. CXTPMarkupObject::SetContentObject(pBuilder, pContent);
  928. }
  929. //////////////////////////////////////////////////////////////////////////
  930. // CXTPMarkupString
  931. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupString, CXTPMarkupObject);
  932. void CXTPMarkupString::RegisterMarkupClass()
  933. {
  934. }
  935. CXTPMarkupString::CXTPMarkupString(LPCWSTR lpszValue, int nLength)
  936. {
  937. m_nLength = !lpszValue ? 0 : nLength == -1 ? (int)wcslen(lpszValue) : nLength;
  938. m_lpszValue = new WCHAR[m_nLength + 1];
  939. if (!lpszValue)
  940. m_lpszValue[0] = 0;
  941. else if (nLength == -1)
  942. memcpy(m_lpszValue, lpszValue, (m_nLength + 1) * sizeof(WCHAR));
  943. else
  944. {
  945. memcpy(m_lpszValue, lpszValue, nLength * sizeof(WCHAR));
  946. m_lpszValue[nLength] = 0;
  947. }
  948. }
  949. CXTPMarkupString* CXTPMarkupString::CreateValue(LPCWSTR lpszString, int nLength)
  950. {
  951. if (lpszString == 0 || nLength == 0 || lpszString[0] == 0)
  952. {
  953. static CXTPMarkupAutoPtr stringEmpty(new CXTPMarkupString(NULL, 0));
  954. return (CXTPMarkupString*)stringEmpty.AddRef();
  955. }
  956. if (lpszString[1] != 0)
  957. return new CXTPMarkupString(lpszString, nLength);
  958. if (lpszString[0] == L' ')
  959. {
  960. static CXTPMarkupAutoPtr stringSpace(new CXTPMarkupString(L" ", 1));
  961. return (CXTPMarkupString*)stringSpace.AddRef();
  962. }
  963. if (lpszString[0] == L'n')
  964. {
  965. static CXTPMarkupAutoPtr stringLineBreak(new CXTPMarkupString(L"n", 1));
  966. return (CXTPMarkupString*)stringLineBreak.AddRef();
  967. }
  968. return new CXTPMarkupString(lpszString, nLength);
  969. }
  970. UINT CXTPMarkupString::GetHashKey() const
  971. {
  972. LPCWSTR key = m_lpszValue;
  973. UINT nHash = 0;
  974. while (*key)
  975. nHash = (nHash<<5) + nHash + *key++;
  976. return nHash;
  977. }
  978. BOOL CXTPMarkupString::IsEqual(const CXTPMarkupObject* pObject) const
  979. {
  980. if (!pObject)
  981. return FALSE;
  982. if (pObject->GetType() != MARKUP_TYPE(CXTPMarkupString))
  983. return FALSE;
  984. if (m_nLength != ((CXTPMarkupString*)pObject)->m_nLength)
  985. return FALSE;
  986. return wcscmp(m_lpszValue, ((CXTPMarkupString*)pObject)->m_lpszValue) == 0;
  987. }
  988. CXTPMarkupString::~CXTPMarkupString()
  989. {
  990. delete[] m_lpszValue;
  991. }
  992. //////////////////////////////////////////////////////////////////////////
  993. // CXTPMarkupCollection
  994. IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupCollection, CXTPMarkupObject);
  995. void CXTPMarkupCollection::RegisterMarkupClass()
  996. {
  997. }
  998. CXTPMarkupCollection::CXTPMarkupCollection()
  999. {
  1000. m_pElementType = NULL;
  1001. m_bLogicalParent = TRUE;
  1002. }
  1003. CXTPMarkupCollection::~CXTPMarkupCollection()
  1004. {
  1005. RemoveAll();
  1006. }
  1007. void CXTPMarkupCollection::RemoveAll()
  1008. {
  1009. for (int i = 0; i < m_arrItems.GetSize(); i++)
  1010. {
  1011. if (m_bLogicalParent) m_arrItems[i]->SetLogicalParent(NULL);
  1012. m_arrItems[i]->Release();
  1013. }
  1014. m_arrItems.RemoveAll();
  1015. }
  1016. void CXTPMarkupCollection::Remove(int nIndex)
  1017. {
  1018. if (nIndex < m_arrItems.GetSize())
  1019. {
  1020. CXTPMarkupObject* pItem = m_arrItems[nIndex];
  1021. m_arrItems.RemoveAt(nIndex);
  1022. if (m_bLogicalParent) pItem->SetLogicalParent(NULL);
  1023. pItem->Release();
  1024. }
  1025. }
  1026. void CXTPMarkupCollection::Add(CXTPMarkupObject* pElement)
  1027. {
  1028. ASSERT(pElement);
  1029. ASSERT(m_pElementType);
  1030. ASSERT(pElement->IsKindOf(m_pElementType));
  1031. if (!pElement || !pElement->IsKindOf(m_pElementType))
  1032. return;
  1033. if (m_bLogicalParent)
  1034. {
  1035. ASSERT(pElement->GetLogicalParent() == NULL);
  1036. pElement->SetLogicalParent(this);
  1037. }
  1038. int nIndex = (int)m_arrItems.Add(pElement);
  1039. OnItemAdded(pElement, nIndex);
  1040. }
  1041. int CXTPMarkupCollection::IndexOf(CXTPMarkupObject* pElement) const
  1042. {
  1043. for (int i = 0; i < m_arrItems.GetSize(); i++)
  1044. {
  1045. if (pElement == m_arrItems[i])
  1046. return i;
  1047. }
  1048. return -1;
  1049. }
  1050. void CXTPMarkupCollection::OnItemAdded(CXTPMarkupObject* /*pItem*/, int /*nIndex*/)
  1051. {
  1052. }
  1053. void CXTPMarkupCollection::SetContentObject(CXTPMarkupBuilder* pBuilder, CXTPMarkupObject* pContent)
  1054. {
  1055. ASSERT(m_pElementType);
  1056. if (pContent->IsKindOf(m_pElementType))
  1057. {
  1058. Add(pContent);
  1059. }
  1060. else
  1061. {
  1062. pBuilder->ThrowBuilderException(CXTPMarkupBuilder::FormatString(_T("'%ls' object cannot be added to '%ls'. Object cannot be converted to type '%ls'"),
  1063. (LPCTSTR)pContent->GetType()->m_lpszClassName, (LPCTSTR)GetType()->m_lpszClassName, (LPCTSTR)m_pElementType->m_lpszClassName));
  1064. }
  1065. }
  1066. BOOL CXTPMarkupCollection::HasContentObject() const
  1067. {
  1068. return GetCount() > 0;
  1069. }
  1070. int CXTPMarkupCollection::GetLogicalChildrenCount() const
  1071. {
  1072. return (int)m_arrItems.GetSize();
  1073. }
  1074. CXTPMarkupObject* CXTPMarkupCollection::GetLogicalChild(int nIndex) const
  1075. {
  1076. return m_arrItems[nIndex];
  1077. }