Fix incorrect handling of ItemsAdded() in wxDataViewCtrl.
When adding items to the model in bulk and then calling ItemsAdded(), internal representation in both the generic and GTK+ versions wasn't updated correctly if the order of the notifications was such that an item would be inserted after other new, but not yet inserted, items. Fixes bug #13587. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69547 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -377,6 +377,22 @@ public:
|
|||||||
m_branchData->children.Remove(node);
|
m_branchData->children.Remove(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns position of child node for given item in children list or wxNOT_FOUND
|
||||||
|
int FindChildByItem(const wxDataViewItem& item) const
|
||||||
|
{
|
||||||
|
if ( !m_branchData )
|
||||||
|
return wxNOT_FOUND;
|
||||||
|
|
||||||
|
const wxDataViewTreeNodes& nodes = m_branchData->children;
|
||||||
|
const int len = nodes.size();
|
||||||
|
for ( int i = 0; i < len; i++ )
|
||||||
|
{
|
||||||
|
if ( nodes[i]->m_item == item )
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return wxNOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
const wxDataViewItem & GetItem() const { return m_item; }
|
const wxDataViewItem & GetItem() const { return m_item; }
|
||||||
void SetItem( const wxDataViewItem & item ) { m_item = item; }
|
void SetItem( const wxDataViewItem & item ) { m_item = item; }
|
||||||
|
|
||||||
@@ -2060,17 +2076,59 @@ bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxData
|
|||||||
if ( !parentNode )
|
if ( !parentNode )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
wxDataViewItemArray siblings;
|
wxDataViewItemArray modelSiblings;
|
||||||
GetModel()->GetChildren(parent, siblings);
|
GetModel()->GetChildren(parent, modelSiblings);
|
||||||
int itemPos = siblings.Index(item, /*fromEnd=*/true);
|
const int modelSiblingsSize = modelSiblings.size();
|
||||||
wxCHECK_MSG( itemPos != wxNOT_FOUND, false, "adding non-existent item?" );
|
|
||||||
|
int posInModel = modelSiblings.Index(item, /*fromEnd=*/true);
|
||||||
|
wxCHECK_MSG( posInModel != wxNOT_FOUND, false, "adding non-existent item?" );
|
||||||
|
|
||||||
wxDataViewTreeNode *itemNode = new wxDataViewTreeNode(parentNode, item);
|
wxDataViewTreeNode *itemNode = new wxDataViewTreeNode(parentNode, item);
|
||||||
itemNode->SetHasChildren(GetModel()->IsContainer(item));
|
itemNode->SetHasChildren(GetModel()->IsContainer(item));
|
||||||
|
|
||||||
parentNode->SetHasChildren(true);
|
parentNode->SetHasChildren(true);
|
||||||
parentNode->InsertChild(itemNode, itemPos);
|
|
||||||
|
const wxDataViewTreeNodes& nodeSiblings = parentNode->GetChildNodes();
|
||||||
|
const int nodeSiblingsSize = nodeSiblings.size();
|
||||||
|
|
||||||
|
int nodePos = 0;
|
||||||
|
|
||||||
|
if ( posInModel == modelSiblingsSize - 1 )
|
||||||
|
{
|
||||||
|
nodePos = nodeSiblingsSize;
|
||||||
|
}
|
||||||
|
else if ( modelSiblingsSize == nodeSiblingsSize + 1 )
|
||||||
|
{
|
||||||
|
// This is the simple case when our node tree already matches the
|
||||||
|
// model and only this one item is missing.
|
||||||
|
nodePos = posInModel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// It's possible that a larger discrepancy between the model and
|
||||||
|
// our realization exists. This can happen e.g. when adding a bunch
|
||||||
|
// of items to the model and then calling ItemsAdded() just once
|
||||||
|
// afterwards. In this case, we must find the right position by
|
||||||
|
// looking at sibling items.
|
||||||
|
|
||||||
|
// append to the end if we won't find a better position:
|
||||||
|
nodePos = nodeSiblingsSize;
|
||||||
|
|
||||||
|
for ( int nextItemPos = posInModel + 1;
|
||||||
|
nextItemPos < modelSiblingsSize;
|
||||||
|
nextItemPos++ )
|
||||||
|
{
|
||||||
|
int nextNodePos = parentNode->FindChildByItem(modelSiblings[nextItemPos]);
|
||||||
|
if ( nextNodePos != wxNOT_FOUND )
|
||||||
|
{
|
||||||
|
nodePos = nextNodePos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parentNode->ChangeSubTreeCount(+1);
|
parentNode->ChangeSubTreeCount(+1);
|
||||||
|
parentNode->InsertChild(itemNode, nodePos);
|
||||||
|
|
||||||
m_count = -1;
|
m_count = -1;
|
||||||
}
|
}
|
||||||
|
@@ -432,6 +432,20 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns position of child node for given item in children list or wxNOT_FOUND
|
||||||
|
int FindChildByItem(const wxDataViewItem& item) const
|
||||||
|
{
|
||||||
|
const void* itemId = item.GetID();
|
||||||
|
const wxGtkTreeModelChildren& nodes = m_children;
|
||||||
|
const int len = nodes.size();
|
||||||
|
for ( int i = 0; i < len; i++ )
|
||||||
|
{
|
||||||
|
if ( nodes[i] == itemId )
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return wxNOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
wxGtkTreeModelNode* GetParent()
|
wxGtkTreeModelNode* GetParent()
|
||||||
{ return m_parent; }
|
{ return m_parent; }
|
||||||
wxGtkTreeModelNodes &GetNodes()
|
wxGtkTreeModelNodes &GetNodes()
|
||||||
@@ -3672,15 +3686,56 @@ bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDa
|
|||||||
wxCHECK_MSG(parent_node, false,
|
wxCHECK_MSG(parent_node, false,
|
||||||
"Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
|
"Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
|
||||||
|
|
||||||
wxDataViewItemArray siblings;
|
wxDataViewItemArray modelSiblings;
|
||||||
m_wx_model->GetChildren(parent, siblings);
|
m_wx_model->GetChildren(parent, modelSiblings);
|
||||||
int itemPos = siblings.Index(item, /*fromEnd=*/true);
|
const int modelSiblingsSize = modelSiblings.size();
|
||||||
wxCHECK_MSG( itemPos != wxNOT_FOUND, false, "adding non-existent item?" );
|
|
||||||
|
int posInModel = modelSiblings.Index(item, /*fromEnd=*/true);
|
||||||
|
wxCHECK_MSG( posInModel != wxNOT_FOUND, false, "adding non-existent item?" );
|
||||||
|
|
||||||
|
const wxGtkTreeModelChildren& nodeSiblings = parent_node->GetChildren();
|
||||||
|
const int nodeSiblingsSize = nodeSiblings.size();
|
||||||
|
|
||||||
|
int nodePos = 0;
|
||||||
|
|
||||||
|
if ( posInModel == modelSiblingsSize - 1 )
|
||||||
|
{
|
||||||
|
nodePos = nodeSiblingsSize;
|
||||||
|
}
|
||||||
|
else if ( modelSiblingsSize == nodeSiblingsSize + 1 )
|
||||||
|
{
|
||||||
|
// This is the simple case when our node tree already matches the
|
||||||
|
// model and only this one item is missing.
|
||||||
|
nodePos = posInModel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// It's possible that a larger discrepancy between the model and
|
||||||
|
// our realization exists. This can happen e.g. when adding a bunch
|
||||||
|
// of items to the model and then calling ItemsAdded() just once
|
||||||
|
// afterwards. In this case, we must find the right position by
|
||||||
|
// looking at sibling items.
|
||||||
|
|
||||||
|
// append to the end if we won't find a better position:
|
||||||
|
nodePos = nodeSiblingsSize;
|
||||||
|
|
||||||
|
for ( int nextItemPos = posInModel + 1;
|
||||||
|
nextItemPos < modelSiblingsSize;
|
||||||
|
nextItemPos++ )
|
||||||
|
{
|
||||||
|
int nextNodePos = parent_node->FindChildByItem(modelSiblings[nextItemPos]);
|
||||||
|
if ( nextNodePos != wxNOT_FOUND )
|
||||||
|
{
|
||||||
|
nodePos = nextNodePos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_wx_model->IsContainer( item ))
|
if (m_wx_model->IsContainer( item ))
|
||||||
parent_node->InsertNode( new wxGtkTreeModelNode( parent_node, item, this ), itemPos );
|
parent_node->InsertNode( new wxGtkTreeModelNode( parent_node, item, this ), nodePos );
|
||||||
else
|
else
|
||||||
parent_node->InsertLeaf( item.GetID(), itemPos );
|
parent_node->InsertLeaf( item.GetID(), nodePos );
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleRefresh();
|
ScheduleRefresh();
|
||||||
|
Reference in New Issue
Block a user