vista tree crash fix

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52597 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Benjamin Williams
2008-03-17 22:05:01 +00:00
parent 2a6585b851
commit 396f85bac5

View File

@@ -72,19 +72,38 @@ typedef struct tagNMTVITEMCHANGE
#endif #endif
// this global variable is used on vista systems for preventing unwanted // this helper class is used on vista systems for preventing unwanted
// item state changes in the vista tree control. It is only used in // item state changes in the vista tree control. It is only effective in
// multi-select mode on vista systems. // multi-select mode on vista systems.
static HTREEITEM gs_unlockItem = NULL; // The vista tree control includes some new code that originally broke the
// multi-selection tree, causing seemingly spurious item selection state changes
// during Shift or Ctrl-click item selection. (To witness the original broken
// behavior, simply make IsLocked() below always return false). This problem was
// solved by using the following class to 'unlock' an item's selection state.
class TreeItemUnlocker class TreeItemUnlocker
{ {
public: public:
TreeItemUnlocker(HTREEITEM item) { gs_unlockItem = item; } // unlock a single item
~TreeItemUnlocker() { gs_unlockItem = NULL; } TreeItemUnlocker(HTREEITEM item) { ms_unlockedItem = item; }
// unlock all items, don't use unless absolutely necessary
TreeItemUnlocker() { ms_unlockedItem = (HTREEITEM)-1; }
// lock everything back
~TreeItemUnlocker() { ms_unlockedItem = NULL; }
// check if the item state is currently locked
static bool IsLocked(HTREEITEM item)
{ return ms_unlockedItem != (HTREEITEM)-1 && item != ms_unlockedItem; }
private:
static HTREEITEM ms_unlockedItem;
}; };
HTREEITEM TreeItemUnlocker::ms_unlockedItem = NULL;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// private functions // private functions
@@ -1586,6 +1605,10 @@ wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent,
void wxTreeCtrl::Delete(const wxTreeItemId& item) void wxTreeCtrl::Delete(const wxTreeItemId& item)
{ {
// unlock tree selections on vista, without this the
// tree ctrl will eventually crash after item deletion
TreeItemUnlocker unlock_all;
if ( !TreeView_DeleteItem(GetHwnd(), HITEM(item)) ) if ( !TreeView_DeleteItem(GetHwnd(), HITEM(item)) )
{ {
wxLogLastError(wxT("TreeView_DeleteItem")); wxLogLastError(wxT("TreeView_DeleteItem"));
@@ -1595,6 +1618,9 @@ void wxTreeCtrl::Delete(const wxTreeItemId& item)
// delete all children (but don't delete the item itself) // delete all children (but don't delete the item itself)
void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item) void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item)
{ {
// unlock tree selections on vista for the duration of this call
TreeItemUnlocker unlock_all;
wxTreeItemIdValue cookie; wxTreeItemIdValue cookie;
wxArrayTreeItemIds children; wxArrayTreeItemIds children;
@@ -1618,6 +1644,9 @@ void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item)
void wxTreeCtrl::DeleteAllItems() void wxTreeCtrl::DeleteAllItems()
{ {
// unlock tree selections on vista for the duration of this call
TreeItemUnlocker unlock_all;
// delete the "virtual" root item. // delete the "virtual" root item.
if ( GET_VIRTUAL_ROOT() ) if ( GET_VIRTUAL_ROOT() )
{ {
@@ -2646,6 +2675,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
// that can be used to regulate this incorrect behavior. The // that can be used to regulate this incorrect behavior. The
// following messages will allow only the unlocked item's selection // following messages will allow only the unlocked item's selection
// state to change // state to change
case TVN_ITEMCHANGINGA: case TVN_ITEMCHANGINGA:
case TVN_ITEMCHANGINGW: case TVN_ITEMCHANGINGW:
{ {
@@ -2654,7 +2684,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{ {
// get info about the item about to be changed // get info about the item about to be changed
NMTVITEMCHANGE* info = (NMTVITEMCHANGE*)lParam; NMTVITEMCHANGE* info = (NMTVITEMCHANGE*)lParam;
if (info->hItem != gs_unlockItem) if (TreeItemUnlocker::IsLocked(info->hItem))
{ {
// item's state is locked, don't allow the change // item's state is locked, don't allow the change
// returning 1 will disallow the change // returning 1 will disallow the change