forked from mirrors/NBTExplorer
Merging master
This commit is contained in:
commit
1aea80c7fd
8 changed files with 1038 additions and 18 deletions
|
@ -193,7 +193,7 @@ namespace NBTExplorer.Model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Capabilities
|
#region Node Capabilities
|
||||||
|
|
||||||
protected virtual NodeCapabilities Capabilities
|
protected virtual NodeCapabilities Capabilities
|
||||||
{
|
{
|
||||||
|
@ -262,6 +262,55 @@ namespace NBTExplorer.Model
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Group Capabilities
|
||||||
|
|
||||||
|
public virtual GroupCapabilities RenameNodeCapabilities
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.Single; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual GroupCapabilities EditNodeCapabilities
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.Single; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual GroupCapabilities DeleteNodeCapabilities
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.MultiMixedType | GroupCapabilities.ElideChildren; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual GroupCapabilities CutNodeCapabilities
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.Single; } //SiblingMixedType
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual GroupCapabilities CopyNodeCapabilities
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.Single; } //SiblingMixedType
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual GroupCapabilities PasteIntoNodeCapabilities
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.Single; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual GroupCapabilities SearchNodeCapabilites
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.Single; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual GroupCapabilities ReorderNodeCapabilities
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.Single; } //SiblingMixedType
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual GroupCapabilities RefreshNodeCapabilites
|
||||||
|
{
|
||||||
|
get { return GroupCapabilities.Single; } // MultiMixedType | ElideChildren
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Operations
|
#region Operations
|
||||||
|
|
||||||
public virtual bool CreateNode (TagType type)
|
public virtual bool CreateNode (TagType type)
|
||||||
|
|
|
@ -17,4 +17,16 @@ namespace NBTExplorer.Model
|
||||||
Reorder = 0x100,
|
Reorder = 0x100,
|
||||||
Refresh = 0x200,
|
Refresh = 0x200,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum GroupCapabilities
|
||||||
|
{
|
||||||
|
Single = 0x0,
|
||||||
|
SiblingSameType = 0x1,
|
||||||
|
SiblingMixedType = 0x2 | SiblingSameType,
|
||||||
|
MultiSameType = 0x4 | SiblingSameType,
|
||||||
|
MultiMixedType = 0x8 | MultiSameType | SiblingMixedType,
|
||||||
|
ElideChildren = 0x10,
|
||||||
|
All = MultiMixedType | ElideChildren,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,8 @@ namespace NBTExplorer.Model
|
||||||
| NodeCapabilities.Cut
|
| NodeCapabilities.Cut
|
||||||
| NodeCapabilities.Delete
|
| NodeCapabilities.Delete
|
||||||
| NodeCapabilities.PasteInto
|
| NodeCapabilities.PasteInto
|
||||||
| (TagParent.IsNamedContainer ? NodeCapabilities.Rename : NodeCapabilities.None)
|
| ((TagParent != null && TagParent.IsNamedContainer) ? NodeCapabilities.Rename : NodeCapabilities.None)
|
||||||
| (TagParent.IsOrderedContainer ? NodeCapabilities.Reorder : NodeCapabilities.None)
|
| ((TagParent != null && TagParent.IsOrderedContainer) ? NodeCapabilities.Reorder : NodeCapabilities.None)
|
||||||
| NodeCapabilities.Search;
|
| NodeCapabilities.Search;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,8 +158,8 @@ namespace NBTExplorer.Model
|
||||||
| NodeCapabilities.Cut
|
| NodeCapabilities.Cut
|
||||||
| NodeCapabilities.Delete
|
| NodeCapabilities.Delete
|
||||||
| NodeCapabilities.Edit
|
| NodeCapabilities.Edit
|
||||||
| (TagParent.IsNamedContainer ? NodeCapabilities.Rename : NodeCapabilities.None)
|
| ((TagParent != null && TagParent.IsNamedContainer) ? NodeCapabilities.Rename : NodeCapabilities.None)
|
||||||
| (TagParent.IsOrderedContainer ? NodeCapabilities.Reorder : NodeCapabilities.None);
|
| ((TagParent != null && TagParent.IsOrderedContainer) ? NodeCapabilities.Reorder : NodeCapabilities.None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ namespace NBTExplorer.Model
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (TagParent.IsOrderedContainer)
|
if (TagParent != null && TagParent.IsOrderedContainer)
|
||||||
return TagParent.OrderedTagContainer.GetTagIndex(Tag) > 0;
|
return TagParent.OrderedTagContainer.GetTagIndex(Tag) > 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ namespace NBTExplorer.Model
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (TagParent.IsOrderedContainer)
|
if (TagParent != null && TagParent.IsOrderedContainer)
|
||||||
return TagParent.OrderedTagContainer.GetTagIndex(Tag) < (TagParent.TagCount - 1);
|
return TagParent.OrderedTagContainer.GetTagIndex(Tag) < (TagParent.TagCount - 1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -210,8 +210,9 @@ namespace NBTExplorer.Model
|
||||||
|
|
||||||
public override bool DeleteNode ()
|
public override bool DeleteNode ()
|
||||||
{
|
{
|
||||||
if (CanDeleteNode) {
|
if (CanDeleteNode && TagParent != null) {
|
||||||
TagParent.DeleteTag(Tag);
|
TagParent.DeleteTag(Tag);
|
||||||
|
IsParentModified = true;
|
||||||
return Parent.Nodes.Remove(this);
|
return Parent.Nodes.Remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +221,7 @@ namespace NBTExplorer.Model
|
||||||
|
|
||||||
public override bool RenameNode ()
|
public override bool RenameNode ()
|
||||||
{
|
{
|
||||||
if (CanRenameNode && TagParent.IsNamedContainer && FormRegistry.EditString != null) {
|
if (CanRenameNode && TagParent != null && TagParent.IsNamedContainer && FormRegistry.EditString != null) {
|
||||||
RestrictedStringFormData data = new RestrictedStringFormData(TagParent.NamedTagContainer.GetTagName(Tag));
|
RestrictedStringFormData data = new RestrictedStringFormData(TagParent.NamedTagContainer.GetTagName(Tag));
|
||||||
data.RestrictedValues.AddRange(TagParent.NamedTagContainer.TagNamesInUse);
|
data.RestrictedValues.AddRange(TagParent.NamedTagContainer.TagNamesInUse);
|
||||||
|
|
||||||
|
@ -247,10 +248,11 @@ namespace NBTExplorer.Model
|
||||||
|
|
||||||
public override bool CutNode ()
|
public override bool CutNode ()
|
||||||
{
|
{
|
||||||
if (CanCutNode) {
|
if (CanCutNode && TagParent != null) {
|
||||||
NbtClipboardController.CopyToClipboard(new NbtClipboardData(NodeName, Tag));
|
NbtClipboardController.CopyToClipboard(new NbtClipboardData(NodeName, Tag));
|
||||||
|
|
||||||
TagParent.DeleteTag(Tag);
|
TagParent.DeleteTag(Tag);
|
||||||
|
IsParentModified = true;
|
||||||
Parent.Nodes.Remove(this);
|
Parent.Nodes.Remove(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +262,7 @@ namespace NBTExplorer.Model
|
||||||
|
|
||||||
public override bool ChangeRelativePosition (int offset)
|
public override bool ChangeRelativePosition (int offset)
|
||||||
{
|
{
|
||||||
if (CanReoderNode) {
|
if (CanReoderNode && TagParent != null) {
|
||||||
int curIndex = TagParent.OrderedTagContainer.GetTagIndex(Tag);
|
int curIndex = TagParent.OrderedTagContainer.GetTagIndex(Tag);
|
||||||
int newIndex = curIndex + offset;
|
int newIndex = curIndex + offset;
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,9 @@
|
||||||
<Compile Include="Controllers\NodeTreeController.cs" />
|
<Compile Include="Controllers\NodeTreeController.cs" />
|
||||||
<Compile Include="FormRegistry.cs" />
|
<Compile Include="FormRegistry.cs" />
|
||||||
<Compile Include="NbtClipboardController.cs" />
|
<Compile Include="NbtClipboardController.cs" />
|
||||||
|
<Compile Include="Vendor\MultiSelectTreeView\MultiSelectTreeview.cs">
|
||||||
|
<SubType>Component</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Windows\CancelSearchForm.cs">
|
<Compile Include="Windows\CancelSearchForm.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("2.1.0.0")]
|
[assembly: AssemblyVersion("2.2.0.0")]
|
||||||
[assembly: AssemblyFileVersion("2.1.0.0")]
|
[assembly: AssemblyFileVersion("2.2.0.0")]
|
||||||
|
|
585
Vendor/MultiSelectTreeView/MultiSelectTreeview.cs
vendored
Normal file
585
Vendor/MultiSelectTreeView/MultiSelectTreeview.cs
vendored
Normal file
|
@ -0,0 +1,585 @@
|
||||||
|
// Copyright 2007 Andrew D. Weiss
|
||||||
|
// Licensed under CPOL
|
||||||
|
// http://www.codeproject.com/Articles/20581/Multiselect-Treeview-Implementation
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace NBTExplorer.Vendor.MultiSelectTreeView
|
||||||
|
{
|
||||||
|
public class MultiSelectTreeView : TreeView
|
||||||
|
{
|
||||||
|
|
||||||
|
#region Selected Node(s) Properties
|
||||||
|
|
||||||
|
private List<TreeNode> m_SelectedNodes = null;
|
||||||
|
public List<TreeNode> SelectedNodes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_SelectedNodes;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ClearSelectedNodes();
|
||||||
|
if( value != null )
|
||||||
|
{
|
||||||
|
foreach( TreeNode node in value )
|
||||||
|
{
|
||||||
|
ToggleNode( node, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note we use the new keyword to Hide the native treeview's SelectedNode property.
|
||||||
|
private TreeNode m_SelectedNode;
|
||||||
|
public new TreeNode SelectedNode
|
||||||
|
{
|
||||||
|
get { return m_SelectedNode; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ClearSelectedNodes();
|
||||||
|
if( value != null )
|
||||||
|
{
|
||||||
|
SelectNode( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public MultiSelectTreeView()
|
||||||
|
{
|
||||||
|
m_SelectedNodes = new List<TreeNode>();
|
||||||
|
base.SelectedNode = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Overridden Events
|
||||||
|
|
||||||
|
protected override void OnGotFocus( EventArgs e )
|
||||||
|
{
|
||||||
|
// Make sure at least one node has a selection
|
||||||
|
// this way we can tab to the ctrl and use the
|
||||||
|
// keyboard to select nodes
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if( m_SelectedNode == null && this.TopNode != null )
|
||||||
|
{
|
||||||
|
ToggleNode( this.TopNode, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnGotFocus( e );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
HandleException( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseDown( MouseEventArgs e )
|
||||||
|
{
|
||||||
|
// If the user clicks on a node that was not
|
||||||
|
// previously selected, select it now.
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
base.SelectedNode = null;
|
||||||
|
|
||||||
|
TreeNode node = this.GetNodeAt( e.Location );
|
||||||
|
if( node != null )
|
||||||
|
{
|
||||||
|
int leftBound = node.Bounds.X; // - 20; // Allow user to click on image
|
||||||
|
int rightBound = node.Bounds.Right + 10; // Give a little extra room
|
||||||
|
if( e.Location.X > leftBound && e.Location.X < rightBound )
|
||||||
|
{
|
||||||
|
if( ModifierKeys == Keys.None && ( m_SelectedNodes.Contains( node ) ) )
|
||||||
|
{
|
||||||
|
// Potential Drag Operation
|
||||||
|
// Let Mouse Up do select
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectNode( node );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnMouseDown( e );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
HandleException( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseUp( MouseEventArgs e )
|
||||||
|
{
|
||||||
|
// If the clicked on a node that WAS previously
|
||||||
|
// selected then, reselect it now. This will clear
|
||||||
|
// any other selected nodes. e.g. A B C D are selected
|
||||||
|
// the user clicks on B, now A C & D are no longer selected.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check to see if a node was clicked on
|
||||||
|
TreeNode node = this.GetNodeAt( e.Location );
|
||||||
|
if( node != null )
|
||||||
|
{
|
||||||
|
if( ModifierKeys == Keys.None && m_SelectedNodes.Contains( node ) )
|
||||||
|
{
|
||||||
|
int leftBound = node.Bounds.X; // -20; // Allow user to click on image
|
||||||
|
int rightBound = node.Bounds.Right + 10; // Give a little extra room
|
||||||
|
if( e.Location.X > leftBound && e.Location.X < rightBound )
|
||||||
|
{
|
||||||
|
|
||||||
|
SelectNode( node );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnMouseUp( e );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
HandleException( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnItemDrag( ItemDragEventArgs e )
|
||||||
|
{
|
||||||
|
// If the user drags a node and the node being dragged is NOT
|
||||||
|
// selected, then clear the active selection, select the
|
||||||
|
// node being dragged and drag it. Otherwise if the node being
|
||||||
|
// dragged is selected, drag the entire selection.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TreeNode node = e.Item as TreeNode;
|
||||||
|
|
||||||
|
if( node != null )
|
||||||
|
{
|
||||||
|
if( !m_SelectedNodes.Contains( node ) )
|
||||||
|
{
|
||||||
|
SelectSingleNode( node );
|
||||||
|
ToggleNode( node, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnItemDrag( e );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
HandleException( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnBeforeSelect( TreeViewCancelEventArgs e )
|
||||||
|
{
|
||||||
|
// Never allow base.SelectedNode to be set!
|
||||||
|
try
|
||||||
|
{
|
||||||
|
base.SelectedNode = null;
|
||||||
|
e.Cancel = true;
|
||||||
|
|
||||||
|
base.OnBeforeSelect( e );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
HandleException( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAfterSelect( TreeViewEventArgs e )
|
||||||
|
{
|
||||||
|
// Never allow base.SelectedNode to be set!
|
||||||
|
try
|
||||||
|
{
|
||||||
|
base.OnAfterSelect( e );
|
||||||
|
base.SelectedNode = null;
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
HandleException( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyDown( KeyEventArgs e )
|
||||||
|
{
|
||||||
|
// Handle all possible key strokes for the control.
|
||||||
|
// including navigation, selection, etc.
|
||||||
|
|
||||||
|
base.OnKeyDown( e );
|
||||||
|
|
||||||
|
if( e.KeyCode == Keys.ShiftKey ) return;
|
||||||
|
|
||||||
|
//this.BeginUpdate();
|
||||||
|
bool bShift = ( ModifierKeys == Keys.Shift );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Nothing is selected in the tree, this isn't a good state
|
||||||
|
// select the top node
|
||||||
|
if( m_SelectedNode == null && this.TopNode != null )
|
||||||
|
{
|
||||||
|
ToggleNode( this.TopNode, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing is still selected in the tree, this isn't a good state, leave.
|
||||||
|
if( m_SelectedNode == null ) return;
|
||||||
|
|
||||||
|
if( e.KeyCode == Keys.Left )
|
||||||
|
{
|
||||||
|
if( m_SelectedNode.IsExpanded && m_SelectedNode.Nodes.Count > 0 )
|
||||||
|
{
|
||||||
|
// Collapse an expanded node that has children
|
||||||
|
m_SelectedNode.Collapse();
|
||||||
|
}
|
||||||
|
else if( m_SelectedNode.Parent != null )
|
||||||
|
{
|
||||||
|
// Node is already collapsed, try to select its parent.
|
||||||
|
SelectSingleNode( m_SelectedNode.Parent );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( e.KeyCode == Keys.Right )
|
||||||
|
{
|
||||||
|
if( !m_SelectedNode.IsExpanded )
|
||||||
|
{
|
||||||
|
// Expand a collpased node's children
|
||||||
|
m_SelectedNode.Expand();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Node was already expanded, select the first child
|
||||||
|
SelectSingleNode( m_SelectedNode.FirstNode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( e.KeyCode == Keys.Up )
|
||||||
|
{
|
||||||
|
// Select the previous node
|
||||||
|
if( m_SelectedNode.PrevVisibleNode != null )
|
||||||
|
{
|
||||||
|
SelectNode( m_SelectedNode.PrevVisibleNode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( e.KeyCode == Keys.Down )
|
||||||
|
{
|
||||||
|
// Select the next node
|
||||||
|
if( m_SelectedNode.NextVisibleNode != null )
|
||||||
|
{
|
||||||
|
SelectNode( m_SelectedNode.NextVisibleNode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( e.KeyCode == Keys.Home )
|
||||||
|
{
|
||||||
|
if( bShift )
|
||||||
|
{
|
||||||
|
if( m_SelectedNode.Parent == null )
|
||||||
|
{
|
||||||
|
// Select all of the root nodes up to this point
|
||||||
|
if( this.Nodes.Count > 0 )
|
||||||
|
{
|
||||||
|
SelectNode( this.Nodes[0] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Select all of the nodes up to this point under this nodes parent
|
||||||
|
SelectNode( m_SelectedNode.Parent.FirstNode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Select this first node in the tree
|
||||||
|
if( this.Nodes.Count > 0 )
|
||||||
|
{
|
||||||
|
SelectSingleNode( this.Nodes[0] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( e.KeyCode == Keys.End )
|
||||||
|
{
|
||||||
|
if( bShift )
|
||||||
|
{
|
||||||
|
if( m_SelectedNode.Parent == null )
|
||||||
|
{
|
||||||
|
// Select the last ROOT node in the tree
|
||||||
|
if( this.Nodes.Count > 0 )
|
||||||
|
{
|
||||||
|
SelectNode( this.Nodes[this.Nodes.Count - 1] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Select the last node in this branch
|
||||||
|
SelectNode( m_SelectedNode.Parent.LastNode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( this.Nodes.Count > 0 )
|
||||||
|
{
|
||||||
|
// Select the last node visible node in the tree.
|
||||||
|
// Don't expand branches incase the tree is virtual
|
||||||
|
TreeNode ndLast = this.Nodes[0].LastNode;
|
||||||
|
while( ndLast.IsExpanded && ( ndLast.LastNode != null ) )
|
||||||
|
{
|
||||||
|
ndLast = ndLast.LastNode;
|
||||||
|
}
|
||||||
|
SelectSingleNode( ndLast );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( e.KeyCode == Keys.PageUp )
|
||||||
|
{
|
||||||
|
// Select the highest node in the display
|
||||||
|
int nCount = this.VisibleCount;
|
||||||
|
TreeNode ndCurrent = m_SelectedNode;
|
||||||
|
while( ( nCount ) > 0 && ( ndCurrent.PrevVisibleNode != null ) )
|
||||||
|
{
|
||||||
|
ndCurrent = ndCurrent.PrevVisibleNode;
|
||||||
|
nCount--;
|
||||||
|
}
|
||||||
|
SelectSingleNode( ndCurrent );
|
||||||
|
}
|
||||||
|
else if( e.KeyCode == Keys.PageDown )
|
||||||
|
{
|
||||||
|
// Select the lowest node in the display
|
||||||
|
int nCount = this.VisibleCount;
|
||||||
|
TreeNode ndCurrent = m_SelectedNode;
|
||||||
|
while( ( nCount ) > 0 && ( ndCurrent.NextVisibleNode != null ) )
|
||||||
|
{
|
||||||
|
ndCurrent = ndCurrent.NextVisibleNode;
|
||||||
|
nCount--;
|
||||||
|
}
|
||||||
|
SelectSingleNode( ndCurrent );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Assume this is a search character a-z, A-Z, 0-9, etc.
|
||||||
|
// Select the first node after the current node that
|
||||||
|
// starts with this character
|
||||||
|
string sSearch = ( (char) e.KeyValue ).ToString();
|
||||||
|
|
||||||
|
TreeNode ndCurrent = m_SelectedNode;
|
||||||
|
while( ( ndCurrent.NextVisibleNode != null ) )
|
||||||
|
{
|
||||||
|
ndCurrent = ndCurrent.NextVisibleNode;
|
||||||
|
if( ndCurrent.Text.StartsWith( sSearch ) )
|
||||||
|
{
|
||||||
|
SelectSingleNode( ndCurrent );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
HandleException( ex );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.EndUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Helper Methods
|
||||||
|
|
||||||
|
private void SelectNode( TreeNode node )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.BeginUpdate();
|
||||||
|
|
||||||
|
if( m_SelectedNode == null || ModifierKeys == Keys.Control )
|
||||||
|
{
|
||||||
|
// Ctrl+Click selects an unselected node, or unselects a selected node.
|
||||||
|
bool bIsSelected = m_SelectedNodes.Contains( node );
|
||||||
|
ToggleNode( node, !bIsSelected );
|
||||||
|
}
|
||||||
|
else if( ModifierKeys == Keys.Shift )
|
||||||
|
{
|
||||||
|
// Shift+Click selects nodes between the selected node and here.
|
||||||
|
TreeNode ndStart = m_SelectedNode;
|
||||||
|
TreeNode ndEnd = node;
|
||||||
|
|
||||||
|
if( ndStart.Parent == ndEnd.Parent )
|
||||||
|
{
|
||||||
|
// Selected node and clicked node have same parent, easy case.
|
||||||
|
if( ndStart.Index < ndEnd.Index )
|
||||||
|
{
|
||||||
|
// If the selected node is beneath the clicked node walk down
|
||||||
|
// selecting each Visible node until we reach the end.
|
||||||
|
while( ndStart != ndEnd )
|
||||||
|
{
|
||||||
|
ndStart = ndStart.NextVisibleNode;
|
||||||
|
if( ndStart == null ) break;
|
||||||
|
ToggleNode( ndStart, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( ndStart.Index == ndEnd.Index )
|
||||||
|
{
|
||||||
|
// Clicked same node, do nothing
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the selected node is above the clicked node walk up
|
||||||
|
// selecting each Visible node until we reach the end.
|
||||||
|
while( ndStart != ndEnd )
|
||||||
|
{
|
||||||
|
ndStart = ndStart.PrevVisibleNode;
|
||||||
|
if( ndStart == null ) break;
|
||||||
|
ToggleNode( ndStart, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Selected node and clicked node have same parent, hard case.
|
||||||
|
// We need to find a common parent to determine if we need
|
||||||
|
// to walk down selecting, or walk up selecting.
|
||||||
|
|
||||||
|
TreeNode ndStartP = ndStart;
|
||||||
|
TreeNode ndEndP = ndEnd;
|
||||||
|
int startDepth = Math.Min( ndStartP.Level, ndEndP.Level );
|
||||||
|
|
||||||
|
// Bring lower node up to common depth
|
||||||
|
while( ndStartP.Level > startDepth )
|
||||||
|
{
|
||||||
|
ndStartP = ndStartP.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bring lower node up to common depth
|
||||||
|
while( ndEndP.Level > startDepth )
|
||||||
|
{
|
||||||
|
ndEndP = ndEndP.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk up the tree until we find the common parent
|
||||||
|
while( ndStartP.Parent != ndEndP.Parent )
|
||||||
|
{
|
||||||
|
ndStartP = ndStartP.Parent;
|
||||||
|
ndEndP = ndEndP.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the node
|
||||||
|
if( ndStartP.Index < ndEndP.Index )
|
||||||
|
{
|
||||||
|
// If the selected node is beneath the clicked node walk down
|
||||||
|
// selecting each Visible node until we reach the end.
|
||||||
|
while( ndStart != ndEnd )
|
||||||
|
{
|
||||||
|
ndStart = ndStart.NextVisibleNode;
|
||||||
|
if( ndStart == null ) break;
|
||||||
|
ToggleNode( ndStart, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( ndStartP.Index == ndEndP.Index )
|
||||||
|
{
|
||||||
|
if( ndStart.Level < ndEnd.Level )
|
||||||
|
{
|
||||||
|
while( ndStart != ndEnd )
|
||||||
|
{
|
||||||
|
ndStart = ndStart.NextVisibleNode;
|
||||||
|
if( ndStart == null ) break;
|
||||||
|
ToggleNode( ndStart, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while( ndStart != ndEnd )
|
||||||
|
{
|
||||||
|
ndStart = ndStart.PrevVisibleNode;
|
||||||
|
if( ndStart == null ) break;
|
||||||
|
ToggleNode( ndStart, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the selected node is above the clicked node walk up
|
||||||
|
// selecting each Visible node until we reach the end.
|
||||||
|
while( ndStart != ndEnd )
|
||||||
|
{
|
||||||
|
ndStart = ndStart.PrevVisibleNode;
|
||||||
|
if( ndStart == null ) break;
|
||||||
|
ToggleNode( ndStart, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Just clicked a node, select it
|
||||||
|
SelectSingleNode( node );
|
||||||
|
}
|
||||||
|
|
||||||
|
OnAfterSelect( new TreeViewEventArgs( m_SelectedNode ) );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.EndUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearSelectedNodes()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach( TreeNode node in m_SelectedNodes )
|
||||||
|
{
|
||||||
|
node.BackColor = this.BackColor;
|
||||||
|
node.ForeColor = this.ForeColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
m_SelectedNodes.Clear();
|
||||||
|
m_SelectedNode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectSingleNode( TreeNode node )
|
||||||
|
{
|
||||||
|
if( node == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearSelectedNodes();
|
||||||
|
ToggleNode( node, true );
|
||||||
|
node.EnsureVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleNode( TreeNode node, bool bSelectNode )
|
||||||
|
{
|
||||||
|
if( bSelectNode )
|
||||||
|
{
|
||||||
|
m_SelectedNode = node;
|
||||||
|
if( !m_SelectedNodes.Contains( node ) )
|
||||||
|
{
|
||||||
|
m_SelectedNodes.Add( node );
|
||||||
|
}
|
||||||
|
node.BackColor = SystemColors.Highlight;
|
||||||
|
node.ForeColor = SystemColors.HighlightText;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_SelectedNodes.Remove( node );
|
||||||
|
node.BackColor = this.BackColor;
|
||||||
|
node.ForeColor = this.ForeColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleException( Exception ex )
|
||||||
|
{
|
||||||
|
// Perform some error handling here.
|
||||||
|
// We don't want to bubble errors to the CLR.
|
||||||
|
MessageBox.Show( ex.Message );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
4
Windows/MainForm.Designer.cs
generated
4
Windows/MainForm.Designer.cs
generated
|
@ -41,7 +41,7 @@
|
||||||
this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
|
this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
this.searchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
this.searchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this._nodeTree = new System.Windows.Forms.TreeView();
|
this._nodeTree = new NBTExplorer.Vendor.MultiSelectTreeView.MultiSelectTreeView();
|
||||||
this.imageList1 = new System.Windows.Forms.ImageList(this.components);
|
this.imageList1 = new System.Windows.Forms.ImageList(this.components);
|
||||||
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
|
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
|
||||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
|
@ -697,7 +697,7 @@
|
||||||
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
|
||||||
private System.Windows.Forms.ToolStripMenuItem searchToolStripMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem searchToolStripMenuItem;
|
||||||
private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem;
|
||||||
private System.Windows.Forms.TreeView _nodeTree;
|
private NBTExplorer.Vendor.MultiSelectTreeView.MultiSelectTreeView _nodeTree;
|
||||||
private System.Windows.Forms.ToolStrip toolStrip1;
|
private System.Windows.Forms.ToolStrip toolStrip1;
|
||||||
private System.Windows.Forms.ToolStripButton _buttonOpen;
|
private System.Windows.Forms.ToolStripButton _buttonOpen;
|
||||||
private System.Windows.Forms.ToolStripButton _buttonSave;
|
private System.Windows.Forms.ToolStripButton _buttonSave;
|
||||||
|
|
|
@ -413,6 +413,294 @@ namespace NBTExplorer.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DeleteNode (IList<TreeNode> nodes)
|
||||||
|
{
|
||||||
|
bool? elideChildren = null;
|
||||||
|
if (!CanOperateOnNodesEx(nodes, DeleteNodePred, out elideChildren))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (elideChildren == true)
|
||||||
|
nodes = ElideChildren(nodes);
|
||||||
|
|
||||||
|
foreach (TreeNode node in nodes) {
|
||||||
|
DataNode dataNode = node.Tag as DataNode;
|
||||||
|
if (dataNode.DeleteNode()) {
|
||||||
|
UpdateNodeText(node.Parent);
|
||||||
|
node.Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private bool CanDeleteNodes (IList<TreeNode> nodes)
|
||||||
|
{
|
||||||
|
bool? elideChildren = null;
|
||||||
|
return CanDeleteNodesEx(nodes, out elideChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CanDeleteNodesEx (IList<TreeNode> nodes, out bool? elideChildren)
|
||||||
|
{
|
||||||
|
GroupCapabilities caps = GroupCapabilities.All;
|
||||||
|
elideChildren = null;
|
||||||
|
|
||||||
|
foreach (TreeNode node in nodes) {
|
||||||
|
if (node == null || !(node.Tag is DataNode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DataNode dataNode = node.Tag as DataNode;
|
||||||
|
if (!dataNode.CanDeleteNode)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
caps &= dataNode.DeleteNodeCapabilities;
|
||||||
|
|
||||||
|
bool elideChildrenFlag = (dataNode.DeleteNodeCapabilities & GroupCapabilities.ElideChildren) == GroupCapabilities.ElideChildren;
|
||||||
|
if (elideChildren == null)
|
||||||
|
elideChildren = elideChildrenFlag;
|
||||||
|
if (elideChildren != elideChildrenFlag)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodes.Count > 1 && !SufficientCapabilities(nodes, caps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
delegate bool DataNodePredicate (DataNode dataNode, out GroupCapabilities caps);
|
||||||
|
|
||||||
|
private bool CreateByteNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_BYTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateShortNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateIntNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateLongNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_LONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateFloatNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_FLOAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateDoubleNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateByteArrayNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_BYTE_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateIntArrayNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_INT_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateStringNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateListNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateCompoundNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_COMPOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RenameNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.RenameNodeCapabilities;
|
||||||
|
return (dataNode != null) && dataNode.CanRenameNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool EditNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.EditNodeCapabilities;
|
||||||
|
return (dataNode != null) && dataNode.CanEditNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DeleteNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.DeleteNodeCapabilities;
|
||||||
|
return (dataNode != null) && dataNode.CanDeleteNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CutNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.CutNodeCapabilities;
|
||||||
|
return (dataNode != null) && dataNode.CanCutNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CopyNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.CopyNodeCapabilities;
|
||||||
|
return (dataNode != null) && dataNode.CanCopyNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool PasteIntoNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.PasteIntoNodeCapabilities;
|
||||||
|
return (dataNode != null) && dataNode.CanPasteIntoNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SearchNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.SearchNodeCapabilites;
|
||||||
|
return (dataNode != null) && dataNode.CanSearchNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ReorderNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.ReorderNodeCapabilities;
|
||||||
|
return (dataNode != null) && dataNode.CanReoderNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RefreshNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = dataNode.RefreshNodeCapabilites;
|
||||||
|
return (dataNode != null) && dataNode.CanRefreshNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private bool CreateTagNodePred (DataNode dataNode, out GroupCapabilities caps)
|
||||||
|
{
|
||||||
|
caps = GroupCapabilities.Single;
|
||||||
|
return (dataNode != null) && dataNode.CanCreateTag
|
||||||
|
}*/
|
||||||
|
|
||||||
|
private bool CanOperateOnNodes (IList<TreeNode> nodes, DataNodePredicate pred)
|
||||||
|
{
|
||||||
|
bool? elideChildren = null;
|
||||||
|
return CanOperateOnNodesEx(nodes, pred, out elideChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CanOperateOnNodesEx (IList<TreeNode> nodes, DataNodePredicate pred, out bool? elideChildren)
|
||||||
|
{
|
||||||
|
GroupCapabilities caps = GroupCapabilities.All;
|
||||||
|
elideChildren = null;
|
||||||
|
|
||||||
|
foreach (TreeNode node in nodes) {
|
||||||
|
if (node == null || !(node.Tag is DataNode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DataNode dataNode = node.Tag as DataNode;
|
||||||
|
GroupCapabilities dataCaps;
|
||||||
|
if (!pred(dataNode, out dataCaps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
caps &= dataCaps;
|
||||||
|
|
||||||
|
bool elideChildrenFlag = (dataNode.DeleteNodeCapabilities & GroupCapabilities.ElideChildren) == GroupCapabilities.ElideChildren;
|
||||||
|
if (elideChildren == null)
|
||||||
|
elideChildren = elideChildrenFlag;
|
||||||
|
if (elideChildren != elideChildrenFlag)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodes.Count > 1 && !SufficientCapabilities(nodes, caps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IList<TreeNode> ElideChildren (IList<TreeNode> nodes)
|
||||||
|
{
|
||||||
|
List<TreeNode> filtered = new List<TreeNode>();
|
||||||
|
|
||||||
|
foreach (TreeNode node in nodes) {
|
||||||
|
TreeNode parent = node.Parent;
|
||||||
|
bool foundParent = false;
|
||||||
|
|
||||||
|
while (parent != null) {
|
||||||
|
if (nodes.Contains(parent)) {
|
||||||
|
foundParent = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parent = parent.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundParent)
|
||||||
|
filtered.Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CommonContainer (IEnumerable<TreeNode> nodes)
|
||||||
|
{
|
||||||
|
object container = null;
|
||||||
|
foreach (TreeNode node in nodes) {
|
||||||
|
DataNode dataNode = node.Tag as DataNode;
|
||||||
|
if (container == null)
|
||||||
|
container = dataNode.Parent;
|
||||||
|
|
||||||
|
if (container != dataNode.Parent)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CommonType (IEnumerable<TreeNode> nodes)
|
||||||
|
{
|
||||||
|
Type datatype = null;
|
||||||
|
foreach (TreeNode node in nodes) {
|
||||||
|
DataNode dataNode = node.Tag as DataNode;
|
||||||
|
if (datatype == null)
|
||||||
|
datatype = dataNode.GetType();
|
||||||
|
|
||||||
|
if (datatype != dataNode.GetType())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SufficientCapabilities (IEnumerable<TreeNode> nodes, GroupCapabilities commonCaps)
|
||||||
|
{
|
||||||
|
bool commonContainer = CommonContainer(nodes);
|
||||||
|
bool commonType = CommonType(nodes);
|
||||||
|
|
||||||
|
bool pass = true;
|
||||||
|
if (commonContainer && commonType)
|
||||||
|
pass &= ((commonCaps & GroupCapabilities.SiblingSameType) == GroupCapabilities.SiblingSameType);
|
||||||
|
else if (commonContainer && !commonType)
|
||||||
|
pass &= ((commonCaps & GroupCapabilities.SiblingMixedType) == GroupCapabilities.SiblingMixedType);
|
||||||
|
else if (!commonContainer && commonType)
|
||||||
|
pass &= ((commonCaps & GroupCapabilities.MultiSameType) == GroupCapabilities.MultiSameType);
|
||||||
|
else if (!commonContainer && !commonType)
|
||||||
|
pass &= ((commonCaps & GroupCapabilities.MultiMixedType) == GroupCapabilities.MultiMixedType);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
private void CopyNode (TreeNode node)
|
private void CopyNode (TreeNode node)
|
||||||
{
|
{
|
||||||
if (node == null || !(node.Tag is DataNode))
|
if (node == null || !(node.Tag is DataNode))
|
||||||
|
@ -685,19 +973,42 @@ namespace NBTExplorer.Windows
|
||||||
private void UpdateUI ()
|
private void UpdateUI ()
|
||||||
{
|
{
|
||||||
TreeNode selected = _nodeTree.SelectedNode;
|
TreeNode selected = _nodeTree.SelectedNode;
|
||||||
if (selected != null && selected.Tag is DataNode) {
|
if (_nodeTree.SelectedNodes.Count > 1) {
|
||||||
|
UpdateUI(_nodeTree.SelectedNodes);
|
||||||
|
}
|
||||||
|
else if (selected != null && selected.Tag is DataNode) {
|
||||||
UpdateUI(selected.Tag as DataNode);
|
UpdateUI(selected.Tag as DataNode);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
DisableButtons(_buttonAddTagByte, _buttonAddTagByteArray, _buttonAddTagCompound, _buttonAddTagDouble, _buttonAddTagFloat,
|
||||||
|
_buttonAddTagInt, _buttonAddTagIntArray, _buttonAddTagList, _buttonAddTagLong, _buttonAddTagShort,
|
||||||
|
_buttonAddTagString, _buttonCopy, _buttonCut, _buttonDelete, _buttonEdit, _buttonPaste, _buttonRefresh,
|
||||||
|
_buttonRename);
|
||||||
|
|
||||||
_buttonSave.Enabled = CheckModifications();
|
_buttonSave.Enabled = CheckModifications();
|
||||||
_buttonFindNext.Enabled = false;
|
_buttonFindNext.Enabled = false;
|
||||||
|
|
||||||
|
DisableMenuItems(_menuItemCopy, _menuItemCut, _menuItemDelete, _menuItemEditValue, _menuItemPaste, _menuItemRefresh,
|
||||||
|
_menuItemRename);
|
||||||
|
|
||||||
_menuItemSave.Enabled = _buttonSave.Enabled;
|
_menuItemSave.Enabled = _buttonSave.Enabled;
|
||||||
_menuItemFind.Enabled = false;
|
_menuItemFind.Enabled = false;
|
||||||
_menuItemFindNext.Enabled = _searchState != null;
|
_menuItemFindNext.Enabled = _searchState != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DisableButtons (params ToolStripButton[] buttons)
|
||||||
|
{
|
||||||
|
foreach (ToolStripButton button in buttons)
|
||||||
|
button.Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisableMenuItems (params ToolStripMenuItem[] buttons)
|
||||||
|
{
|
||||||
|
foreach (ToolStripMenuItem button in buttons)
|
||||||
|
button.Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateUI (DataNode node)
|
private void UpdateUI (DataNode node)
|
||||||
{
|
{
|
||||||
if (node == null)
|
if (node == null)
|
||||||
|
@ -736,6 +1047,47 @@ namespace NBTExplorer.Windows
|
||||||
_menuItemRefresh.Enabled = node.CanRefreshNode;
|
_menuItemRefresh.Enabled = node.CanRefreshNode;
|
||||||
_menuItemFind.Enabled = node.CanSearchNode;
|
_menuItemFind.Enabled = node.CanSearchNode;
|
||||||
_menuItemFindNext.Enabled = _searchState != null;
|
_menuItemFindNext.Enabled = _searchState != null;
|
||||||
|
|
||||||
|
UpdateUI(_nodeTree.SelectedNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateUI (IList<TreeNode> nodes)
|
||||||
|
{
|
||||||
|
if (nodes == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_buttonAddTagByte.Enabled = CanOperateOnNodes(nodes, CreateByteNodePred);
|
||||||
|
_buttonAddTagShort.Enabled = CanOperateOnNodes(nodes, CreateShortNodePred);
|
||||||
|
_buttonAddTagInt.Enabled = CanOperateOnNodes(nodes, CreateIntNodePred);
|
||||||
|
_buttonAddTagLong.Enabled = CanOperateOnNodes(nodes, CreateLongNodePred);
|
||||||
|
_buttonAddTagFloat.Enabled = CanOperateOnNodes(nodes, CreateFloatNodePred);
|
||||||
|
_buttonAddTagDouble.Enabled = CanOperateOnNodes(nodes, CreateDoubleNodePred);
|
||||||
|
_buttonAddTagByteArray.Enabled = CanOperateOnNodes(nodes, CreateByteArrayNodePred);
|
||||||
|
_buttonAddTagIntArray.Enabled = CanOperateOnNodes(nodes, CreateIntArrayNodePred);
|
||||||
|
_buttonAddTagString.Enabled = CanOperateOnNodes(nodes, CreateStringNodePred);
|
||||||
|
_buttonAddTagList.Enabled = CanOperateOnNodes(nodes, CreateListNodePred);
|
||||||
|
_buttonAddTagCompound.Enabled = CanOperateOnNodes(nodes, CreateCompoundNodePred);
|
||||||
|
|
||||||
|
_buttonSave.Enabled = CheckModifications();
|
||||||
|
_buttonRename.Enabled = CanOperateOnNodes(nodes, RenameNodePred);
|
||||||
|
_buttonEdit.Enabled = CanOperateOnNodes(nodes, EditNodePred);
|
||||||
|
_buttonDelete.Enabled = CanOperateOnNodes(nodes, DeleteNodePred);
|
||||||
|
_buttonCut.Enabled = CanOperateOnNodes(nodes, CutNodePred) && NbtClipboardController.IsInitialized; ;
|
||||||
|
_buttonCopy.Enabled = CanOperateOnNodes(nodes, CopyNodePred) && NbtClipboardController.IsInitialized; ;
|
||||||
|
_buttonPaste.Enabled = CanOperateOnNodes(nodes, PasteIntoNodePred) && NbtClipboardController.IsInitialized; ;
|
||||||
|
_buttonFindNext.Enabled = CanOperateOnNodes(nodes, SearchNodePred) || _searchState != null;
|
||||||
|
_buttonRefresh.Enabled = CanOperateOnNodes(nodes, RefreshNodePred);
|
||||||
|
|
||||||
|
_menuItemSave.Enabled = _buttonSave.Enabled;
|
||||||
|
_menuItemRename.Enabled = _buttonRename.Enabled;
|
||||||
|
_menuItemEditValue.Enabled = _buttonEdit.Enabled;
|
||||||
|
_menuItemDelete.Enabled = _buttonDelete.Enabled;
|
||||||
|
_menuItemCut.Enabled = _buttonCut.Enabled;
|
||||||
|
_menuItemCopy.Enabled = _buttonCopy.Enabled;
|
||||||
|
_menuItemPaste.Enabled = _buttonPaste.Enabled;
|
||||||
|
_menuItemFind.Enabled = CanOperateOnNodes(nodes, SearchNodePred);
|
||||||
|
_menuItemRefresh.Enabled = _buttonRefresh.Enabled;
|
||||||
|
_menuItemFindNext.Enabled = _searchState != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateOpenMenu ()
|
private void UpdateOpenMenu ()
|
||||||
|
@ -786,6 +1138,23 @@ namespace NBTExplorer.Windows
|
||||||
list.Insert(0, entry);
|
list.Insert(0, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GroupCapabilities CommonCapabilities (IEnumerable<GroupCapabilities> capabilities)
|
||||||
|
{
|
||||||
|
GroupCapabilities caps = GroupCapabilities.All;
|
||||||
|
foreach (GroupCapabilities cap in capabilities)
|
||||||
|
caps &= cap;
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ActionDeleteNode ()
|
||||||
|
{
|
||||||
|
DeleteNode(_nodeTree.SelectedNodes);
|
||||||
|
|
||||||
|
_nodeTree.SelectedNodes.Clear();
|
||||||
|
_nodeTree.SelectedNode = null;
|
||||||
|
UpdateUI();
|
||||||
|
}
|
||||||
|
|
||||||
#region Event Handlers
|
#region Event Handlers
|
||||||
|
|
||||||
private void MainForm_Closing (object sender, CancelEventArgs e)
|
private void MainForm_Closing (object sender, CancelEventArgs e)
|
||||||
|
@ -867,7 +1236,7 @@ namespace NBTExplorer.Windows
|
||||||
|
|
||||||
private void _buttonDelete_Click (object sender, EventArgs e)
|
private void _buttonDelete_Click (object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
DeleteNode(_nodeTree.SelectedNode);
|
ActionDeleteNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _buttonCopy_Click (object sernder, EventArgs e)
|
private void _buttonCopy_Click (object sernder, EventArgs e)
|
||||||
|
@ -995,7 +1364,7 @@ namespace NBTExplorer.Windows
|
||||||
|
|
||||||
private void _menuItemDelete_Click (object sender, EventArgs e)
|
private void _menuItemDelete_Click (object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
DeleteNode(_nodeTree.SelectedNode);
|
ActionDeleteNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _menuItemCopy_Click (object sender, EventArgs e)
|
private void _menuItemCopy_Click (object sender, EventArgs e)
|
||||||
|
|
Loading…
Reference in a new issue