You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
6.7 KiB
182 lines
6.7 KiB
// <file>
|
|
// <copyright see="prj:///doc/copyright.txt"/>
|
|
// <license see="prj:///doc/license.txt"/>
|
|
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
|
// <version>$Revision$</version>
|
|
// </file>
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using ICSharpCode.TextEditor.Document;
|
|
|
|
namespace ICSharpCode.TextEditor
|
|
{
|
|
public class TextAreaDragDropHandler
|
|
{
|
|
public static Action<Exception> OnDragDropException = ex => MessageBox.Show(ex.ToString());
|
|
|
|
private 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a drag'n'drop event handler.
|
|
/// Windows Forms swallows unhandled exceptions during drag'n'drop, so we report them here.
|
|
/// </summary>
|
|
private static DragEventHandler MakeDragEventHandler(DragEventHandler h)
|
|
{
|
|
return (sender, e) =>
|
|
{
|
|
try
|
|
{
|
|
h(sender, e);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
OnDragDropException(ex);
|
|
}
|
|
};
|
|
}
|
|
|
|
private 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;
|
|
|
|
if ((e.AllowedEffect & DragDropEffects.Move) > 0)
|
|
return DragDropEffects.Move;
|
|
|
|
if ((e.AllowedEffect & DragDropEffects.Copy) > 0)
|
|
return DragDropEffects.Copy;
|
|
return DragDropEffects.None;
|
|
}
|
|
|
|
protected void OnDragEnter(object sender, DragEventArgs e)
|
|
{
|
|
if (IsSupportedData(e.Data))
|
|
e.Effect = GetDragDropEffect(e);
|
|
}
|
|
|
|
private void InsertString(int offset, string str)
|
|
{
|
|
if (str == null)
|
|
return;
|
|
|
|
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)
|
|
{
|
|
if (!IsSupportedData(e.Data))
|
|
{
|
|
return;
|
|
}
|
|
|
|
textArea.BeginUpdate();
|
|
textArea.Document.UndoStack.StartUndoGroup();
|
|
try
|
|
{
|
|
var offset = textArea.Caret.Offset;
|
|
if (textArea.IsReadOnly(offset))
|
|
return;
|
|
|
|
try
|
|
{
|
|
if (e.Data.GetDataPresent(typeof(DefaultSelection)))
|
|
{
|
|
var 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))
|
|
return;
|
|
var len = sel.Length;
|
|
textArea.Document.Remove(sel.Offset, len);
|
|
if (sel.Offset < offset)
|
|
offset -= len;
|
|
}
|
|
}
|
|
}
|
|
catch (System.InvalidCastException)
|
|
{
|
|
/*
|
|
If GetDataPresent(typeof(DefaultSelection)) threw this
|
|
exception, then it's an interprocess DefaultSelection
|
|
COM object that is not serializable! In general,
|
|
GetDataPresent(typeof(...)) throws InvalidCastException
|
|
for drags and drops from other GitExt processes (maybe
|
|
we need to make the data objects [Serializable]?). We
|
|
can get around this exception by doing
|
|
GetDataPresent(String s) [using the string of the type
|
|
name seems to work fine!] Since it is interprocess
|
|
data, just get the string data from it - special
|
|
handling logic in try {} is only valid for selections
|
|
within the current process's text editor!
|
|
*/
|
|
}
|
|
|
|
textArea.SelectionManager.ClearSelection();
|
|
InsertString(offset, (string)e.Data.GetData("System.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();
|
|
|
|
var p = textArea.PointToClient(new Point(e.X, e.Y));
|
|
|
|
if (textArea.TextView.DrawingPosition.Contains(p.X, p.Y))
|
|
{
|
|
var realmousepos = textArea.TextView.GetLogicalPosition(
|
|
p.X - textArea.TextView.DrawingPosition.X,
|
|
p.Y - textArea.TextView.DrawingPosition.Y);
|
|
var lineNr = Math.Min(textArea.Document.TotalNumberOfLines - 1, Math.Max(val1: 0, realmousepos.Y));
|
|
|
|
textArea.Caret.Position = new TextLocation(realmousepos.X, lineNr);
|
|
textArea.SetDesiredColumn();
|
|
if (IsSupportedData(e.Data) && !textArea.IsReadOnly(textArea.Caret.Offset))
|
|
e.Effect = GetDragDropEffect(e);
|
|
else
|
|
e.Effect = DragDropEffects.None;
|
|
}
|
|
else
|
|
{
|
|
e.Effect = DragDropEffects.None;
|
|
}
|
|
}
|
|
|
|
private static bool IsSupportedData(IDataObject data)
|
|
{
|
|
return data.GetDataPresent(DataFormats.StringFormat)
|
|
|| data.GetDataPresent(DataFormats.Text)
|
|
|| data.GetDataPresent(DataFormats.UnicodeText);
|
|
}
|
|
}
|
|
}
|