Fix selection handling wxDataViewMainWindow::ItemDeleted().
The code to update m_selection was too aggressive in the virtual list case, when it simply cleared it, and broken for single-item selection in the general case. Fixed to recompute selection properly. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68622 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -388,6 +388,21 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns node corresponding to 'item' if its in m_nodes or NULL otherwise
|
||||||
|
wxDataViewTreeNode *FindItemAsNode(const wxDataViewItem& item) const
|
||||||
|
{
|
||||||
|
for ( wxDataViewTreeNodes::const_iterator i = m_nodes.begin();
|
||||||
|
i != m_nodes.end();
|
||||||
|
++i )
|
||||||
|
{
|
||||||
|
if( (*i)->GetItem() == item )
|
||||||
|
return *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxDataViewTreeNode *m_parent;
|
wxDataViewTreeNode *m_parent;
|
||||||
wxDataViewTreeNodes m_nodes;
|
wxDataViewTreeNodes m_nodes;
|
||||||
@@ -2006,60 +2021,107 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
|
|||||||
(wxDataViewVirtualListModel*) GetOwner()->GetModel();
|
(wxDataViewVirtualListModel*) GetOwner()->GetModel();
|
||||||
m_count = list_model->GetCount();
|
m_count = list_model->GetCount();
|
||||||
|
|
||||||
// TODO: why empty the entire selection?
|
if ( !m_selection.empty() )
|
||||||
m_selection.Empty();
|
{
|
||||||
|
const int row = GetRowByItem(item);
|
||||||
|
|
||||||
|
const size_t selCount = m_selection.size();
|
||||||
|
for ( size_t i = 0; i < selCount; i++ )
|
||||||
|
{
|
||||||
|
if ( m_selection[i] > (unsigned)row )
|
||||||
|
m_selection[i]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itemRow = m_selection.Index(row);
|
||||||
|
if ( itemRow != wxNOT_FOUND )
|
||||||
|
m_selection.RemoveAt(itemRow);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else // general case
|
else // general case
|
||||||
{
|
{
|
||||||
wxDataViewTreeNode * node = FindNode(parent);
|
wxDataViewTreeNode * node = FindNode(parent);
|
||||||
|
int itemPosInNode = node ? node->GetChildren().Index(item.GetID()) : wxNOT_FOUND;
|
||||||
|
|
||||||
// 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
|
||||||
// collapsed) item in a tree model. So it's not an error if we don't know
|
// collapsed) item in a tree model. So it's not an error if we don't know
|
||||||
// about this item, just return without doing anything then.
|
// about this item, just return without doing anything then.
|
||||||
if ( !node || node->GetChildren().Index(item.GetID()) == wxNOT_FOUND )
|
if ( !node || itemPosInNode == wxNOT_FOUND )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int sub = -1;
|
|
||||||
node->GetChildren().Remove( item.GetID() );
|
|
||||||
// Manipolate selection
|
|
||||||
if( m_selection.GetCount() > 1 )
|
|
||||||
{
|
|
||||||
m_selection.Empty();
|
|
||||||
}
|
|
||||||
bool isContainer = false;
|
bool isContainer = false;
|
||||||
wxDataViewTreeNodes nds = node->GetNodes();
|
wxDataViewTreeNode *itemNode = NULL;
|
||||||
|
|
||||||
|
const wxDataViewTreeNodes nds = node->GetNodes();
|
||||||
for (size_t i = 0; i < nds.GetCount(); i ++)
|
for (size_t i = 0; i < nds.GetCount(); i ++)
|
||||||
{
|
{
|
||||||
if (nds[i]->GetItem() == item)
|
if (nds[i]->GetItem() == item)
|
||||||
{
|
{
|
||||||
isContainer = true;
|
isContainer = true;
|
||||||
|
itemNode = nds[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete the item from wxDataViewTreeNode representation:
|
||||||
|
int itemsDeleted = 1;
|
||||||
|
node->GetChildren().Remove( item.GetID() );
|
||||||
|
|
||||||
if( isContainer )
|
if( isContainer )
|
||||||
{
|
{
|
||||||
wxDataViewTreeNode * n = NULL;
|
wxDataViewTreeNode *n = node->FindItemAsNode(item);
|
||||||
wxDataViewTreeNodes nodes = node->GetNodes();
|
|
||||||
int len = nodes.GetCount();
|
|
||||||
for( int i = 0; i < len; i ++)
|
|
||||||
{
|
|
||||||
if( nodes[i]->GetItem() == item )
|
|
||||||
{
|
|
||||||
n = nodes[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wxCHECK_MSG( n != NULL, false, "item not found" );
|
wxCHECK_MSG( n != NULL, false, "item not found" );
|
||||||
|
|
||||||
node->GetNodes().Remove( n );
|
node->GetNodes().Remove( n );
|
||||||
sub -= n->GetSubTreeCount();
|
itemsDeleted += n->GetSubTreeCount();
|
||||||
::DestroyTreeHelper(n);
|
::DestroyTreeHelper(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the row number invalid and get a new valid one when user call GetRowCount
|
// Make the row number invalid and get a new valid one when user call GetRowCount
|
||||||
m_count = -1;
|
m_count = -1;
|
||||||
node->ChangeSubTreeCount(sub);
|
node->ChangeSubTreeCount(-itemsDeleted);
|
||||||
|
|
||||||
|
// Update selection by removing 'item' and its entire children tree from the selection.
|
||||||
|
if ( !m_selection.empty() )
|
||||||
|
{
|
||||||
|
// we can't call GetRowByItem() on 'item', as it's already deleted, so compute it from
|
||||||
|
// the parent ('node') and position in its list of children
|
||||||
|
int itemRow;
|
||||||
|
if ( itemPosInNode == 0 )
|
||||||
|
{
|
||||||
|
// 1st child, row number is that of the parent node + 1
|
||||||
|
itemRow = GetRowByItem(node->GetItem()) + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// row number is that of the sibling above 'item' + its subtree if any + 1
|
||||||
|
const wxDataViewItem sibling = wxDataViewItem(node->GetChildren()[itemPosInNode - 1]);
|
||||||
|
const wxDataViewTreeNode *siblingNode = node->FindItemAsNode(sibling);
|
||||||
|
|
||||||
|
itemRow = GetRowByItem(sibling);
|
||||||
|
if ( siblingNode )
|
||||||
|
itemRow += siblingNode->GetSubTreeCount();
|
||||||
|
itemRow += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDataViewSelection newsel(wxDataViewSelectionCmp);
|
||||||
|
|
||||||
|
for ( wxDataViewSelection::const_iterator i = m_selection.begin();
|
||||||
|
i != m_selection.end();
|
||||||
|
++i )
|
||||||
|
{
|
||||||
|
const int s = *i;
|
||||||
|
if ( s < itemRow )
|
||||||
|
newsel.push_back(s);
|
||||||
|
else if ( s >= itemRow + itemsDeleted )
|
||||||
|
newsel.push_back(s - itemsDeleted);
|
||||||
|
// else: deleted item, remove from selection
|
||||||
|
}
|
||||||
|
|
||||||
|
m_selection = newsel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the current row to the last row if the current exceed the max row number
|
// Change the current row to the last row if the current exceed the max row number
|
||||||
|
Reference in New Issue
Block a user