Don't use global variables for generic wxDataViewCtrl sorting.

Improve code quality and also fix the following issue: when 2 or more
wxDataViewCtrl were frozen, only the first one was sorted on thaw as g_column
was erased by the first wxDataViewCtrl to be sorted and so preventing the
other one from being sorted.

Closes https://github.com/wxWidgets/wxWidgets/pull/63
This commit is contained in:
ArnaudD-FR
2015-08-06 13:54:20 +02:00
committed by Vadim Zeitlin
parent 3b573aa4d3
commit 09e8876c0c

View File

@@ -80,7 +80,6 @@ static const int EXPANDER_OFFSET = 1;
// Below is the compare stuff.
// For the generic implementation, both the leaf nodes and the nodes are sorted for
// fast search when needed
static wxDataViewModel* g_model;
// The column is either the index of the column to be used for sorting or one
// of the special values in this enum:
@@ -96,9 +95,6 @@ enum
SortColumn_Default = -1
};
static int g_column = SortColumn_None;
static bool g_asending = true;
// ----------------------------------------------------------------------------
// helper functions
// ----------------------------------------------------------------------------
@@ -407,17 +403,18 @@ public:
// wxDataViewTreeNode
//-----------------------------------------------------------------------------
class wxDataViewMainWindow;
class wxDataViewTreeNode;
WX_DEFINE_ARRAY( wxDataViewTreeNode *, wxDataViewTreeNodes );
int LINKAGEMODE wxGenericTreeModelNodeCmp( wxDataViewTreeNode ** node1,
wxDataViewTreeNode ** node2);
class wxDataViewTreeNode
{
public:
wxDataViewTreeNode(wxDataViewTreeNode *parent, const wxDataViewItem& item)
: m_parent(parent),
wxDataViewTreeNode(wxDataViewMainWindow *window,
wxDataViewTreeNode *parent,
const wxDataViewItem& item)
: m_window(window),
m_parent(parent),
m_item(item),
m_branchData(NULL)
{
@@ -439,9 +436,9 @@ public:
}
}
static wxDataViewTreeNode* CreateRootNode()
static wxDataViewTreeNode* CreateRootNode(wxDataViewMainWindow *w)
{
wxDataViewTreeNode *n = new wxDataViewTreeNode(NULL, wxDataViewItem());
wxDataViewTreeNode *n = new wxDataViewTreeNode(w, NULL, wxDataViewItem());
n->m_branchData = new BranchNodeData;
n->m_branchData->open = true;
return n;
@@ -455,17 +452,7 @@ public:
return m_branchData->children;
}
void InsertChild(wxDataViewTreeNode *node, unsigned index)
{
if ( !m_branchData )
m_branchData = new BranchNodeData;
m_branchData->children.Insert(node, index);
// TODO: insert into sorted array directly in O(log n) instead of resorting in O(n log n)
if (g_column >= -1)
m_branchData->children.Sort( &wxGenericTreeModelNodeCmp );
}
void InsertChild(wxDataViewTreeNode *node, unsigned index);
void RemoveChild(wxDataViewTreeNode *node)
{
@@ -580,27 +567,10 @@ public:
m_parent->ChangeSubTreeCount(num);
}
void Resort()
{
if ( !m_branchData )
return;
if (g_column >= -1)
{
wxDataViewTreeNodes& nodes = m_branchData->children;
nodes.Sort( &wxGenericTreeModelNodeCmp );
int len = nodes.GetCount();
for (int i = 0; i < len; i ++)
{
if ( nodes[i]->HasChildren() )
nodes[i]->Resort();
}
}
}
void Resort();
private:
wxDataViewMainWindow *m_window;
wxDataViewTreeNode *m_parent;
// Corresponding model item.
@@ -634,12 +604,6 @@ private:
};
int LINKAGEMODE wxGenericTreeModelNodeCmp( wxDataViewTreeNode ** node1,
wxDataViewTreeNode ** node2)
{
return g_model->Compare( (*node1)->GetItem(), (*node2)->GetItem(), g_column, g_asending );
}
//-----------------------------------------------------------------------------
// wxDataViewMainWindow
@@ -680,10 +644,10 @@ public:
// SortPrepare() was called -- and ignored -- while we were frozen.
virtual void DoThaw()
{
if ( g_column == SortColumn_OnThaw )
if ( m_sortColumn == SortColumn_OnThaw )
{
Resort();
g_column = SortColumn_None;
m_sortColumn = SortColumn_None;
}
wxWindow::DoThaw();
@@ -691,23 +655,23 @@ public:
void SortPrepare()
{
g_model = GetModel();
wxDataViewModel* model = GetModel();
wxDataViewColumn* col = GetOwner()->GetSortingColumn();
if( !col )
{
if (g_model->HasDefaultCompare())
if (model->HasDefaultCompare())
{
// See below for the explanation of IsFrozen() test.
if ( IsFrozen() )
g_column = SortColumn_OnThaw;
m_sortColumn = SortColumn_OnThaw;
else
g_column = SortColumn_Default;
m_sortColumn = SortColumn_Default;
}
else
g_column = SortColumn_None;
m_sortColumn = SortColumn_None;
g_asending = true;
m_sortAscending = true;
return;
}
@@ -716,12 +680,12 @@ public:
// them all at once when the window is finally thawed, see above.
if ( IsFrozen() )
{
g_column = SortColumn_OnThaw;
m_sortColumn = SortColumn_OnThaw;
return;
}
g_column = col->GetModelColumn();
g_asending = col->IsSortOrderAscending();
m_sortColumn = col->GetModelColumn();
m_sortAscending = col->IsSortOrderAscending();
}
void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
@@ -844,6 +808,9 @@ public:
void StartEditing(const wxDataViewItem& item, const wxDataViewColumn* col);
void FinishEditing();
int GetSortColumn() const { return m_sortColumn; }
bool IsAscendingSort() const { return m_sortAscending; }
private:
void InvalidateCount() { m_count = -1; }
void UpdateCount(int count)
@@ -912,6 +879,10 @@ private:
// This is the tree node under the cursor
wxDataViewTreeNode * m_underMouse;
// sorted column + extra flags
int m_sortColumn;
bool m_sortAscending;
// The control used for editing or NULL.
wxWeakRef<wxWindow> m_editorCtrl;
@@ -1469,13 +1440,74 @@ void wxDataViewRenameTimer::Notify()
m_owner->OnRenameTimer();
}
// ----------------------------------------------------------------------------
// wxDataViewTreeNode
// ----------------------------------------------------------------------------
// Used by wxGenericTreeModelNodeCmp sort callback only.
//
// This is not thread safe but it should be fine if all events are handled in
// one thread.
static wxDataViewModel* g_model;
static int g_column;
static bool g_asending;
int LINKAGEMODE wxGenericTreeModelNodeCmp(wxDataViewTreeNode ** node1,
wxDataViewTreeNode ** node2)
{
return g_model->Compare((*node1)->GetItem(), (*node2)->GetItem(), g_column, g_asending);
}
void wxDataViewTreeNode::InsertChild(wxDataViewTreeNode *node, unsigned index)
{
if (!m_branchData)
m_branchData = new BranchNodeData;
m_branchData->children.Insert(node, index);
// TODO: insert into sorted array directly in O(log n) instead of resorting in O(n log n)
if ((g_column = m_window->GetSortColumn()) >= -1)
{
g_model = m_window->GetModel();
g_asending = m_window->IsAscendingSort();
m_branchData->children.Sort(&wxGenericTreeModelNodeCmp);
}
}
void wxDataViewTreeNode::Resort()
{
if (!m_branchData)
return;
if ((g_column = m_window->GetSortColumn()) >= -1)
{
wxDataViewTreeNodes& nodes = m_branchData->children;
g_model = m_window->GetModel();
g_asending = m_window->IsAscendingSort();
nodes.Sort(&wxGenericTreeModelNodeCmp);
int len = nodes.GetCount();
for (int i = 0; i < len; i++)
{
if (nodes[i]->HasChildren())
nodes[i]->Resort();
}
}
}
//-----------------------------------------------------------------------------
// wxDataViewMainWindow
//-----------------------------------------------------------------------------
// The tree building helper, declared firstly
static void BuildTreeHelper( const wxDataViewModel * model, const wxDataViewItem & item,
wxDataViewTreeNode * node);
static void BuildTreeHelper(wxDataViewMainWindow *window,
const wxDataViewModel *model,
const wxDataViewItem & item,
wxDataViewTreeNode * node);
wxIMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow);
@@ -1532,11 +1564,15 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i
// TODO: maybe there is something system colour to use
m_penExpander = wxPen(wxColour(0,0,0));
m_root = wxDataViewTreeNode::CreateRootNode();
m_root = wxDataViewTreeNode::CreateRootNode(this);
// Make m_count = -1 will cause the class recaculate the real displaying number of rows.
m_count = -1;
m_underMouse = NULL;
m_sortColumn = SortColumn_None;
m_sortAscending = true;
UpdateDisplay();
}
@@ -2330,7 +2366,7 @@ bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxData
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(this, parentNode, item);
itemNode->SetHasChildren(GetModel()->IsContainer(item));
parentNode->SetHasChildren(true);
@@ -2503,7 +2539,7 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
{
SortPrepare();
g_model->Resort();
GetModel()->Resort();
GetOwner()->InvalidateColBestWidths();
@@ -2534,7 +2570,7 @@ bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned i
return true;
*/
SortPrepare();
g_model->Resort();
GetModel()->Resort();
GetOwner()->InvalidateColBestWidth(view_column);
@@ -3148,7 +3184,7 @@ void wxDataViewMainWindow::Expand( unsigned int row )
if( node->GetChildNodes().empty() )
{
SortPrepare();
::BuildTreeHelper(GetModel(), node->GetItem(), node);
::BuildTreeHelper(this, GetModel(), node->GetItem(), node);
}
const unsigned countNewRows = node->GetSubTreeCount();
@@ -3253,7 +3289,7 @@ wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item
// child nodes in the control's representation yet. We have
// to realize its subtree now.
SortPrepare();
::BuildTreeHelper(model, node->GetItem(), node);
::BuildTreeHelper(this, model, node->GetItem(), node);
}
const wxDataViewTreeNodes& nodes = node->GetChildNodes();
@@ -3463,8 +3499,8 @@ int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem & item) const
}
}
static void BuildTreeHelper( const wxDataViewModel * model, const wxDataViewItem & item,
wxDataViewTreeNode * node)
static void BuildTreeHelper( wxDataViewMainWindow *window, const wxDataViewModel * model,
const wxDataViewItem & item, wxDataViewTreeNode * node)
{
if( !model->IsContainer( item ) )
return;
@@ -3474,7 +3510,7 @@ static void BuildTreeHelper( const wxDataViewModel * model, const wxDataViewIte
for ( unsigned int index = 0; index < num; index++ )
{
wxDataViewTreeNode *n = new wxDataViewTreeNode(node, children[index]);
wxDataViewTreeNode *n = new wxDataViewTreeNode(window, node, children[index]);
if( model->IsContainer(children[index]) )
n->SetHasChildren( true );
@@ -3496,12 +3532,12 @@ void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
return;
}
m_root = wxDataViewTreeNode::CreateRootNode();
m_root = wxDataViewTreeNode::CreateRootNode(this);
// First we define a invalid item to fetch the top-level elements
wxDataViewItem item;
SortPrepare();
BuildTreeHelper( model, item, m_root);
BuildTreeHelper(this, model, item, m_root);
InvalidateCount();
}