nim_duilib/tool_kits/duilib/Control/TreeView.cpp
jiajia_deng f811e9836c Fix #85 crash when removing TreeView from Box
- Set all of the child node parent is root node.

Signed-off-by: jiajia_deng <2894220@gmail.com>
2019-07-24 14:37:27 +08:00

257 lines
5.3 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 "TreeView.h"
namespace ui
{
TreeNode::TreeNode() :
m_bExpand(true),
m_pTreeView(nullptr),
m_pParentTreeNode(nullptr),
m_iDepth(ROOT_NODE_DEPTH),
m_aTreeNodes()
{
}
bool TreeNode::IsVisible() const
{
return ListContainerElement::IsVisible()
&& (!m_pParentTreeNode || (m_pParentTreeNode && m_pParentTreeNode->IsExpand() && m_pParentTreeNode->IsVisible()));
}
void TreeNode::SetInternVisible(bool bVisible)
{
Control::SetInternVisible(bVisible);
if (m_items.empty()) return;
for (auto it = m_items.begin(); it != m_items.end(); it++)
{
auto pControl = *it;
// 控制子控件显示状态
// InternVisible状态应由子控件自己控制
pControl->SetInternVisible(Control::IsVisible());
}
}
void TreeNode::SetWindow(Window* pManager, Box* pParent, bool bInit)
{
for (auto it = m_aTreeNodes.begin(); it != m_aTreeNodes.end(); it++)
{
// 将所有子控件的父节点GetParent都设置为 TreeView 中隐藏的 TreeNode
// 在 TreeView 递归销毁子控件时不会因为获取不到父容器指针而崩溃
// RootNode 是一个智能指针,在 TreeView 完全销毁以后会自动销毁
(*it)->SetWindow(pManager, m_pTreeView->GetRootNode(), bInit);
}
ListContainerElement::SetWindow(pManager, pParent, bInit);
}
void TreeNode::SetTreeView(TreeView* pTreeView)
{
m_pTreeView = pTreeView;
}
bool TreeNode::OnClickItem(EventArgs* pMsg)
{
TreeNode* pItem = static_cast<TreeNode*>(pMsg->pSender);
pItem->SetExpand(!pItem->IsExpand());
return true;
}
TreeNode* TreeNode::GetParentNode()
{
return m_pParentTreeNode;
}
void TreeNode::SetParentNode(TreeNode* pParentTreeNode)
{
m_pParentTreeNode = pParentTreeNode;
}
bool TreeNode::AddChildNode(TreeNode* pTreeNode)
{
return AddChildNodeAt(pTreeNode, GetChildNodeCount());
}
bool TreeNode::AddChildNodeAt(TreeNode* pTreeNode, std::size_t iIndex)
{
if( iIndex < 0 || iIndex > m_aTreeNodes.size() ) return false;
m_aTreeNodes.insert(m_aTreeNodes.begin() + iIndex, pTreeNode);
pTreeNode->m_iDepth = m_iDepth + 1;
pTreeNode->SetParentNode(this);
pTreeNode->SetTreeView(m_pTreeView);
if( m_pWindow != NULL ) m_pWindow->InitControls(pTreeNode, NULL);
pTreeNode->OnEvent[kEventClick] += nbase::Bind(&TreeNode::OnClickItem, this, std::placeholders::_1);
UiRect padding = m_pLayout->GetPadding();
int nodeIndex = -1;
if (m_iDepth != ROOT_NODE_DEPTH) {
nodeIndex = GetIndex();
padding.left += m_pTreeView->GetIndent();
}
pTreeNode->m_pLayout->SetPadding(padding);
std::size_t nGlobalIndex = iIndex;
for (std::size_t i = 0; i < iIndex; i++)
{
nGlobalIndex += ((TreeNode*)m_aTreeNodes[i])->GetDescendantNodeCount();
}
return m_pTreeView->ListBox::AddAt(pTreeNode, (int)(nodeIndex + nGlobalIndex + 1));
}
bool TreeNode::RemoveChildNodeAt(std::size_t iIndex)
{
if (iIndex < 0 || iIndex >= m_aTreeNodes.size()) {
return false;
}
TreeNode* pTreeNode = ((TreeNode*)m_aTreeNodes[iIndex]);
m_aTreeNodes.erase(m_aTreeNodes.begin() + iIndex);
return pTreeNode->RemoveSelf();
}
bool TreeNode::RemoveChildNode(TreeNode* pTreeNode)
{
auto it = std::find(m_aTreeNodes.begin(), m_aTreeNodes.end(), pTreeNode);
if (it == m_aTreeNodes.end()) {
return false;
}
int iIndex = it - m_aTreeNodes.begin();
return RemoveChildNodeAt(iIndex);
}
void TreeNode::RemoveAllChildNode()
{
while (m_aTreeNodes.size() > 0)
{
RemoveChildNodeAt(0);
}
}
bool TreeNode::RemoveSelf()
{
for( auto it = m_aTreeNodes.begin(); it != m_aTreeNodes.end(); it++ )
{
(*it)->RemoveSelf();
}
m_aTreeNodes.clear();
if (m_iDepth != ROOT_NODE_DEPTH) {
return m_pTreeView->ListBox::RemoveAt(GetIndex());
}
return false;
}
int TreeNode::GetDescendantNodeCount()
{
int nodeCount = (int)GetChildNodeCount();
for( auto it = m_aTreeNodes.begin(); it != m_aTreeNodes.end(); it++ )
{
nodeCount += (*it)->GetDescendantNodeCount();
}
return nodeCount;
}
std::size_t TreeNode::GetChildNodeCount()
{
return m_aTreeNodes.size();
}
TreeNode* TreeNode::GetChildNode(std::size_t iIndex)
{
if( iIndex < 0 || iIndex >= m_aTreeNodes.size() ) return NULL;
return static_cast<TreeNode*>(m_aTreeNodes[iIndex]);
}
int TreeNode::GetChildNodeIndex(TreeNode* pTreeNode)
{
auto it = std::find(m_aTreeNodes.begin(), m_aTreeNodes.end(), pTreeNode);
if (it == m_aTreeNodes.end()) {
return -1;
}
return it - m_aTreeNodes.begin();
}
bool TreeNode::IsExpand() const
{
return m_bExpand;
}
void TreeNode::SetExpand(bool bExpand)
{
if(m_bExpand == bExpand) {
return;
}
m_bExpand = bExpand;
m_pTreeView->Arrange();
}
int TreeNode::GetDepth()
{
return m_iDepth;
}
TreeView::TreeView() :
ListBox(new VLayout),
m_iIndent(0),
m_rootNode()
{
m_rootNode.reset(new TreeNode());
m_rootNode->SetTreeView(this);
}
void TreeView::SetAttribute(const std::wstring& strName, const std::wstring& strValue)
{
if( strName == _T("indent") ) {
SetIndent(_ttoi(strValue.c_str()));
}
else {
ListBox::SetAttribute(strName, strValue);
}
}
bool TreeView::Add(Control* pControl)
{
ASSERT(FALSE);
return true;
}
bool TreeView::AddAt(Control* pControl, std::size_t iIndex)
{
ASSERT(FALSE);
return true;
}
bool TreeView::Remove(Control* pControl)
{
ASSERT(FALSE);
return true;
}
bool TreeView::RemoveAt(std::size_t iIndex)
{
ASSERT(FALSE);
return true;
}
void TreeView::RemoveAll()
{
ASSERT(FALSE);
}
void TreeView::SetWindow(Window* pManager, Box* pParent, bool bInit)
{
ListBox::SetWindow(pManager, pParent, bInit);
m_rootNode->SetWindow(pManager, pParent, bInit);
}
}