Merge branch 'dvc-add-item-error' of https://github.com/thesiv/wxWidgets

Fix adding items to collapsed nodes of wxDataViewCtrl in wxGTK too.

See #22228.
This commit is contained in:
Vadim Zeitlin
2022-03-24 21:37:15 +01:00
3 changed files with 300 additions and 91 deletions

View File

@@ -959,7 +959,13 @@ private:
// Return false only if the event was vetoed by its handler. // Return false only if the event was vetoed by its handler.
bool SendExpanderEvent(wxEventType type, const wxDataViewItem& item); bool SendExpanderEvent(wxEventType type, const wxDataViewItem& item);
wxDataViewTreeNode * FindNode( const wxDataViewItem & item ); struct FindNodeResult
{
wxDataViewTreeNode * m_node;
bool m_subtreeRealized;
};
FindNodeResult FindNode( const wxDataViewItem & item );
wxDataViewColumn *FindColumnForEditing(const wxDataViewItem& item, wxDataViewCellMode mode) const; wxDataViewColumn *FindColumnForEditing(const wxDataViewItem& item, wxDataViewCellMode mode) const;
@@ -3089,8 +3095,15 @@ bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxData
// specific position (row) is unclear, so clear whole height cache // specific position (row) is unclear, so clear whole height cache
ClearRowHeightCache(); ClearRowHeightCache();
wxDataViewTreeNode *parentNode = FindNode(parent); const FindNodeResult findResult = FindNode(parent);
wxDataViewTreeNode *parentNode = findResult.m_node;
// If one of parents is not realized yet (has children but was never
// expanded). Return as nodes will be initialized in Expand().
if ( !findResult.m_subtreeRealized )
return true;
// The parent node was not found.
if ( !parentNode ) if ( !parentNode )
return false; return false;
@@ -3197,7 +3210,13 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
} }
else // general case else // general case
{ {
wxDataViewTreeNode *parentNode = FindNode(parent); const FindNodeResult findResult = FindNode(parent);
wxDataViewTreeNode *parentNode = findResult.m_node;
// One of parents of the parent node has children but was never
// expanded, so the tree was not built and we have nothing to delete.
if ( !findResult.m_subtreeRealized )
return true;
// Notice that it is possible that the item being deleted is not in the // Notice that it is possible that the item being deleted is not in the
// tree at all, for example we could be deleting a never shown (because // tree at all, for example we could be deleting a never shown (because
@@ -3316,7 +3335,10 @@ bool wxDataViewMainWindow::DoItemChanged(const wxDataViewItem & item, int view_c
// column but also falls back to other values for comparison. To ensure // column but also falls back to other values for comparison. To ensure
// consistency it is better to treat a value change as if it was an item // consistency it is better to treat a value change as if it was an item
// change. // change.
wxDataViewTreeNode* const node = FindNode(item); const FindNodeResult findResult = FindNode(item);
wxDataViewTreeNode* const node = findResult.m_node;
if ( !findResult.m_subtreeRealized )
return true;
wxCHECK_MSG( node, false, "invalid item" ); wxCHECK_MSG( node, false, "invalid item" );
node->PutInSortOrder(this); node->PutInSortOrder(this);
} }
@@ -4084,14 +4106,22 @@ void wxDataViewMainWindow::Collapse(unsigned int row)
} }
} }
wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item ) wxDataViewMainWindow::FindNodeResult
wxDataViewMainWindow::FindNode( const wxDataViewItem & item )
{ {
FindNodeResult result;
result.m_node = NULL;
result.m_subtreeRealized = true;
const wxDataViewModel * model = GetModel(); const wxDataViewModel * model = GetModel();
if( model == NULL ) if( model == NULL )
return NULL; return result;
if (!item.IsOk()) if (!item.IsOk())
return m_root; {
result.m_node = m_root;
return result;
}
// Compose the parent-chain for the item we are looking for // Compose the parent-chain for the item we are looking for
wxVector<wxDataViewItem> parentChain; wxVector<wxDataViewItem> parentChain;
@@ -4112,9 +4142,9 @@ wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item
if( node->GetChildNodes().empty() ) if( node->GetChildNodes().empty() )
{ {
// Even though the item is a container, it doesn't have any // Even though the item is a container, it doesn't have any
// child nodes in the control's representation yet. We have // child nodes in the control's representation yet.
// to realize its subtree now. result.m_subtreeRealized = false;
::BuildTreeHelper(this, model, node->GetItem(), node); return result;
} }
const wxDataViewTreeNodes& nodes = node->GetChildNodes(); const wxDataViewTreeNodes& nodes = node->GetChildNodes();
@@ -4126,7 +4156,10 @@ wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item
if (currentNode->GetItem() == parentChain[iter]) if (currentNode->GetItem() == parentChain[iter])
{ {
if (currentNode->GetItem() == item) if (currentNode->GetItem() == item)
return currentNode; {
result.m_node = currentNode;
return result;
}
node = currentNode; node = currentNode;
found = true; found = true;
@@ -4134,15 +4167,15 @@ wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item
} }
} }
if (!found) if (!found)
return NULL; return result;
} }
else else
return NULL; return result;
if ( !iter ) if ( !iter )
break; break;
} }
return NULL; return result;
} }
void wxDataViewMainWindow::HitTest( const wxPoint & point, wxDataViewItem & item, void wxDataViewMainWindow::HitTest( const wxPoint & point, wxDataViewItem & item,

View File

@@ -275,11 +275,22 @@ public:
void OnInternalIdle(); void OnInternalIdle();
enum wxFindNodeMode
{
// return NULL from FindNode() of a subtree was not realized
wxFIND_NODE_RETURN_IF_SUBTREE_NOT_REALIZED,
// call BuildBranch() from FindNode() to realize a subtree
wxFIND_NODE_BUILD_SUBTREE,
};
protected: protected:
void InitTree(); void InitTree();
void ScheduleRefresh(); void ScheduleRefresh();
wxGtkTreeModelNode *FindNode( const wxDataViewItem &item ); wxGtkTreeModelNode *FindNode( const wxDataViewItem &item,
wxFindNodeMode mode =
wxFIND_NODE_RETURN_IF_SUBTREE_NOT_REALIZED );
wxGtkTreeModelNode *FindNode( GtkTreeIter *iter ); wxGtkTreeModelNode *FindNode( GtkTreeIter *iter );
wxGtkTreeModelNode *FindParentNode( const wxDataViewItem &item ); wxGtkTreeModelNode *FindParentNode( const wxDataViewItem &item );
wxGtkTreeModelNode *FindParentNode( GtkTreeIter *iter ); wxGtkTreeModelNode *FindParentNode( GtkTreeIter *iter );
@@ -3959,7 +3970,7 @@ bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDa
{ {
if (!m_wx_model->IsVirtualListModel()) if (!m_wx_model->IsVirtualListModel())
{ {
wxGtkTreeModelNode *parent_node = FindNode( parent ); wxGtkTreeModelNode *parent_node = FindNode( parent, wxFIND_NODE_BUILD_SUBTREE );
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");
@@ -3973,6 +3984,17 @@ bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDa
const wxGtkTreeModelChildren& nodeSiblings = parent_node->GetChildren(); const wxGtkTreeModelChildren& nodeSiblings = parent_node->GetChildren();
const int nodeSiblingsSize = nodeSiblings.size(); const int nodeSiblingsSize = nodeSiblings.size();
if ( nodeSiblingsSize == 0 )
{
BuildBranch( parent_node );
return true;
}
else
{
if ( parent_node->FindChildByItem(item) != wxNOT_FOUND )
return true;
}
int nodePos = 0; int nodePos = 0;
if ( posInModel == modelSiblingsSize - 1 ) if ( posInModel == modelSiblingsSize - 1 )
@@ -4398,10 +4420,13 @@ int wxDataViewCtrlInternal::GetIndexOf( const wxDataViewItem &parent, const wxDa
} }
static wxGtkTreeModelNode* wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item,
wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item ) wxFindNodeMode mode )
{ {
if( model == NULL ) if ( !item.IsOk() )
return m_root;
if( m_wx_model == NULL )
return NULL; return NULL;
ItemList list; ItemList list;
@@ -4412,14 +4437,25 @@ wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *tr
{ {
wxDataViewItem * pItem = new wxDataViewItem( it ); wxDataViewItem * pItem = new wxDataViewItem( it );
list.Insert( pItem ); list.Insert( pItem );
it = model->GetParent( it ); it = m_wx_model->GetParent( it );
} }
wxGtkTreeModelNode * node = treeNode; wxGtkTreeModelNode * node = m_root;
for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() ) for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
{ {
if( node && node->GetNodes().GetCount() != 0 ) if( node && node->GetNodes().GetCount() != 0 )
{ {
switch ( mode )
{
case wxFIND_NODE_RETURN_IF_SUBTREE_NOT_REALIZED:
// Do nothing and a subtree will not built.
break;
case wxFIND_NODE_BUILD_SUBTREE:
BuildBranch( node );
break;
}
int len = node->GetNodes().GetCount(); int len = node->GetNodes().GetCount();
wxGtkTreeModelNodes &nodes = node->GetNodes(); wxGtkTreeModelNodes &nodes = node->GetNodes();
int j = 0; int j = 0;
@@ -4450,10 +4486,9 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
return m_root; return m_root;
wxDataViewItem item( (void*) iter->user_data ); wxDataViewItem item( (void*) iter->user_data );
if (!item.IsOk())
return m_root;
wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item ); const wxFindNodeMode mode = wxFIND_NODE_RETURN_IF_SUBTREE_NOT_REALIZED;
wxGtkTreeModelNode *result = FindNode( item, mode );
/* /*
if (!result) if (!result)
@@ -4468,26 +4503,6 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
return result; return result;
} }
wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item )
{
if (!item.IsOk())
return m_root;
wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
/*
if (!result)
{
wxLogDebug( "Not found %p", item.GetID() );
char *crash = NULL;
*crash = 0;
}
// TODO: remove this code
*/
return result;
}
static wxGtkTreeModelNode* static wxGtkTreeModelNode*
wxDataViewCtrlInternal_FindParentNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item ) wxDataViewCtrlInternal_FindParentNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
{ {

View File

@@ -102,6 +102,10 @@ public:
// |-- wxTEST_ITEM_CHILD // |-- wxTEST_ITEM_CHILD
// | // |
// |-- wxTEST_ITEM_GRANDCHILD // |-- wxTEST_ITEM_GRANDCHILD
// | |
// | |-- wxTEST_ITEM_LEAF
// | |
// | |-- wxTEST_ITEM_LEAF_HIDDEN
// | // |
// |-- wxTEST_ITEM_GRANDCHILD_HIDDEN // |-- wxTEST_ITEM_GRANDCHILD_HIDDEN
// //
@@ -111,15 +115,19 @@ public:
wxTEST_ITEM_ROOT, wxTEST_ITEM_ROOT,
wxTEST_ITEM_CHILD, wxTEST_ITEM_CHILD,
wxTEST_ITEM_GRANDCHILD, wxTEST_ITEM_GRANDCHILD,
wxTEST_ITEM_GRANDCHILD_HIDDEN, wxTEST_ITEM_LEAF,
wxTEST_ITEM_LEAF_HIDDEN,
wxTEST_ITEM_GRANDCHILD_HIDDEN
}; };
DataViewCtrlTestModel() DataViewCtrlTestModel()
: m_root(wxTEST_ITEM_ROOT), : m_root(wxTEST_ITEM_ROOT),
m_child(wxTEST_ITEM_CHILD), m_child(wxTEST_ITEM_CHILD),
m_grandChild(wxTEST_ITEM_GRANDCHILD), m_grandChild(wxTEST_ITEM_GRANDCHILD),
m_grandChildHidden(wxTEST_ITEM_GRANDCHILD_HIDDEN), m_leaf(wxTEST_ITEM_LEAF),
m_secondGrandchildVisible(false) m_leafHidden(wxTEST_ITEM_LEAF_HIDDEN),
m_grandchildHidden(wxTEST_ITEM_GRANDCHILD_HIDDEN),
m_allItemsVisible(false)
{ {
} }
@@ -139,8 +147,14 @@ public:
case wxTEST_ITEM_GRANDCHILD: case wxTEST_ITEM_GRANDCHILD:
return wxDataViewItem(const_cast<wxTestItem*>(&m_grandChild)); return wxDataViewItem(const_cast<wxTestItem*>(&m_grandChild));
case wxTEST_ITEM_LEAF:
return wxDataViewItem(const_cast<wxTestItem*>(&m_leaf));
case wxTEST_ITEM_LEAF_HIDDEN:
return wxDataViewItem(const_cast<wxTestItem*>(&m_leafHidden));
case wxTEST_ITEM_GRANDCHILD_HIDDEN: case wxTEST_ITEM_GRANDCHILD_HIDDEN:
return wxDataViewItem(const_cast<wxTestItem*>(&m_grandChildHidden)); return wxDataViewItem(const_cast<wxTestItem*>(&m_grandchildHidden));
} }
return wxDataViewItem(); return wxDataViewItem();
} }
@@ -177,6 +191,14 @@ public:
variant = "grand child"; variant = "grand child";
break; break;
case wxTEST_ITEM_LEAF:
variant = "leaf";
break;
case wxTEST_ITEM_LEAF_HIDDEN:
variant = "initially hidden leaf";
break;
case wxTEST_ITEM_GRANDCHILD_HIDDEN: case wxTEST_ITEM_GRANDCHILD_HIDDEN:
variant = "initially hidden"; variant = "initially hidden";
break; break;
@@ -213,6 +235,10 @@ public:
case wxTEST_ITEM_GRANDCHILD: case wxTEST_ITEM_GRANDCHILD:
case wxTEST_ITEM_GRANDCHILD_HIDDEN: case wxTEST_ITEM_GRANDCHILD_HIDDEN:
return GetDataViewItem(m_child); return GetDataViewItem(m_child);
case wxTEST_ITEM_LEAF:
case wxTEST_ITEM_LEAF_HIDDEN:
return GetDataViewItem(m_grandChild);
} }
return wxDataViewItem(); return wxDataViewItem();
} }
@@ -224,9 +250,11 @@ public:
case wxTEST_ITEM_NULL: case wxTEST_ITEM_NULL:
case wxTEST_ITEM_ROOT: case wxTEST_ITEM_ROOT:
case wxTEST_ITEM_CHILD: case wxTEST_ITEM_CHILD:
case wxTEST_ITEM_GRANDCHILD:
return true; return true;
case wxTEST_ITEM_GRANDCHILD: case wxTEST_ITEM_LEAF:
case wxTEST_ITEM_LEAF_HIDDEN:
case wxTEST_ITEM_GRANDCHILD_HIDDEN: case wxTEST_ITEM_GRANDCHILD_HIDDEN:
return false; return false;
} }
@@ -249,15 +277,27 @@ public:
case wxTEST_ITEM_CHILD: case wxTEST_ITEM_CHILD:
children.push_back(GetDataViewItem(m_grandChild)); children.push_back(GetDataViewItem(m_grandChild));
if ( m_secondGrandchildVisible ) if ( m_allItemsVisible )
{ {
children.push_back(GetDataViewItem(m_grandChildHidden)); children.push_back(GetDataViewItem(m_grandchildHidden));
return 2; return 2;
} }
return 1; return 1;
case wxTEST_ITEM_GRANDCHILD: case wxTEST_ITEM_GRANDCHILD:
children.push_back(GetDataViewItem(m_leaf));
if ( m_allItemsVisible )
{
children.push_back(GetDataViewItem(m_leafHidden));
return 2;
}
return 1;
case wxTEST_ITEM_LEAF:
case wxTEST_ITEM_LEAF_HIDDEN:
case wxTEST_ITEM_GRANDCHILD_HIDDEN: case wxTEST_ITEM_GRANDCHILD_HIDDEN:
FAIL( "The item is not a container" ); FAIL( "The item is not a container" );
return 0; return 0;
@@ -265,10 +305,34 @@ public:
return 0; return 0;
} }
void ShowSecondGrandChild() enum wxItemsOrder
{ {
m_secondGrandchildVisible = true; wxORDER_LEAF_THEN_GRANCHILD,
ItemAdded(GetDataViewItem(m_child), GetDataViewItem(m_grandChildHidden)); wxORDER_GRANCHILD_THEN_LEAF
};
void ShowChildren(wxItemsOrder order)
{
m_allItemsVisible = true;
switch ( order )
{
case wxORDER_LEAF_THEN_GRANCHILD:
ItemAdded(GetDataViewItem(m_grandChild), GetDataViewItem(m_leafHidden));
ItemAdded(GetDataViewItem(m_child), GetDataViewItem(m_grandchildHidden));
break;
case wxORDER_GRANCHILD_THEN_LEAF:
ItemAdded(GetDataViewItem(m_child), GetDataViewItem(m_grandchildHidden));
ItemAdded(GetDataViewItem(m_grandChild), GetDataViewItem(m_leafHidden));
break;
}
}
void HideChildren()
{
m_allItemsVisible = false;
ItemDeleted(GetDataViewItem(m_grandChild), GetDataViewItem(m_leafHidden));
ItemDeleted(GetDataViewItem(m_child), GetDataViewItem(m_grandchildHidden));
} }
private: private:
@@ -282,10 +346,12 @@ private:
wxTestItem m_root; wxTestItem m_root;
wxTestItem m_child; wxTestItem m_child;
wxTestItem m_grandChild; wxTestItem m_grandChild;
wxTestItem m_grandChildHidden; wxTestItem m_leaf;
wxTestItem m_leafHidden;
wxTestItem m_grandchildHidden;
// Whether wxTEST_ITEM_GRANDCHILD_HIDDEN item should be visible or not. // Whether wxTEST_ITEM_GRANDCHILD_HIDDEN item should be visible or not.
bool m_secondGrandchildVisible; bool m_allItemsVisible;
}; };
@@ -296,6 +362,51 @@ public:
~DataViewCtrlWithCustomModelTestCase(); ~DataViewCtrlWithCustomModelTestCase();
protected: protected:
enum wxItemExistence
{
wxITEM_APPEAR,
wxITEM_DISAPPEAR
};
void UpdateAndWaitForItem(const wxDataViewItem& item, wxItemExistence existence)
{
m_dvc->Refresh();
m_dvc->Update();
#ifdef __WXGTK__
// Unfortunately it's not enough to call wxYield() once, so wait up to
// 0.5 sec.
wxStopWatch sw;
while ( true )
{
wxYield();
const bool isItemRectEmpty = m_dvc->GetItemRect(item).IsEmpty();
switch ( existence )
{
case wxITEM_APPEAR:
if ( !isItemRectEmpty )
return;
break;
case wxITEM_DISAPPEAR:
if ( isItemRectEmpty )
return;
break;
}
if ( sw.Time() > 500 )
{
WARN("Timed out waiting for wxDataViewCtrl");
break;
}
}
#else // !__WXGTK__
wxUnusedVar(item);
wxUnusedVar(existence);
#endif // __WXGTK__
}
// The dataview control. // The dataview control.
wxDataViewCtrl *m_dvc; wxDataViewCtrl *m_dvc;
@@ -303,7 +414,12 @@ protected:
DataViewCtrlTestModel *m_model; DataViewCtrlTestModel *m_model;
// Its items. // Its items.
wxDataViewItem m_root, m_child, m_grandchild, m_grandchildHidden; wxDataViewItem m_root,
m_child,
m_grandchild,
m_leaf,
m_leafHidden,
m_grandchildHidden;
wxDECLARE_NO_COPY_CLASS(DataViewCtrlWithCustomModelTestCase); wxDECLARE_NO_COPY_CLASS(DataViewCtrlWithCustomModelTestCase);
}; };
@@ -384,6 +500,10 @@ DataViewCtrlWithCustomModelTestCase::DataViewCtrlWithCustomModelTestCase()
m_child = m_model->GetDataViewItem(DataViewCtrlTestModel::wxTEST_ITEM_CHILD); m_child = m_model->GetDataViewItem(DataViewCtrlTestModel::wxTEST_ITEM_CHILD);
m_grandchild = m_grandchild =
m_model->GetDataViewItem(DataViewCtrlTestModel::wxTEST_ITEM_GRANDCHILD); m_model->GetDataViewItem(DataViewCtrlTestModel::wxTEST_ITEM_GRANDCHILD);
m_leaf =
m_model->GetDataViewItem(DataViewCtrlTestModel::wxTEST_ITEM_LEAF);
m_leafHidden =
m_model->GetDataViewItem(DataViewCtrlTestModel::wxTEST_ITEM_LEAF_HIDDEN);
m_grandchildHidden = m_grandchildHidden =
m_model->GetDataViewItem(DataViewCtrlTestModel::wxTEST_ITEM_GRANDCHILD_HIDDEN); m_model->GetDataViewItem(DataViewCtrlTestModel::wxTEST_ITEM_GRANDCHILD_HIDDEN);
@@ -566,53 +686,94 @@ TEST_CASE_METHOD(DataViewCtrlWithCustomModelTestCase,
wxYield(); wxYield();
#endif // __WXGTK__ #endif // __WXGTK__
SECTION( "Was Expanded" ) // Unfortunately we can't combine test options with SECTION() so use
// the additional enum variable.
enum
{ {
wxOPTIONS_EXPAND_ADD_LEAF_THEN_GRANCHILD,
wxOPTIONS_DONT_EXPAND_ADD_LEAF_THEN_GRANCHILD,
wxOPTIONS_EXPAND_ADD_GRANCHILD_THEN_LEAF,
wxOPTIONS_DONT_EXPAND_ADD_GRANCHILD_THEN_LEAF
} options;
SECTION( "Was Expanded, Add The Leaf Then The Grandchild" )
{
options = wxOPTIONS_EXPAND_ADD_LEAF_THEN_GRANCHILD;
}
SECTION( "Was Not Expanded, Add The Leaf Then The Grandchild" )
{
options = wxOPTIONS_DONT_EXPAND_ADD_LEAF_THEN_GRANCHILD;
}
SECTION( "Was Expanded, Add The Grandchild Then The Leaf" )
{
options = wxOPTIONS_EXPAND_ADD_GRANCHILD_THEN_LEAF;
}
SECTION( "Was Not Expanded, Add The Grandchild Then The Leaf" )
{
options = wxOPTIONS_DONT_EXPAND_ADD_GRANCHILD_THEN_LEAF;
}
switch ( options )
{
case wxOPTIONS_EXPAND_ADD_LEAF_THEN_GRANCHILD:
case wxOPTIONS_EXPAND_ADD_GRANCHILD_THEN_LEAF:
CHECK( m_dvc->GetItemRect(m_grandchild).IsEmpty() ); CHECK( m_dvc->GetItemRect(m_grandchild).IsEmpty() );
CHECK( m_dvc->GetItemRect(m_leafHidden).IsEmpty() );
CHECK( m_dvc->GetItemRect(m_grandchildHidden).IsEmpty() ); CHECK( m_dvc->GetItemRect(m_grandchildHidden).IsEmpty() );
m_dvc->Expand(m_child); m_dvc->Expand(m_child);
m_dvc->Expand(m_grandchild);
#ifdef __WXGTK__ UpdateAndWaitForItem(m_grandchild, wxITEM_APPEAR);
wxYield();
#endif // __WXGTK__
CHECK( !m_dvc->GetItemRect(m_grandchild).IsEmpty() ); CHECK( !m_dvc->GetItemRect(m_grandchild).IsEmpty() );
CHECK( !m_dvc->GetItemRect(m_leaf).IsEmpty() );
CHECK( m_dvc->GetItemRect(m_leafHidden).IsEmpty() );
CHECK( m_dvc->GetItemRect(m_grandchildHidden).IsEmpty() ); CHECK( m_dvc->GetItemRect(m_grandchildHidden).IsEmpty() );
m_dvc->Collapse(m_grandchild);
m_dvc->Collapse(m_child); m_dvc->Collapse(m_child);
} break;
SECTION( "Was Not Expanded" ) case wxOPTIONS_DONT_EXPAND_ADD_LEAF_THEN_GRANCHILD:
{ case wxOPTIONS_DONT_EXPAND_ADD_GRANCHILD_THEN_LEAF:
// Do nothing. // Do nothing.
break;
} }
// Check wxDataViewModel::ItemAdded(). // Check wxDataViewModel::ItemAdded().
m_model->ShowSecondGrandChild(); switch ( options )
m_dvc->Expand(m_child);
m_dvc->Refresh();
m_dvc->Update();
CHECK( m_dvc->IsExpanded(m_child) );
#ifdef __WXGTK__
// Unfortunately it's not enough to call wxYield() once, so wait up to
// 0.5 sec.
wxStopWatch sw;
while ( m_dvc->GetItemRect(m_grandchild).IsEmpty() )
{ {
if ( sw.Time() > 500 ) case wxOPTIONS_EXPAND_ADD_LEAF_THEN_GRANCHILD:
{ case wxOPTIONS_DONT_EXPAND_ADD_LEAF_THEN_GRANCHILD:
WARN("Timed out waiting for wxDataViewCtrl"); m_model->ShowChildren(DataViewCtrlTestModel::wxORDER_LEAF_THEN_GRANCHILD);
break;
case wxOPTIONS_EXPAND_ADD_GRANCHILD_THEN_LEAF:
case wxOPTIONS_DONT_EXPAND_ADD_GRANCHILD_THEN_LEAF:
m_model->ShowChildren(DataViewCtrlTestModel::wxORDER_GRANCHILD_THEN_LEAF);
break; break;
} }
wxYield();
}
#endif // __WXGTK__
m_dvc->Expand(m_child);
m_dvc->Expand(m_grandchild);
UpdateAndWaitForItem(m_leaf, wxITEM_APPEAR);
CHECK( m_dvc->IsExpanded(m_child) );
CHECK( m_dvc->IsExpanded(m_grandchild) );
CHECK( !m_dvc->GetItemRect(m_grandchild).IsEmpty() ); CHECK( !m_dvc->GetItemRect(m_grandchild).IsEmpty() );
CHECK( !m_dvc->GetItemRect(m_leaf).IsEmpty() );
CHECK( !m_dvc->GetItemRect(m_leafHidden).IsEmpty() );
CHECK( !m_dvc->GetItemRect(m_grandchildHidden).IsEmpty() ); CHECK( !m_dvc->GetItemRect(m_grandchildHidden).IsEmpty() );
m_model->HideChildren();
UpdateAndWaitForItem(m_leafHidden, wxITEM_DISAPPEAR);
CHECK( m_dvc->GetItemRect(m_leafHidden).IsEmpty() );
// Check that the problem with nodes duplication in ItemAdded() fixed.
CHECK( m_dvc->GetItemRect(m_grandchildHidden).IsEmpty() );
} }
TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase,