Browse Source

fix #232: Raise DataObject events on clipboard and drag'n'drop operations in AvalonEdit

pull/343/merge
Siegfried Pammer 12 years ago
parent
commit
234136ff25
  1. 60
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  2. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs
  3. 23
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs
  4. 20
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs

60
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs

@ -312,13 +312,14 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textArea != null && textArea.Document != null) { if (textArea != null && textArea.Document != null) {
if (textArea.Selection.IsEmpty && textArea.Options.CutCopyWholeLine) { if (textArea.Selection.IsEmpty && textArea.Options.CutCopyWholeLine) {
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line); DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
CopyWholeLine(textArea, currentLine); if (CopyWholeLine(textArea, currentLine)) {
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(new SimpleSegment(currentLine.Offset, currentLine.TotalLength)); ISegment[] segmentsToDelete = textArea.GetDeletableSegments(new SimpleSegment(currentLine.Offset, currentLine.TotalLength));
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) { for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
textArea.Document.Remove(segmentsToDelete[i]); textArea.Document.Remove(segmentsToDelete[i]);
} }
}
} else { } else {
CopySelectedText(textArea); if (CopySelectedText(textArea))
textArea.RemoveSelectedText(); textArea.RemoveSelectedText();
} }
textArea.Caret.BringCaretToView(); textArea.Caret.BringCaretToView();
@ -326,50 +327,74 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
} }
static void CopySelectedText(TextArea textArea) static bool CopySelectedText(TextArea textArea)
{ {
var data = textArea.Selection.CreateDataObject(textArea); var data = textArea.Selection.CreateDataObject(textArea);
var copyingEventArgs = new DataObjectCopyingEventArgs(data, false);
textArea.RaiseEvent(copyingEventArgs);
if (copyingEventArgs.CommandCancelled)
return false;
try { try {
Clipboard.SetDataObject(data, true); Clipboard.SetDataObject(data, true);
} catch (ExternalException) { } catch (ExternalException) {
// Apparently this exception sometimes happens randomly. // Apparently this exception sometimes happens randomly.
// The MS controls just ignore it, so we'll do the same. // The MS controls just ignore it, so we'll do the same.
return; return false;
} }
string text = textArea.Selection.GetText(); string text = textArea.Selection.GetText();
text = TextUtilities.NormalizeNewLines(text, Environment.NewLine); text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
textArea.OnTextCopied(new TextEventArgs(text)); textArea.OnTextCopied(new TextEventArgs(text));
return true;
} }
const string LineSelectedType = "MSDEVLineSelect"; // This is the type VS 2003 and 2005 use for flagging a whole line copy const string LineSelectedType = "MSDEVLineSelect"; // This is the type VS 2003 and 2005 use for flagging a whole line copy
static void CopyWholeLine(TextArea textArea, DocumentLine line) public static bool ConfirmDataFormat(TextArea textArea, DataObject dataObject, string format)
{
var e = new DataObjectSettingDataEventArgs(dataObject, format);
textArea.RaiseEvent(e);
return !e.CommandCancelled;
}
static bool CopyWholeLine(TextArea textArea, DocumentLine line)
{ {
ISegment wholeLine = new SimpleSegment(line.Offset, line.TotalLength); ISegment wholeLine = new SimpleSegment(line.Offset, line.TotalLength);
string text = textArea.Document.GetText(wholeLine); string text = textArea.Document.GetText(wholeLine);
// Ensure we use the appropriate newline sequence for the OS // Ensure we use the appropriate newline sequence for the OS
text = TextUtilities.NormalizeNewLines(text, Environment.NewLine); text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
DataObject data = new DataObject(text); DataObject data = new DataObject();
if (ConfirmDataFormat(textArea, data, DataFormats.UnicodeText))
data.SetText(text);
// Also copy text in HTML format to clipboard - good for pasting text into Word // Also copy text in HTML format to clipboard - good for pasting text into Word
// or to the SharpDevelop forums. // or to the SharpDevelop forums.
if (ConfirmDataFormat(textArea, data, DataFormats.Html)) {
IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter; IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options))); HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options)));
}
if (ConfirmDataFormat(textArea, data, LineSelectedType)) {
MemoryStream lineSelected = new MemoryStream(1); MemoryStream lineSelected = new MemoryStream(1);
lineSelected.WriteByte(1); lineSelected.WriteByte(1);
data.SetData(LineSelectedType, lineSelected, false); data.SetData(LineSelectedType, lineSelected, false);
}
var copyingEventArgs = new DataObjectCopyingEventArgs(data, false);
textArea.RaiseEvent(copyingEventArgs);
if (copyingEventArgs.CommandCancelled)
return false;
try { try {
Clipboard.SetDataObject(data, true); Clipboard.SetDataObject(data, true);
} catch (ExternalException) { } catch (ExternalException) {
// Apparently this exception sometimes happens randomly. // Apparently this exception sometimes happens randomly.
// The MS controls just ignore it, so we'll do the same. // The MS controls just ignore it, so we'll do the same.
return; return false;
} }
textArea.OnTextCopied(new TextEventArgs(text)); textArea.OnTextCopied(new TextEventArgs(text));
return true;
} }
static void CanPaste(object target, CanExecuteRoutedEventArgs args) static void CanPaste(object target, CanExecuteRoutedEventArgs args)
@ -411,6 +436,27 @@ namespace ICSharpCode.AvalonEdit.Editing
if (!string.IsNullOrEmpty(text)) { if (!string.IsNullOrEmpty(text)) {
bool fullLine = textArea.Options.CutCopyWholeLine && dataObject.GetDataPresent(LineSelectedType); bool fullLine = textArea.Options.CutCopyWholeLine && dataObject.GetDataPresent(LineSelectedType);
bool rectangular = dataObject.GetDataPresent(RectangleSelection.RectangularSelectionDataType); bool rectangular = dataObject.GetDataPresent(RectangleSelection.RectangularSelectionDataType);
string pasteFormat;
// fill the suggested DataFormat used for the paste action:
if (fullLine)
pasteFormat = LineSelectedType;
else if (rectangular && textArea.Selection.IsEmpty && !(textArea.Selection is RectangleSelection))
pasteFormat = RectangleSelection.RectangularSelectionDataType;
else
pasteFormat = DataFormats.UnicodeText;
var pastingEventArgs = new DataObjectPastingEventArgs(dataObject, false, pasteFormat);
textArea.RaiseEvent(pastingEventArgs);
if (pastingEventArgs.CommandCancelled)
return;
// DataObject.PastingEvent handlers might have changed the format to apply.
pasteFormat = pastingEventArgs.FormatToApply;
fullLine = pasteFormat == LineSelectedType;
rectangular = pasteFormat == RectangleSelection.RectangularSelectionDataType;
if (fullLine) { if (fullLine) {
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line); DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
if (textArea.ReadOnlySectionProvider.CanInsert(currentLine.Offset)) { if (textArea.ReadOnlySectionProvider.CanInsert(currentLine.Offset)) {

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs

@ -396,9 +396,11 @@ namespace ICSharpCode.AvalonEdit.Editing
{ {
var data = base.CreateDataObject(textArea); var data = base.CreateDataObject(textArea);
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, RectangularSelectionDataType)) {
MemoryStream isRectangle = new MemoryStream(1); MemoryStream isRectangle = new MemoryStream(1);
isRectangle.WriteByte(1); isRectangle.WriteByte(1);
data.SetData(RectangularSelectionDataType, isRectangle, false); data.SetData(RectangularSelectionDataType, isRectangle, false);
}
return data; return data;
} }

23
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs

@ -270,15 +270,30 @@ namespace ICSharpCode.AvalonEdit.Editing
/// </summary> /// </summary>
public virtual DataObject CreateDataObject(TextArea textArea) public virtual DataObject CreateDataObject(TextArea textArea)
{ {
string text = GetText(); DataObject data = new DataObject();
// Ensure we use the appropriate newline sequence for the OS // Ensure we use the appropriate newline sequence for the OS
DataObject data = new DataObject(TextUtilities.NormalizeNewLines(text, Environment.NewLine)); string text = TextUtilities.NormalizeNewLines(GetText(), Environment.NewLine);
// we cannot use DataObject.SetText - then we cannot drag to SciTe
// (but dragging to Word works in both cases) // Enable drag/drop to Word, Notepad++ and others
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.UnicodeText)) {
data.SetText(text);
}
// Enable drag/drop to SciTe:
// We cannot use SetText, thus we need to use typeof(string).FullName as data format.
// new DataObject(object) calls SetData(object), which in turn calls SetData(Type, data),
// which then uses Type.FullName as format.
// We immitate that behavior here as well:
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, typeof(string).FullName)) {
data.SetData(typeof(string).FullName, text);
}
// Also copy text in HTML format to clipboard - good for pasting text into Word // Also copy text in HTML format to clipboard - good for pasting text into Word
// or to the SharpDevelop forums. // or to the SharpDevelop forums.
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.Html)) {
HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options))); HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options)));
}
return data; return data;
} }
} }

20
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs

@ -234,6 +234,21 @@ namespace ICSharpCode.AvalonEdit.Editing
string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line); string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
text = TextUtilities.NormalizeNewLines(text, newLine); text = TextUtilities.NormalizeNewLines(text, newLine);
string pasteFormat;
// fill the suggested DataFormat used for the paste action:
if (rectangular)
pasteFormat = RectangleSelection.RectangularSelectionDataType;
else
pasteFormat = DataFormats.UnicodeText;
var pastingEventArgs = new DataObjectPastingEventArgs(e.Data, true, pasteFormat);
textArea.RaiseEvent(pastingEventArgs);
if (pastingEventArgs.CommandCancelled)
return;
// DataObject.PastingEvent handlers might have changed the format to apply.
rectangular = pastingEventArgs.FormatToApply == RectangleSelection.RectangularSelectionDataType;
// Mark the undo group with the currentDragDescriptor, if the drag // Mark the undo group with the currentDragDescriptor, if the drag
// is originating from the same control. This allows combining // is originating from the same control. This allows combining
// the undo groups when text is moved. // the undo groups when text is moved.
@ -320,6 +335,11 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
} }
var copyingEventArgs = new DataObjectCopyingEventArgs(dataObject, true);
textArea.RaiseEvent(copyingEventArgs);
if (copyingEventArgs.CommandCancelled)
return;
object dragDescriptor = new object(); object dragDescriptor = new object();
this.currentDragDescriptor = dragDescriptor; this.currentDragDescriptor = dragDescriptor;

Loading…
Cancel
Save