Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Implement treestore sorting #243

Open
wants to merge 3 commits into from

2 participants

@riviti

This makes it possible to tell TreeStore to sort the rows by one of the columns. Implemented for GTK and WPF. Mac is impossible for me to do since I do not have a system to test on.

@sevoku
Collaborator

Any progress here? I'm going to look on sorting next weeks. Has someone tried this approach? Can the backend code be reused?

@sevoku sevoku commented on the diff
Xwt/Xwt/TreeStore.cs
@@ -69,6 +69,11 @@ public TreeStore (params IDataField[] fields)
ITreeStoreBackend Backend {
get { return (ITreeStoreBackend)BackendHost.Backend; }
}
+
+ public void SetSortField (IDataField field, ColumnSortDirection order)
@sevoku Collaborator
sevoku added a note

This is redundant. Sorting can be set on the columns directly.

@riviti
riviti added a note

As far as I remember, for the Gtk+ backend this is (was) not possible, because the Xwt column does not have access to the Gtk+ tree store, which is where sorting is controlled in that toolkit. I remember there was some Xwt api concern about this PR which is the reason for it not being merged, but the discussion doesn't seem to have happened here, perhaps it was in #mono or #monodevelop.

@sevoku Collaborator
sevoku added a note

Hhm, I recently merged 8d05788 (PR: #429) which adds column sorting for Gtk (https://github.com/mono/xwt/blob/master/Xwt.Gtk/Xwt.GtkBackend/TableViewBackend.cs#L149) and it seems to work as expected. Column wise sorting has only the limitation that more complex sorting is not possible (e.g. column1=x && column2=y), but this should be implemented in a separate SortFunc implementation which would override column sorting settings (like it does Gtk in the Filter and Sort stores) and is not part of this PR, too.

So the Frontend implementation is Ok, atm. The backends should simply handle the appropriate column settings.

@riviti
riviti added a note

Well, I don't have any immediate interest in getting this merged (anymore), so since it seems to have bitrotted, I'd say whoever feels the need should feel free to pick this work up and finish it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@sevoku sevoku added the feedback label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 16, 2013
  1. @riviti
  2. @riviti
Commits on Sep 19, 2013
  1. @riviti
This page is out of date. Refresh to see the latest.
View
5 Xwt.Gtk/Xwt.GtkBackend/TreeStoreBackend.cs
@@ -86,6 +86,11 @@ public void Clear ()
Tree.Clear ();
}
+ public void SetSortField(IDataField field, ColumnSortDirection direction)
+ {
+ Tree.SetSortColumnId (field.Index, direction == ColumnSortDirection.Ascending ? Gtk.SortType.Ascending : Gtk.SortType.Descending);
+ }
+
public TreePosition GetChild (TreePosition pos, int index)
{
IterPos tpos = GetIterPos (pos);
View
38 Xwt.WPF/Xwt.WPFBackend/TreeStoreBackend.cs
@@ -183,7 +183,30 @@ public void Clear ()
this.topNodes.Clear();
}
- public IEnumerator GetEnumerator ()
+ #region Sorting handling
+
+ public void SetSortField(IDataField field, ColumnSortDirection order)
+ {
+ SortField = field;
+ SortOrder = order;
+ OnSortOptionsChanged(new SortingOptionsEventArgs(field, order));
+ }
+
+ public event EventHandler<SortingOptionsEventArgs> SortOptionsChanged;
+
+ protected virtual void OnSortOptionsChanged(SortingOptionsEventArgs e)
+ {
+ var handler = SortOptionsChanged;
+ if (handler != null) handler(this, e);
+ }
+
+ public ColumnSortDirection SortOrder { get; private set; }
+
+ public IDataField SortField { get; private set; }
+
+ #endregion
+
+ public IEnumerator GetEnumerator ()
{
return this.topNodes.GetEnumerator ();
}
@@ -236,4 +259,17 @@ private void OnNodesReordered (TreeNodeOrderEventArgs e)
handler (this, e);
}
}
+
+ public class SortingOptionsEventArgs : EventArgs
+ {
+ public SortingOptionsEventArgs(IDataField sortingField, ColumnSortDirection sortOrder)
+ {
+ SortField = sortingField;
+ SortOrder = sortOrder;
+ }
+
+ public ColumnSortDirection SortOrder { get; private set; }
+
+ public IDataField SortField { get; private set; }
+ }
}
View
20 Xwt.WPF/Xwt.WPFBackend/TreeViewBackend.cs
@@ -26,6 +26,7 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Windows.Data;
using System.Windows.Documents;
@@ -158,9 +159,24 @@ public void UnselectAll ()
Tree.UnselectAll();
}
- public void SetSource (ITreeDataSource source, IBackend sourceBackend)
+ public void SetSource(ITreeDataSource source, IBackend sourceBackend)
{
- Tree.ItemsSource = (TreeStoreBackend) sourceBackend;
+ var oldBackend = Tree.ItemsSource as TreeStoreBackend;
+ if (oldBackend != null)
+ oldBackend.SortOptionsChanged -= TreeStoreBackend_SortOptionsChanged;
+
+ var treeStoreBackend = (TreeStoreBackend)sourceBackend;
+ treeStoreBackend.SortOptionsChanged += TreeStoreBackend_SortOptionsChanged;
+
+ Tree.ItemsSource = treeStoreBackend;
+ if (treeStoreBackend.SortField != null)
+ Tree.Items.SortDescriptions.Add(new SortDescription(".[" + treeStoreBackend.SortField.Index + "]", treeStoreBackend.SortOrder == ColumnSortDirection.Ascending ? ListSortDirection.Ascending : ListSortDirection.Descending));
+ }
+
+ void TreeStoreBackend_SortOptionsChanged(object sender, SortingOptionsEventArgs e)
+ {
+ Tree.Items.SortDescriptions.Clear();
+ Tree.Items.SortDescriptions.Add(new SortDescription(".[" + e.SortField.Index + "]", e.SortOrder == ColumnSortDirection.Ascending ? ListSortDirection.Ascending : ListSortDirection.Descending));
}
public object AddColumn (ListViewColumn column)
View
1  Xwt/Xwt.Backends/ITreeStoreBackend.cs
@@ -44,6 +44,7 @@ public interface ITreeStoreBackend: ITreeDataSource, IBackend
TreePosition GetNext (TreePosition pos);
TreePosition GetPrevious (TreePosition pos);
void Clear ();
+ void SetSortField (IDataField field, ColumnSortDirection order);
}
}
View
103 Xwt/Xwt/TreeStore.cs
@@ -37,7 +37,7 @@ namespace Xwt
[BackendType (typeof(ITreeStoreBackend))]
public class TreeStore: XwtComponent, ITreeDataSource
{
- IDataField[] fields;
+ readonly IDataField[] fields;
class TreeStoreBackendHost: BackendHost<TreeStore,ITreeStoreBackend>
{
@@ -69,6 +69,11 @@ public TreeStore (params IDataField[] fields)
ITreeStoreBackend Backend {
get { return (ITreeStoreBackend)BackendHost.Backend; }
}
+
+ public void SetSortField (IDataField field, ColumnSortDirection order)
@sevoku Collaborator
sevoku added a note

This is redundant. Sorting can be set on the columns directly.

@riviti
riviti added a note

As far as I remember, for the Gtk+ backend this is (was) not possible, because the Xwt column does not have access to the Gtk+ tree store, which is where sorting is controlled in that toolkit. I remember there was some Xwt api concern about this PR which is the reason for it not being merged, but the discussion doesn't seem to have happened here, perhaps it was in #mono or #monodevelop.

@sevoku Collaborator
sevoku added a note

Hhm, I recently merged 8d05788 (PR: #429) which adds column sorting for Gtk (https://github.com/mono/xwt/blob/master/Xwt.Gtk/Xwt.GtkBackend/TableViewBackend.cs#L149) and it seems to work as expected. Column wise sorting has only the limitation that more complex sorting is not possible (e.g. column1=x && column2=y), but this should be implemented in a separate SortFunc implementation which would override column sorting settings (like it does Gtk in the Filter and Sort stores) and is not part of this PR, too.

So the Frontend implementation is Ok, atm. The backends should simply handle the appropriate column settings.

@riviti
riviti added a note

Well, I don't have any immediate interest in getting this merged (anymore), so since it seems to have bitrotted, I'd say whoever feels the need should feel free to pick this work up and finish it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ {
+ Backend.SetSortField (field, order);
+ }
public TreeNavigator GetFirstNode ()
{
@@ -175,6 +180,38 @@ public override int GetHashCode ()
return ParentList.GetHashCode () ^ NodeId;
}
}
+
+ class NodeComparer : IComparer<Node>
+ {
+
+ readonly int fieldIndex;
+
+ readonly ColumnSortDirection direction;
+
+ public NodeComparer (int fieldIndex, ColumnSortDirection direction)
+ {
+ this.fieldIndex = fieldIndex;
+ this.direction = direction;
+
+ }
+
+ #region IComparer implementation
+
+ public int Compare (Node x, Node y)
+ {
+ var xData = x.Data [fieldIndex] as IComparable;
+ if (xData != null) {
+ if (direction == ColumnSortDirection.Ascending)
+ return xData.CompareTo (y.Data [fieldIndex]);
+ return -xData.CompareTo (y.Data [fieldIndex]);
+ }
+ // TODO: What to do here?
+ return 0;
+ }
+
+ #endregion
+
+ }
class NodeList: List<Node>
{
@@ -182,10 +219,13 @@ class NodeList: List<Node>
}
Type[] columnTypes;
- NodeList rootNodes = new NodeList ();
+ readonly NodeList rootNodes = new NodeList ();
int version;
int nextNodeId;
-
+
+ int sortFieldId = -1;
+ ColumnSortDirection columnSortDirection;
+
public event EventHandler<TreeNodeEventArgs> NodeInserted;
public event EventHandler<TreeNodeChildEventArgs> NodeDeleted;
public event EventHandler<TreeNodeEventArgs> NodeChanged;
@@ -204,7 +244,46 @@ public void Clear ()
{
rootNodes.Clear ();
}
-
+
+ public void SetSortField (IDataField field, ColumnSortDirection direction)
+ {
+ if (sortFieldId != field.Index) {
+ sortFieldId = field.Index;
+ columnSortDirection = direction;
+ Sort (rootNodes, true);
+ }
+ }
+
+ void Sort (NodeList toSort, bool recurse = false)
+ {
+ DoSort (toSort, recurse);
+ version++;
+ }
+
+ void DoSort (NodeList toSort, bool recurse = false)
+ {
+ var oldPositions = new Dictionary<Node, int> ();
+ int i = 0;
+ foreach (var node in toSort) {
+ oldPositions.Add (node, i++);
+ }
+
+ toSort.Sort (new NodeComparer(sortFieldId, columnSortDirection));
+
+ var oldIndexes = new int[toSort.Count];
+ for (int j = 0; j < toSort.Count; j++) {
+ oldIndexes [j] = oldPositions [toSort [j]];
+ }
+ if (NodesReordered != null) {
+ NodesReordered (this, new TreeNodeOrderEventArgs (toSort.Parent, oldIndexes));
+ }
+
+ if (!recurse)
+ return;
+ foreach (var child in toSort)
+ DoSort (child.Children, true);
+ }
+
NodePosition GetPosition (TreePosition pos)
{
if (pos == null)
@@ -236,6 +315,7 @@ public void SetValue (TreePosition pos, int column, object value)
node.Data [column] = value;
if (NodeChanged != null)
NodeChanged (this, new TreeNodeEventArgs (pos));
+ Sort (n.ParentList);
}
public object GetValue (TreePosition pos, int column)
@@ -298,13 +378,13 @@ public TreePosition InsertBefore (TreePosition pos)
np.ParentList.Insert (np.NodeIndex, nn);
version++;
- // Update the NodePosition since it is now invalid
- np.NodeIndex++;
- np.StoreVersion = version;
-
var node = new NodePosition () { ParentList = np.ParentList, NodeId = nn.NodeId, NodeIndex = np.NodeIndex - 1, StoreVersion = version };
if (NodeInserted != null)
NodeInserted (this, new TreeNodeEventArgs (node));
+
+ // Don't update the NodePosition. We cannot know what index will be correct after sorting.
+ Sort (np.ParentList);
+
return node;
}
@@ -317,12 +397,13 @@ public TreePosition InsertAfter (TreePosition pos)
np.ParentList.Insert (np.NodeIndex + 1, nn);
version++;
- // Update the provided position is still valid
- np.StoreVersion = version;
-
var node = new NodePosition () { ParentList = np.ParentList, NodeId = nn.NodeId, NodeIndex = np.NodeIndex + 1, StoreVersion = version };
if (NodeInserted != null)
NodeInserted (this, new TreeNodeEventArgs (node));
+
+ // Don't update the NodePosition. We cannot know what index will be correct after sorting.
+ Sort (np.ParentList);
+
return node;
}
Something went wrong with that request. Please try again.