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:
|
||||
wxDataViewTreeNode *m_parent;
|
||||
wxDataViewTreeNodes m_nodes;
|
||||
@@ -2006,60 +2021,107 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
|
||||
(wxDataViewVirtualListModel*) GetOwner()->GetModel();
|
||||
m_count = list_model->GetCount();
|
||||
|
||||
// TODO: why empty the entire selection?
|
||||
m_selection.Empty();
|
||||
if ( !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
|
||||
{
|
||||
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
|
||||
// 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
|
||||
// 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;
|
||||
|
||||
int sub = -1;
|
||||
node->GetChildren().Remove( item.GetID() );
|
||||
// Manipolate selection
|
||||
if( m_selection.GetCount() > 1 )
|
||||
{
|
||||
m_selection.Empty();
|
||||
}
|
||||
bool isContainer = false;
|
||||
wxDataViewTreeNodes nds = node->GetNodes();
|
||||
wxDataViewTreeNode *itemNode = NULL;
|
||||
|
||||
const wxDataViewTreeNodes nds = node->GetNodes();
|
||||
for (size_t i = 0; i < nds.GetCount(); i ++)
|
||||
{
|
||||
if (nds[i]->GetItem() == item)
|
||||
{
|
||||
isContainer = true;
|
||||
itemNode = nds[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the item from wxDataViewTreeNode representation:
|
||||
int itemsDeleted = 1;
|
||||
node->GetChildren().Remove( item.GetID() );
|
||||
|
||||
if( isContainer )
|
||||
{
|
||||
wxDataViewTreeNode * n = NULL;
|
||||
wxDataViewTreeNodes nodes = node->GetNodes();
|
||||
int len = nodes.GetCount();
|
||||
for( int i = 0; i < len; i ++)
|
||||
{
|
||||
if( nodes[i]->GetItem() == item )
|
||||
{
|
||||
n = nodes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
wxDataViewTreeNode *n = node->FindItemAsNode(item);
|
||||
|
||||
wxCHECK_MSG( n != NULL, false, "item not found" );
|
||||
|
||||
node->GetNodes().Remove( n );
|
||||
sub -= n->GetSubTreeCount();
|
||||
itemsDeleted += n->GetSubTreeCount();
|
||||
::DestroyTreeHelper(n);
|
||||
}
|
||||
|
||||
// Make the row number invalid and get a new valid one when user call GetRowCount
|
||||
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
|
||||
|
Reference in New Issue
Block a user