Browse Source

Reimplemented expanding/collapsing.

pull/10/head
Daniel Grunwald 14 years ago
parent
commit
54e170cae5
  1. 1
      ILSpy/AssemblyList.cs
  2. 4
      ILSpy/TreeNodes/AssemblyListTreeNode.cs
  3. 3
      ILSpy/TreeNodes/BaseTypesTreeNode.cs
  4. 3
      ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
  5. 3
      ILSpy/TreeNodes/ResourceListTreeNode.cs
  6. 73
      SharpTreeView/FlatListTreeNode.cs
  7. 80
      SharpTreeView/SharpTreeNode.cs
  8. 2
      SharpTreeView/SharpTreeNodeView.cs
  9. 2
      SharpTreeView/SharpTreeView.cs
  10. 25
      SharpTreeView/TreeFlattener.cs

1
ILSpy/AssemblyList.cs

@ -134,6 +134,7 @@ namespace ICSharpCode.ILSpy @@ -134,6 +134,7 @@ namespace ICSharpCode.ILSpy
{
if (def == null)
return null;
App.Current.Dispatcher.VerifyAccess();
if (def.DeclaringType != null) {
TypeTreeNode decl = FindTypeNode(def.DeclaringType);
if (decl != null) {

4
ILSpy/TreeNodes/AssemblyListTreeNode.cs

@ -45,6 +45,10 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -45,6 +45,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.assemblyList = assemblyList;
}
public override object Text {
get { return assemblyList.ListName; }
}
/*
public override DropEffect CanDrop(IDataObject data, DropEffect requestedEffect)
{

3
ILSpy/TreeNodes/BaseTypesTreeNode.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.TreeView;
@ -63,7 +64,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -63,7 +64,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
EnsureLazyChildren();
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren));
foreach (var child in this.Children) {
child.Decompile(language, output, options);
}

3
ILSpy/TreeNodes/ReferenceFolderTreeNode.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.TreeView;
using Mono.Cecil;
@ -60,7 +61,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -60,7 +61,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
EnsureLazyChildren();
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren));
foreach (var child in this.Children) {
child.Decompile(language, output, options);
}

3
ILSpy/TreeNodes/ResourceListTreeNode.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
using System;
using System.IO;
using System.Text;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Utils;
@ -51,7 +52,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -51,7 +52,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
EnsureLazyChildren();
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren));
foreach (var child in this.Children) {
child.Decompile(language, output, options);
output.WriteLine();

73
SharpTreeView/FlatListTreeNode.cs

@ -20,8 +20,8 @@ namespace ICSharpCode.TreeView @@ -20,8 +20,8 @@ namespace ICSharpCode.TreeView
/// <summary>Subtree height in the flat list tree</summary>
byte height = 1;
/// <summary>Length in the flat list, including children (children within the flat list).</summary>
internal int totalListLength = 1;
/// <summary>Length in the flat list, including children (children within the flat list). -1 = invalidated</summary>
int totalListLength = -1;
int Balance {
get { return Height(right) - Height(left); }
@ -39,14 +39,23 @@ namespace ICSharpCode.TreeView @@ -39,14 +39,23 @@ namespace ICSharpCode.TreeView
Debug.Assert(right == null || right.listParent == this);
Debug.Assert(height == 1 + Math.Max(Height(left), Height(right)));
Debug.Assert(Math.Abs(this.Balance) <= 1);
Debug.Assert(totalListLength == (left != null ? left.totalListLength : 0) + (isVisible ? 1 : 0) + (right != null ? right.totalListLength : 0));
Debug.Assert(totalListLength == -1 || totalListLength == (left != null ? left.totalListLength : 0) + (isVisible ? 1 : 0) + (right != null ? right.totalListLength : 0));
if (left != null) left.CheckInvariants();
if (right != null) right.CheckInvariants();
}
SharpTreeNode GetListRoot()
{
SharpTreeNode node = this;
while (node.listParent != null)
node = node.listParent;
return node;
}
#region GetNodeByVisibleIndex / GetVisibleIndexForNode
internal static SharpTreeNode GetNodeByVisibleIndex(SharpTreeNode root, int index)
{
root.GetTotalListLength(); // ensure all list lengths are calculated
Debug.Assert(index >= 0);
Debug.Assert(index < root.totalListLength);
SharpTreeNode node = root;
@ -69,12 +78,12 @@ namespace ICSharpCode.TreeView @@ -69,12 +78,12 @@ namespace ICSharpCode.TreeView
internal static int GetVisibleIndexForNode(SharpTreeNode node)
{
int index = 0;
int index = node.left != null ? node.left.GetTotalListLength() : 0;
while (node.listParent != null) {
if (node == node.listParent.right) {
if (node.listParent.left != null)
index += node.listParent.left.totalListLength;
if (node.isVisible)
index += node.listParent.left.GetTotalListLength();
if (node.listParent.isVisible)
index++;
}
node = node.listParent;
@ -91,6 +100,8 @@ namespace ICSharpCode.TreeView @@ -91,6 +100,8 @@ namespace ICSharpCode.TreeView
/// <returns>The new root node</returns>
static SharpTreeNode Rebalance(SharpTreeNode node)
{
Debug.Assert(node.left == null || Math.Abs(node.left.Balance) <= 1);
Debug.Assert(node.right == null || Math.Abs(node.right.Balance) <= 1);
// Keep looping until it's balanced. Not sure if this is stricly required; this is based on
// the Rope code where node merging made this necessary.
while (Math.Abs(node.Balance) > 1) {
@ -100,7 +111,6 @@ namespace ICSharpCode.TreeView @@ -100,7 +111,6 @@ namespace ICSharpCode.TreeView
if (node.Balance > 1) {
if (node.right.Balance < 0) {
node.right = node.right.RotateRight();
node.right.RecalculateAugmentedData();
}
node = node.RotateLeft();
// If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the left node; so rebalance that.
@ -108,24 +118,31 @@ namespace ICSharpCode.TreeView @@ -108,24 +118,31 @@ namespace ICSharpCode.TreeView
} else if (node.Balance < -1) {
if (node.left.Balance > 0) {
node.left = node.left.RotateLeft();
node.left.RecalculateAugmentedData();
}
node = node.RotateRight();
// If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the right node; so rebalance that.
node.right = Rebalance(node.right);
}
}
node.RecalculateAugmentedData();
Debug.Assert(Math.Abs(node.Balance) <= 1);
node.height = (byte)(1 + Math.Max(Height(node.left), Height(node.right)));
node.totalListLength = -1; // mark for recalculation
// since balancing checks the whole tree up to the root, the whole path will get marked as invalid
return node;
}
void RecalculateAugmentedData()
internal int GetTotalListLength()
{
Debug.Assert(Math.Abs(this.Balance) <= 1);
this.height = (byte)(1 + Math.Max(Height(this.left), Height(this.right)));
this.totalListLength = (isVisible ? 1 : 0)
+ (left != null ? left.totalListLength : 0)
+ (right != null ? right.totalListLength : 0);
if (totalListLength >= 0)
return totalListLength;
int length = (isVisible ? 1 : 0);
if (left != null) {
length += left.GetTotalListLength();
}
if (right != null) {
length += right.GetTotalListLength();
}
return totalListLength = length;
}
SharpTreeNode RotateLeft()
@ -145,8 +162,10 @@ namespace ICSharpCode.TreeView @@ -145,8 +162,10 @@ namespace ICSharpCode.TreeView
this.right = b;
newTop.left = this;
newTop.listParent = this.listParent;
RecalculateAugmentedData();
return this.listParent = newTop;
this.listParent = newTop;
// rebalance the 'this' node - this is necessary in some bulk insertion cases:
newTop.left = Rebalance(this);
return newTop;
}
SharpTreeNode RotateRight()
@ -166,15 +185,17 @@ namespace ICSharpCode.TreeView @@ -166,15 +185,17 @@ namespace ICSharpCode.TreeView
this.left = b;
newTop.right = this;
newTop.listParent = this.listParent;
RecalculateAugmentedData();
return this.listParent = newTop;
this.listParent = newTop;
newTop.right = Rebalance(this);
return newTop;
}
#endregion
#region Insertion
static void InsertNodeAfter(SharpTreeNode pos, SharpTreeNode newNode)
{
Debug.Assert(newNode.listParent == null);
// newNode might be the model root of a whole subtree, so go to the list root of that subtree:
newNode = newNode.GetListRoot();
if (pos.right == null) {
pos.right = newNode;
newNode.listParent = pos;
@ -194,10 +215,10 @@ namespace ICSharpCode.TreeView @@ -194,10 +215,10 @@ namespace ICSharpCode.TreeView
{
while (pos.listParent != null) {
if (pos == pos.listParent.left) {
pos.listParent.left = Rebalance(pos);
pos = pos.listParent.left = Rebalance(pos);
} else {
Debug.Assert(pos == pos.listParent.right);
pos.listParent.right = Rebalance(pos);
pos = pos.listParent.right = Rebalance(pos);
}
pos = pos.listParent;
}
@ -208,14 +229,14 @@ namespace ICSharpCode.TreeView @@ -208,14 +229,14 @@ namespace ICSharpCode.TreeView
pos.treeFlattener = null;
newRoot.treeFlattener.root = newRoot;
}
Debug.Assert(newRoot.listParent == null);
newRoot.CheckInvariants();
}
[Conditional("DEBUG")]
static void DumpTree(SharpTreeNode node)
{
while (node.listParent != null)
node = node.listParent;
node.DumpTree();
node.GetListRoot().DumpTree();
}
[Conditional("DEBUG")]
@ -225,7 +246,7 @@ namespace ICSharpCode.TreeView @@ -225,7 +246,7 @@ namespace ICSharpCode.TreeView
if (left != null)
left.DumpTree();
Debug.Unindent();
Debug.WriteLine("{0}, totalListLength={1}, height={2}", ToString(), totalListLength, height);
Debug.WriteLine("{0}, totalListLength={1}, height={2}, Balance={3}, isVisible={4}", ToString(), totalListLength, height, Balance, isVisible);
Debug.Indent();
if (right != null)
right.DumpTree();

80
SharpTreeView/SharpTreeNode.cs

@ -21,6 +21,56 @@ namespace ICSharpCode.TreeView @@ -21,6 +21,56 @@ namespace ICSharpCode.TreeView
internal SharpTreeNode modelParent;
bool isVisible = true;
void UpdateIsVisible(bool parentIsVisible, bool updateFlattener)
{
bool newIsVisible = parentIsVisible && !isHidden;
if (isVisible != newIsVisible) {
isVisible = newIsVisible;
// invalidate the augmented data
SharpTreeNode node = this;
while (node != null && node.totalListLength >= 0) {
node.totalListLength = -1;
node = node.listParent;
}
// Remember the removed nodes:
List<SharpTreeNode> removedNodes = null;
if (updateFlattener && !newIsVisible) {
removedNodes = VisibleDescendantsAndSelf().ToList();
}
// also update the model children:
UpdateChildIsVisible(false);
// Validate our invariants:
if (updateFlattener)
GetListRoot().CheckInvariants();
// Tell the flattener about the removed nodes:
if (removedNodes != null) {
var flattener = GetListRoot().treeFlattener;
if (flattener != null) {
flattener.NodesRemoved(GetVisibleIndexForNode(this), removedNodes);
}
}
// Tell the flattener about the new nodes:
if (updateFlattener && newIsVisible) {
var flattener = GetListRoot().treeFlattener;
if (flattener != null) {
flattener.NodesInserted(GetVisibleIndexForNode(this), VisibleDescendantsAndSelf());
}
}
}
}
void UpdateChildIsVisible(bool updateFlattener)
{
if (modelChildren != null && modelChildren.Count > 0) {
bool showChildren = isVisible && isExpanded;
foreach (SharpTreeNode child in modelChildren) {
child.UpdateIsVisible(showChildren, updateFlattener);
}
}
}
#region Main
public SharpTreeNode()
@ -72,6 +122,8 @@ namespace ICSharpCode.TreeView @@ -72,6 +122,8 @@ namespace ICSharpCode.TreeView
set {
if (isHidden != value) {
isHidden = value;
if (modelParent != null)
UpdateIsVisible(modelParent.isVisible && modelParent.isExpanded, true);
RaisePropertyChanged("IsHidden");
}
}
@ -110,17 +162,28 @@ namespace ICSharpCode.TreeView @@ -110,17 +162,28 @@ namespace ICSharpCode.TreeView
if (e.NewItems != null) {
SharpTreeNode insertionPos;
if (e.NewStartingIndex == 0)
insertionPos = this;
insertionPos = null;
else
insertionPos = modelChildren[e.NewStartingIndex - 1];
foreach (SharpTreeNode node in e.NewItems) {
Debug.Assert(node.modelParent == null);
node.modelParent = this;
Debug.WriteLine("Inserting {0} after {1}", node.ToString(), insertionPos.ToString());
InsertNodeAfter(insertionPos, node);
node.UpdateIsVisible(isVisible && isExpanded, false);
Debug.WriteLine("Inserting {0} after {1}", node, insertionPos);
while (insertionPos != null && insertionPos.modelChildren != null && insertionPos.modelChildren.Count > 0) {
insertionPos = insertionPos.modelChildren.Last();
}
InsertNodeAfter(insertionPos ?? this, node);
insertionPos = node;
if (node.isVisible) {
var flattener = GetListRoot().treeFlattener;
if (flattener != null) {
flattener.NodesInserted(GetVisibleIndexForNode(node), node.VisibleDescendantsAndSelf());
}
}
}
DumpTree(this);
}
RaisePropertyChanged("ShowExpander");
@ -149,6 +212,7 @@ namespace ICSharpCode.TreeView @@ -149,6 +212,7 @@ namespace ICSharpCode.TreeView
{
if (isExpanded != value) {
isExpanded = value;
UpdateChildIsVisible(true);
if (isExpanded) {
EnsureLazyChildren();
}
@ -208,14 +272,14 @@ namespace ICSharpCode.TreeView @@ -208,14 +272,14 @@ namespace ICSharpCode.TreeView
return TreeTraversal.PreOrder(this, n => n.Children);
}
public IEnumerable<SharpTreeNode> ExpandedDescendants()
internal IEnumerable<SharpTreeNode> VisibleDescendants()
{
return TreeTraversal.PreOrder(this.Children, n => n.IsExpanded ? n.Children : null);
return TreeTraversal.PreOrder(this.Children.Where(c => c.isVisible), n => n.Children.Where(c => c.isVisible));
}
public IEnumerable<SharpTreeNode> ExpandedDescendantsAndSelf()
internal IEnumerable<SharpTreeNode> VisibleDescendantsAndSelf()
{
return TreeTraversal.PreOrder(this, n => n.IsExpanded ? n.Children : null);
return TreeTraversal.PreOrder(this, n => n.Children.Where(c => c.isVisible));
}
public IEnumerable<SharpTreeNode> Ancestors()

2
SharpTreeView/SharpTreeNodeView.cs

@ -87,7 +87,7 @@ namespace ICSharpCode.TreeView @@ -87,7 +87,7 @@ namespace ICSharpCode.TreeView
OnIsEditingChanged();
} else if (e.PropertyName == "IsLast") {
if (ParentTreeView.ShowLines) {
foreach (var child in Node.ExpandedDescendantsAndSelf()) {
foreach (var child in Node.VisibleDescendantsAndSelf()) {
var container = ParentTreeView.ItemContainerGenerator.ContainerFromItem(child) as SharpTreeViewItem;
if (container != null) {
container.NodeView.LinesRenderer.InvalidateVisual();

2
SharpTreeView/SharpTreeView.cs

@ -153,7 +153,7 @@ namespace ICSharpCode.TreeView @@ -153,7 +153,7 @@ namespace ICSharpCode.TreeView
internal void HandleCollapsing(SharpTreeNode Node)
{
var selectedChilds = Node.ExpandedDescendants().Where(n => n.IsSelected);
var selectedChilds = Node.VisibleDescendants().Where(n => n.IsSelected);
if (selectedChilds.Any()) {
var list = SelectedItems.Cast<SharpTreeNode>().Except(selectedChilds).ToList();
list.AddOnce(Node);

25
SharpTreeView/TreeFlattener.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
@ -32,6 +33,28 @@ namespace ICSharpCode.TreeView @@ -32,6 +33,28 @@ namespace ICSharpCode.TreeView
public event NotifyCollectionChangedEventHandler CollectionChanged;
public void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
CollectionChanged(this, e);
}
public void NodesInserted(int index, IEnumerable<SharpTreeNode> nodes)
{
if (!includeRoot) index--;
foreach (SharpTreeNode node in nodes) {
RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, node, index++));
}
}
public void NodesRemoved(int index, IEnumerable<SharpTreeNode> nodes)
{
if (!includeRoot) index--;
foreach (SharpTreeNode node in nodes) {
RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, node, index));
}
}
public void Stop()
{
Debug.Assert(root.treeFlattener == this);
@ -51,7 +74,7 @@ namespace ICSharpCode.TreeView @@ -51,7 +74,7 @@ namespace ICSharpCode.TreeView
public int Count {
get {
return includeRoot ? root.totalListLength : root.totalListLength - 1;
return includeRoot ? root.GetTotalListLength() : root.GetTotalListLength() - 1;
}
}

Loading…
Cancel
Save