// Copyright � 2006 by Christoph Richner. All rights are reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// website http://www.raccoom.net, email support@raccoom.net, msn chrisdarebell@msn.com
using System;
using System.Windows.Forms;
using System.Drawing;
namespace Raccoom.Windows.Forms
{
/// <summary>
/// Drag'n'Drop Hyperlink from Webbrowser to a control.
/// </summary>
public class TreeViewDragDropHyperlink
{
#region fields
#region delegate
public class UrlDragDropEventArgs : EventArgs
{
private Uri _uri;
public UrlDragDropEventArgs(Uri uri)
{
this._uri = uri;
}
public Uri Uri
{
get
{
return _uri;
}
}
}
public delegate void UrlDragDropDelegate(object sender, UrlDragDropEventArgs e);
#endregion
public UrlDragDropDelegate UrlDragDrop;
#endregion
#region constructors
public TreeViewDragDropHyperlink(System.Windows.Forms.Control control)
{
System.Diagnostics.Debug.Assert(control!=null);
//
control.AllowDrop = true;
control.DragEnter += new System.Windows.Forms.DragEventHandler(OnDragEnter);
control.DragDrop +=new System.Windows.Forms.DragEventHandler(OnDragDrop);
}
#endregion
#region public interface
/// <summary>
/// Allow draging of UniformResourceLocator (Hyperlinks)
/// </summary>
private void OnDragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
if(e.Data.GetData("UniformResourceLocator",true)!=null)
{
e.Effect = System.Windows.Forms.DragDropEffects.Link;
}
else
{
e.Effect = System.Windows.Forms.DragDropEffects.None;
}
}
/// <summary>
/// If valid UniformResourceLocator was dropped, load it
/// </summary>
private void OnDragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
// FileContents
// UniformResourceLocator
//
try
{
string url = e.Data.GetData(typeof(string)) as string;
// some browser deliver url and text in UniformResourceLocator
string[] tokens =url.Split('\n');
if(tokens.Length>1)
{
url= tokens[0];
}
//
if(UrlDragDrop!=null) UrlDragDrop(this, new UrlDragDropEventArgs(new Uri(url)));
}
catch (System.Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
#endregion
}
/// <summary>
/// Mimic the "Windows" (tm) way and implement a placeholder letting the user know where the item will be dropped.
/// </summary>
/// <remarks>Copyright by Gabe Anguiano, http://www.codeproject.com/cs/miscctrl/TreeViewReArr.asp</remarks>
public class TreeViewDragDropRearrange
{
#region fields
private string _nodeMap;
private TreeView _treeView;
#endregion
#region public constructors
public TreeViewDragDropRearrange(TreeView treeView)
{
System.Diagnostics.Debug.Assert(treeView!=null);
//
_treeView = treeView;
_treeView.MouseDown += new MouseEventHandler(treeView1_MouseDown);
_treeView.ItemDrag += new ItemDragEventHandler(treeView1_ItemDrag);
_treeView.DragEnter += new DragEventHandler(treeView1_DragEnter);
_treeView.DragDrop += new DragEventHandler(treeView1_DragDrop);
_treeView.DragOver += new DragEventHandler(treeView1_DragOver);
}
#endregion
#region private interface
private void treeView1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
_treeView.SelectedNode = _treeView.GetNodeAt(e.X, e.Y);
}
private void treeView1_ItemDrag(object sender, System.Windows.Forms.ItemDragEventArgs e)
{
_treeView.DoDragDrop(e.Item, DragDropEffects.Move);
}
private void treeView1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void treeView1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
if(e.Data.GetDataPresent("System.Windows.Forms.TreeNode", false) && _nodeMap != "")
{
TreeNode MovingNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");
string[] NodeIndexes = _nodeMap.Split('|');
TreeNodeCollection InsertCollection = _treeView.Nodes;
for(int i = 0; i < NodeIndexes.Length - 1; i++)
{
InsertCollection = InsertCollection[Int32.Parse(NodeIndexes[i])].Nodes;
}
if(InsertCollection != null)
{
InsertCollection.Insert(Int32.Parse(NodeIndexes[NodeIndexes.Length - 1]), (TreeNode)MovingNode.Clone());
_treeView.SelectedNode = InsertCollection[Int32.Parse(NodeIndexes[NodeIndexes.Length - 1])];
MovingNode.Remove();
}
}
}
private void treeView1_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
{
TreeNode NodeOver = _treeView.GetNodeAt(_treeView.PointToClient(Cursor.Position));
TreeNode NodeMoving = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");
// A bit long, but to summarize, process the following coe only if the nodeover is null
// and either the nodeover is not the same thing as nodemoving UNLESSS nodeover happens
// to be the last node in the branch (so we can allow drag & drop below a parent branch)
if(NodeOver != null && (NodeOver != NodeMoving || (NodeOver.Parent != null && NodeOver.Index == (NodeOver.Parent.Nodes.Count - 1))))
{
int OffsetY = _treeView.PointToClient(Cursor.Position).Y - NodeOver.Bounds.Top;
int NodeOverImageWidth = _treeView.ImageList.Images[NodeOver.ImageIndex].Size.Width + 8;
Graphics g = _treeView.CreateGraphics();
// Image index of 1 is the non-folder icon
if(NodeOver.ImageIndex == 1)
{
#region Standard Node
if(OffsetY < (NodeOver.Bounds.Height / 2))
{
//this.lblDebug.Text = "top";
#region If NodeOver is a child then cancel
TreeNode tnParadox = NodeOver;
while(tnParadox.Parent != null)
{
if(tnParadox.Parent == NodeMoving)
{
this._nodeMap = "";
return;
}
tnParadox = tnParadox.Parent;
}
#endregion
#region Store the placeholder info into a pipe delimited string
TreeNode tnPlaceholderInfo = NodeOver;
string NewNodeMap = ((int)NodeOver.Index).ToString();
while(tnPlaceholderInfo.Parent != null)
{
tnPlaceholderInfo = tnPlaceholderInfo.Parent;
NewNodeMap = tnPlaceholderInfo.Index + "|" + NewNodeMap;
}
if(NewNodeMap == this._nodeMap)
return;
else
this._nodeMap = NewNodeMap;
#endregion
#region Clear placeholders above and below
_treeView.Refresh();
#endregion
#region Draw the placeholders
int LeftPos, RightPos;
LeftPos = NodeOver.Bounds.Left - NodeOverImageWidth;
RightPos = _treeView.Width - 4;
Point[] LeftTriangle = new Point[5]{
new Point(LeftPos, NodeOver.Bounds.Top - 4),
new Point(LeftPos, NodeOver.Bounds.Top + 4),
new Point(LeftPos + 4, NodeOver.Bounds.Y),
new Point(LeftPos + 4, NodeOver.Bounds.Top - 1),
new Point(LeftPos, NodeOver.Bounds.Top - 5)};
Point[] RightTriangle = new Point[5]{
new Point(RightPos, NodeOver.Bounds.Top - 4),
new Point(RightPos, NodeOver.Bounds.Top + 4),
new Point(RightPos - 4, NodeOver.Bounds.Y),
new Point(RightPos - 4, NodeOver.Bounds.Top - 1),
new Point(RightPos, NodeOver.Bounds.Top - 5)};
g.FillPolygon(System.Drawing.Brushes.Black, LeftTriangle);
g.FillPolygon(System.Drawing.Brushes.Black, RightTriangle);
g.DrawLine(new System.Drawing.Pen(Color.Black, 2), new Point(LeftPos, NodeOver.Bounds.Top), new Point(RightPos, NodeOver.Bounds.Top));
#endregion
}
else
{
//this.lblDebug.Text = "bottom";
#region If NodeOver is a child then cancel
TreeNode tnParadox = NodeOver;
while(tnParadox.Parent != null)
{
if(tnParadox.Parent == NodeMoving)
{
this._nodeMap = "";
return;
}
tnParadox = tnParadox.Parent;
}
#endregion
#region Allow drag drop to parent branches
TreeNode ParentDragDrop = null;
// If the node the mouse is over is the last node of the branch we should allow
// the ability to drop the "nodemoving" node BELOW the parent node
if(NodeOver.Parent != null && NodeOver.Index == (NodeOver.Parent.Nodes.Count - 1))
{
int XPos = _treeView.PointToClient(Cursor.Position).X;
if(XPos < NodeOver.Bounds.Left)
{
ParentDragDrop = NodeOver.Parent;
while(true)
{
if(XPos > (ParentDragDrop.Bounds.Left - _treeView.ImageList.Images[ParentDragDrop.ImageIndex].Size.Width))
break;
if(ParentDragDrop.Parent != null)
ParentDragDrop = ParentDragDrop.Parent;
else
break;
}
}
}
#endregion
#region Store the placeholder info into a pipe delimited string
// Since we are in a special case here, use the ParentDragDrop node as the current "nodeover"
TreeNode tnPlaceholderInfo;
if(ParentDragDrop != null)
tnPlaceholderInfo = ParentDragDrop;
else
tnPlaceholderInfo = NodeOver;
string NewNodeMap = ((int)tnPlaceholderInfo.Index + 1).ToString();
while(tnPlaceholderInfo.Parent != null)
{
tnPlaceholderInfo = tnPlaceholderInfo.Parent;
NewNodeMap = tnPlaceholderInfo.Index + "|" + NewNodeMap;
}
if(NewNodeMap == this._nodeMap)
return;
else
this._nodeMap = NewNodeMap;
#endregion
#region Clear placeholders above and below
_treeView.Refresh();
#endregion
#region Draw the placeholders
// Once again, we are not dragging to node over, draw the placeholder using the ParentDragDrop bounds
int LeftPos, RightPos;
if(ParentDragDrop != null)
LeftPos = ParentDragDrop.Bounds.Left - (_treeView.ImageList.Images[ParentDragDrop.ImageIndex].Size.Width + 8);
else
LeftPos = NodeOver.Bounds.Left - NodeOverImageWidth;
RightPos = _treeView.Width - 4;
Point[] LeftTriangle = new Point[5]{
new Point(LeftPos, NodeOver.Bounds.Bottom - 4),
new Point(LeftPos, NodeOver.Bounds.Bottom + 4),
new Point(LeftPos + 4, NodeOver.Bounds.Bottom),
new Point(LeftPos + 4, NodeOver.Bounds.Bottom - 1),
new Point(LeftPos, NodeOver.Bounds.Bottom - 5)};
Point[] RightTriangle = new Point[5]{
new Point(RightPos, NodeOver.Bounds.Bottom - 4),
new Point(RightPos, NodeOver.Bounds.Bottom + 4),
new Point(RightPos - 4, NodeOver.Bounds.Bottom),
new Point(RightPos - 4, NodeOver.Bounds.Bottom - 1),
new Point(RightPos, NodeOver.Bounds.Bottom - 5)};
g.FillPolygon(System.Drawing.Brushes.Black, LeftTriangle);
g.FillPolygon(System.Drawing.Brushes.Black, RightTriangle);
g.DrawLine(new System.Drawing.Pen(Color.Black, 2), new Point(LeftPos, NodeOver.Bounds.Bottom), new Point(RightPos, NodeOver.Bounds.Bottom));
#endregion
}
#endregion
}
else
{
#region Folder Node
if(OffsetY < (NodeOver.Bounds.Height / 3))
{
//this.lblDebug.Text = "folder top";
#region If NodeOver is a child then cancel
TreeNode tnParadox = NodeOver;
while(tnParadox.Parent != null)
{
if(tnParadox.Parent == NodeMoving)
{
this._nodeMap = "";
return;
}
tnParadox = tnParadox.Parent;
}
#endregion
#region Store the placeholder info into a pipe delimited string
TreeNode tnPlaceholderInfo = NodeOver;
string NewNodeMap = ((int)NodeOver.Index).ToString();
while(tnPlaceholderInfo.Parent != null)
{
tnPlaceholderInfo = tnPlaceholderInfo.Parent;
NewNodeMap = tnPlaceholderInfo.Index + "|" + NewNodeMap;
}
if(NewNodeMap == this._nodeMap)
return;
else
this._nodeMap = NewNodeMap;
#endregion
#region Clear placeholders above and below
_treeView.Refresh();
#endregion
#region Draw the placeholders
int LeftPos, RightPos;
LeftPos = NodeOver.Bounds.Left - NodeOverImageWidth;
RightPos = _treeView.Width - 4;
Point[] LeftTriangle = new Point[5]{
new Point(LeftPos, NodeOver.Bounds.Top - 4),
new Point(LeftPos, NodeOver.Bounds.Top + 4),
new Point(LeftPos + 4, NodeOver.Bounds.Y),
new Point(LeftPos + 4, NodeOver.Bounds.Top - 1),
new Point(LeftPos, NodeOver.Bounds.Top - 5)};
Point[] RightTriangle = new Point[5]{
new Point(RightPos, NodeOver.Bounds.Top - 4),
new Point(RightPos, NodeOver.Bounds.Top + 4),
new Point(RightPos - 4, NodeOver.Bounds.Y),
new Point(RightPos - 4, NodeOver.Bounds.Top - 1),
new Point(RightPos, NodeOver.Bounds.Top - 5)};
g.FillPolygon(System.Drawing.Brushes.Black, LeftTriangle);
g.FillPolygon(System.Drawing.Brushes.Black, RightTriangle);
g.DrawLine(new System.Drawing.Pen(Color.Black, 2), new Point(LeftPos, NodeOver.Bounds.Top), new Point(RightPos, NodeOver.Bounds.Top));
#endregion
}
else if((NodeOver.Parent != null && NodeOver.Index == 0) && (OffsetY > (NodeOver.Bounds.Height - (NodeOver.Bounds.Height / 3))))
{
//this.lblDebug.Text = "folder bottom";
#region If NodeOver is a child then cancel
TreeNode tnParadox = NodeOver;
while(tnParadox.Parent != null)
{
if(tnParadox.Parent == NodeMoving)
{
this._nodeMap = "";
return;
}
tnParadox = tnParadox.Parent;
}
#endregion
#region Store the placeholder info into a pipe delimited string
TreeNode tnPlaceholderInfo = NodeOver;
string NewNodeMap = ((int)NodeOver.Index + 1).ToString();
while(tnPlaceholderInfo.Parent != null)
{
tnPlaceholderInfo = tnPlaceholderInfo.Parent;
NewNodeMap = tnPlaceholderInfo.Index + "|" + NewNodeMap;
}
if(NewNodeMap == this._nodeMap)
return;
else
this._nodeMap = NewNodeMap;
#endregion
#region Clear placeholders above and below
_treeView.Refresh();
#endregion
#region Draw the placeholders
int LeftPos, RightPos;
LeftPos = NodeOver.Bounds.Left - NodeOverImageWidth;
RightPos = _treeView.Width - 4;
Point[] LeftTriangle = new Point[5]{
new Point(LeftPos, NodeOver.Bounds.Bottom - 4),
new Point(LeftPos, NodeOver.Bounds.Bottom + 4),
new Point(LeftPos + 4, NodeOver.Bounds.Bottom),
new Point(LeftPos + 4, NodeOver.Bounds.Bottom - 1),
new Point(LeftPos, NodeOver.Bounds.Bottom - 5)};
Point[] RightTriangle = new Point[5]{
new Point(RightPos, NodeOver.Bounds.Bottom - 4),
new Point(RightPos, NodeOver.Bounds.Bottom + 4),
new Point(RightPos - 4, NodeOver.Bounds.Bottom),
new Point(RightPos - 4, NodeOver.Bounds.Bottom - 1),
new Point(RightPos, NodeOver.Bounds.Bottom - 5)};
g.FillPolygon(System.Drawing.Brushes.Black, LeftTriangle);
g.FillPolygon(System.Drawing.Brushes.Black, RightTriangle);
g.DrawLine(new System.Drawing.Pen(Color.Black, 2), new Point(LeftPos, NodeOver.Bounds.Bottom), new Point(RightPos, NodeOver.Bounds.Bottom));
#endregion
}
else
{
//this.lblDebug.Text = "folder over";
if(NodeOver.Nodes.Count > 0)
{
NodeOver.Expand();
//this.Refresh();
}
else
{
#region Prevent the node from being dragged onto itself
if(NodeMoving == NodeOver)
return;
#endregion
#region If NodeOver is a child then cancel
TreeNode tnParadox = NodeOver;
while(tnParadox.Parent != null)
{
if(tnParadox.Parent == NodeMoving)
{
this._nodeMap = "";
return;
}
tnParadox = tnParadox.Parent;
}
#endregion
#region Store the placeholder info into a pipe delimited string
TreeNode tnPlaceholderInfo = NodeOver;
string NewNodeMap = ((int)NodeOver.Index).ToString();
while(tnPlaceholderInfo.Parent != null)
{
tnPlaceholderInfo = tnPlaceholderInfo.Parent;
NewNodeMap = tnPlaceholderInfo.Index + "|" + NewNodeMap;
}
NewNodeMap = NewNodeMap + "|0";
if(NewNodeMap == this._nodeMap)
return;
else
this._nodeMap = NewNodeMap;
#endregion
#region Clear placeholders above and below
_treeView.Refresh();
#endregion
#region Draw the "add to folder" placeholder
int RightPos = NodeOver.Bounds.Right + 6;
Point[] RightTriangle = new Point[5]{
new Point(RightPos, NodeOver.Bounds.Y + (NodeOver.Bounds.Height / 2) + 4),
new Point(RightPos, NodeOver.Bounds.Y + (NodeOver.Bounds.Height / 2) + 4),
new Point(RightPos - 4, NodeOver.Bounds.Y + (NodeOver.Bounds.Height / 2)),
new Point(RightPos - 4, NodeOver.Bounds.Y + (NodeOver.Bounds.Height / 2) - 1),
new Point(RightPos, NodeOver.Bounds.Y + (NodeOver.Bounds.Height / 2) - 5)};
_treeView.Refresh();
g.FillPolygon(System.Drawing.Brushes.Black, RightTriangle);
#endregion
}
}
#endregion
}
}
}
#endregion
}
}