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