//
//
//
//
// $Revision$
//
using System;
using System.Drawing;
using System.Windows.Forms;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.TextEditor
{
public class TextAreaDragDropHandler
{
public static Action OnDragDropException = ex => MessageBox.Show(ex.ToString());
TextArea textArea;
public void Attach(TextArea textArea)
{
this.textArea = textArea;
textArea.AllowDrop = true;
textArea.DragEnter += MakeDragEventHandler(OnDragEnter);
textArea.DragDrop += MakeDragEventHandler(OnDragDrop);
textArea.DragOver += MakeDragEventHandler(OnDragOver);
}
///
/// Create a drag'n'drop event handler.
/// Windows Forms swallows unhandled exceptions during drag'n'drop, so we report them here.
///
static DragEventHandler MakeDragEventHandler(DragEventHandler h)
{
return (sender, e) => {
try {
h(sender, e);
} catch (Exception ex) {
OnDragDropException(ex);
}
};
}
static DragDropEffects GetDragDropEffect(DragEventArgs e)
{
if ((e.AllowedEffect & DragDropEffects.Move) > 0 &&
(e.AllowedEffect & DragDropEffects.Copy) > 0) {
return (e.KeyState & 8) > 0 ? DragDropEffects.Copy : DragDropEffects.Move;
} else if ((e.AllowedEffect & DragDropEffects.Move) > 0) {
return DragDropEffects.Move;
} else if ((e.AllowedEffect & DragDropEffects.Copy) > 0) {
return DragDropEffects.Copy;
}
return DragDropEffects.None;
}
protected void OnDragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string))) {
e.Effect = GetDragDropEffect(e);
}
}
void InsertString(int offset, string str)
{
textArea.Document.Insert(offset, str);
textArea.SelectionManager.SetSelection(new DefaultSelection(textArea.Document,
textArea.Document.OffsetToPosition(offset),
textArea.Document.OffsetToPosition(offset + str.Length)));
textArea.Caret.Position = textArea.Document.OffsetToPosition(offset + str.Length);
textArea.Refresh();
}
protected void OnDragDrop(object sender, DragEventArgs e)
{
Point p = textArea.PointToClient(new Point(e.X, e.Y));
if (e.Data.GetDataPresent(typeof(string))) {
textArea.BeginUpdate();
textArea.Document.UndoStack.StartUndoGroup();
try {
int offset = textArea.Caret.Offset;
if (textArea.IsReadOnly(offset)) {
// prevent dragging text into readonly section
return;
}
if (e.Data.GetDataPresent(typeof(DefaultSelection))) {
ISelection sel = (ISelection)e.Data.GetData(typeof(DefaultSelection));
if (sel.ContainsPosition(textArea.Caret.Position)) {
return;
}
if (GetDragDropEffect(e) == DragDropEffects.Move) {
if (SelectionManager.SelectionIsReadOnly(textArea.Document, sel)) {
// prevent dragging text out of readonly section
return;
}
int len = sel.Length;
textArea.Document.Remove(sel.Offset, len);
if (sel.Offset < offset) {
offset -= len;
}
}
}
textArea.SelectionManager.ClearSelection();
InsertString(offset, (string)e.Data.GetData(typeof(string)));
textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
} finally {
textArea.Document.UndoStack.EndUndoGroup();
textArea.EndUpdate();
}
}
}
protected void OnDragOver(object sender, DragEventArgs e)
{
if (!textArea.Focused) {
textArea.Focus();
}
Point p = textArea.PointToClient(new Point(e.X, e.Y));
if (textArea.TextView.DrawingPosition.Contains(p.X, p.Y)) {
TextLocation realmousepos= textArea.TextView.GetLogicalPosition(p.X - textArea.TextView.DrawingPosition.X,
p.Y - textArea.TextView.DrawingPosition.Y);
int lineNr = Math.Min(textArea.Document.TotalNumberOfLines - 1, Math.Max(0, realmousepos.Y));
textArea.Caret.Position = new TextLocation(realmousepos.X, lineNr);
textArea.SetDesiredColumn();
if (e.Data.GetDataPresent(typeof(string)) && !textArea.IsReadOnly(textArea.Caret.Offset)) {
e.Effect = GetDragDropEffect(e);
} else {
e.Effect = DragDropEffects.None;
}
} else {
e.Effect = DragDropEffects.None;
}
}
}
}