diff --git a/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.csproj b/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.csproj
index b0d700f89d..197a22139b 100644
--- a/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.csproj
+++ b/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.csproj
@@ -52,6 +52,7 @@
+
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageControl.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageControl.cs
index b2b1ce9b05..4bd28e2733 100644
--- a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageControl.cs
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageControl.cs
@@ -31,6 +31,7 @@ namespace ICSharpCode.CodeCoverage
ToolStrip toolStrip;
bool showSourceCodePanel;
bool showVisitCountPanel = true;
+ SequencePointListViewSorter sequencePointListViewSorter;
public CodeCoverageControl()
{
@@ -338,7 +339,7 @@ namespace ICSharpCode.CodeCoverage
listView.FullRowSelect = true;
listView.HideSelection = false;
listView.ItemActivate += ListViewItemActivate;
-
+
visitCountColumnHeader = new ColumnHeader();
visitCountColumnHeader.Text = StringParser.Parse("${res:ICSharpCode.CodeCoverage.VisitCount}");
visitCountColumnHeader.Width = 80;
@@ -364,6 +365,9 @@ namespace ICSharpCode.CodeCoverage
startColumnColumnHeader,
endLineColumnHeader,
endColumnColumnHeader});
+
+ // Create custom list view sorter.
+ sequencePointListViewSorter = new SequencePointListViewSorter(listView);
}
void DisposeListView()
@@ -383,6 +387,8 @@ namespace ICSharpCode.CodeCoverage
listView.ItemActivate -= ListViewItemActivate;
listView.Dispose();
listView = null;
+
+ sequencePointListViewSorter.Dispose();
}
void CreateVerticalSplitContainer()
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/SequencePointListViewSorter.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/SequencePointListViewSorter.cs
new file mode 100644
index 0000000000..3ac82d3051
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/SequencePointListViewSorter.cs
@@ -0,0 +1,140 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Sorts the list view that contains code coverage sequence
+ /// points.
+ ///
+ public class SequencePointListViewSorter : IComparer, IDisposable
+ {
+ ListView listView;
+ int column = -1;
+ SortOrder sortOrder = SortOrder.None;
+
+ const int VisitCountColumn = 0;
+ const int SequencePointLineColumn = 1;
+ const int SequencePointStartColumnColumn = 2;
+ const int SequencePointEndLineColumn = 3;
+ const int SequencePointEndColumnColumn = 4;
+
+ public SequencePointListViewSorter(ListView listView)
+ {
+ this.listView = listView;
+ listView.ListViewItemSorter = this;
+ listView.ColumnClick += ListViewColumnClick;
+ }
+
+ public void Dispose()
+ {
+ if (listView != null) {
+ listView.ColumnClick -= ListViewColumnClick;
+ }
+ }
+
+ ///
+ /// Compares two list view items and sorts them according
+ /// to the currently sorted column.
+ ///
+ public int Compare(object x, object y)
+ {
+ CodeCoverageSequencePoint lhs = null;
+ CodeCoverageSequencePoint rhs = null;
+
+ ListViewItem item = x as ListViewItem;
+ if (item != null) {
+ lhs = item.Tag as CodeCoverageSequencePoint;
+ }
+
+ item = y as ListViewItem;
+ if (item != null) {
+ rhs = item.Tag as CodeCoverageSequencePoint;
+ }
+
+ if (lhs != null && rhs != null) {
+ return Compare(lhs, rhs);
+ }
+ return 0;
+ }
+
+ ///
+ /// Sorts the list view by the specified column.
+ ///
+ public void Sort(int column)
+ {
+ if (this.column == column) {
+ ToggleSortOrder();
+ } else {
+ sortOrder = SortOrder.Ascending;
+ }
+ this.column = column;
+ listView.Sort();
+ }
+
+ ///
+ /// Compares two code coverage sequence points based on the
+ /// currently sorted column and sort order.
+ ///
+ int Compare(CodeCoverageSequencePoint x, CodeCoverageSequencePoint y)
+ {
+ int result = 0;
+ switch (column) {
+ case VisitCountColumn:
+ result = x.VisitCount - y.VisitCount;
+ break;
+ case SequencePointLineColumn:
+ result = x.Line - y.Line;
+ break;
+ case SequencePointStartColumnColumn:
+ result = x.Column - y.Column;
+ break;
+ case SequencePointEndLineColumn:
+ result = x.EndLine - y.EndLine;
+ break;
+ case SequencePointEndColumnColumn:
+ result = x.EndColumn - y.EndColumn;
+ break;
+ }
+
+ // Sort by secondary sort column?
+ if (result == 0 && column != SequencePointLineColumn) {
+ result = x.Line - y.Line;
+ }
+
+ if (sortOrder == SortOrder.Descending) {
+ return -result;
+ }
+ return result;
+ }
+
+ ///
+ /// Switches the sort order from ascending to descending
+ /// and vice versa.
+ ///
+ void ToggleSortOrder()
+ {
+ if (sortOrder == SortOrder.Ascending) {
+ sortOrder = SortOrder.Descending;
+ } else {
+ sortOrder = SortOrder.Ascending;
+ }
+ }
+
+ ///
+ /// User clicked a column header so sort that column.
+ ///
+ void ListViewColumnClick(object source, ColumnClickEventArgs e)
+ {
+ Sort(e.Column);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverage.Tests.csproj b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverage.Tests.csproj
index ed5cabe9c5..c245627f4d 100644
--- a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverage.Tests.csproj
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverage.Tests.csproj
@@ -52,6 +52,7 @@
+
diff --git a/src/AddIns/Misc/CodeCoverage/Test/ListViewSortingTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/ListViewSortingTestFixture.cs
new file mode 100644
index 0000000000..dda4e70eb8
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/ListViewSortingTestFixture.cs
@@ -0,0 +1,165 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Windows.Forms;
+using ICSharpCode.CodeCoverage;
+using NUnit.Framework;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ ///
+ /// Tests the sorting of the list view that shows
+ /// the code coverage sequence points (visit counts, etc).
+ /// Here we are not actually using the real list view, but
+ /// just a list view which has the same number of columns.
+ /// Eventually the sorter class will be replaced in
+ /// SharpDevelop 3.0 with the generic sorting classes.
+ ///
+ [TestFixture]
+ public class ListViewSortingTestFixture
+ {
+ ListView listView;
+ CodeCoverageSequencePoint firstSequencePoint;
+ CodeCoverageSequencePoint secondSequencePoint;
+ SequencePointListViewSorter sorter;
+ const int VisitCountColumn = 0;
+ const int SequencePointLineColumn = 1;
+ const int SequencePointStartColumnColumn = 2;
+ const int SequencePointEndLineColumn = 3;
+ const int SequencePointEndColumnColumn = 4;
+
+ [SetUp]
+ public void SetUp()
+ {
+ listView = new ListView();
+ sorter = new SequencePointListViewSorter(listView);
+
+ listView.Columns.Add("Visit Count");
+ listView.Columns.Add("Line");
+ listView.Columns.Add("Column");
+ listView.Columns.Add("End Line");
+ listView.Columns.Add("End Column");
+
+ // Add first sequence point.
+ firstSequencePoint = new CodeCoverageSequencePoint(String.Empty, 1, 5, 1, 5, 10);
+ ListViewItem item = new ListViewItem("First");
+ item.Tag = firstSequencePoint;
+ listView.Items.Add(item);
+
+ // Add second sequence point.
+ secondSequencePoint = new CodeCoverageSequencePoint(String.Empty, 0, 10, 2, 10, 8);
+ item = new ListViewItem("Second");
+ item.Tag = secondSequencePoint;
+ listView.Items.Add(item);
+
+ // Need to create the control's handle otherwise
+ // the list view will not sort.
+ listView.CreateControl();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ listView.Dispose();
+ }
+
+ [Test]
+ public void InitialOrderSameAsOrderAdded()
+ {
+ Assert.AreSame(firstSequencePoint, listView.Items[0].Tag);
+ Assert.AreSame(secondSequencePoint, listView.Items[1].Tag);
+ }
+
+ [Test]
+ public void SortVisitCountColumn()
+ {
+ sorter.Sort(VisitCountColumn);
+ Assert.AreSame(secondSequencePoint, listView.Items[0].Tag);
+ }
+
+ [Test]
+ public void SortVisitCountColumnTwice()
+ {
+ sorter.Sort(VisitCountColumn);
+ sorter.Sort(VisitCountColumn);
+ Assert.AreSame(firstSequencePoint, listView.Items[0].Tag);
+ }
+
+ [Test]
+ public void SortLineColumnTwice()
+ {
+ sorter.Sort(SequencePointLineColumn);
+ sorter.Sort(SequencePointLineColumn);
+ Assert.AreSame(secondSequencePoint, listView.Items[0].Tag);
+ }
+
+ [Test]
+ public void SortStartColumnTwice()
+ {
+ sorter.Sort(SequencePointStartColumnColumn);
+ sorter.Sort(SequencePointStartColumnColumn);
+ Assert.AreSame(secondSequencePoint, listView.Items[0].Tag);
+ }
+
+ [Test]
+ public void SortEndLineTwice()
+ {
+ sorter.Sort(SequencePointEndLineColumn);
+ sorter.Sort(SequencePointEndLineColumn);
+ Assert.AreSame(secondSequencePoint, listView.Items[0].Tag);
+ }
+
+ [Test]
+ public void SortEndColumn()
+ {
+ sorter.Sort(SequencePointEndColumnColumn);
+ Assert.AreSame(secondSequencePoint, listView.Items[0].Tag);
+ }
+
+ [Test]
+ public void CompareNulls()
+ {
+ Assert.AreEqual(0, sorter.Compare(null, null));
+ }
+
+ [Test]
+ public void CompareNullRhs()
+ {
+ Assert.AreEqual(0, sorter.Compare(null, new ListViewItem()));
+ }
+
+ [Test]
+ public void CompareTwoListViewItemsWithNoTags()
+ {
+ sorter.Sort(VisitCountColumn);
+ Assert.AreEqual(0, sorter.Compare(new ListViewItem(), new ListViewItem()));
+ }
+
+ [Test]
+ public void CompareRhsListViewItemWithNoTag()
+ {
+ sorter.Sort(VisitCountColumn);
+ Assert.AreEqual(0, sorter.Compare(listView.Items[0], new ListViewItem()));
+ }
+
+ [Test]
+ public void SecondarySortByLineWhenVisitCountSame()
+ {
+ sorter.Sort(VisitCountColumn);
+ CodeCoverageSequencePoint pt1 = new CodeCoverageSequencePoint(String.Empty, 0, 1, 0, 0, 0);
+ CodeCoverageSequencePoint pt2 = new CodeCoverageSequencePoint(String.Empty, 0, 2, 0, 0, 0);
+
+ ListViewItem item1 = new ListViewItem();
+ item1.Tag = pt1;
+ ListViewItem item2 = new ListViewItem();
+ item2.Tag = pt2;
+
+ Assert.AreEqual(-1, sorter.Compare(item1, item2));
+ }
+ }
+}