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. 80
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  2. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs
  3. 25
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs
  4. 20
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs

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

@ -312,64 +312,89 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -312,64 +312,89 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textArea != null && textArea.Document != null) {
if (textArea.Selection.IsEmpty && textArea.Options.CutCopyWholeLine) {
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
CopyWholeLine(textArea, currentLine);
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(new SimpleSegment(currentLine.Offset, currentLine.TotalLength));
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
textArea.Document.Remove(segmentsToDelete[i]);
if (CopyWholeLine(textArea, currentLine)) {
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(new SimpleSegment(currentLine.Offset, currentLine.TotalLength));
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
textArea.Document.Remove(segmentsToDelete[i]);
}
}
} else {
CopySelectedText(textArea);
textArea.RemoveSelectedText();
if (CopySelectedText(textArea))
textArea.RemoveSelectedText();
}
textArea.Caret.BringCaretToView();
args.Handled = true;
}
}
static void CopySelectedText(TextArea textArea)
static bool CopySelectedText(TextArea textArea)
{
var data = textArea.Selection.CreateDataObject(textArea);
var copyingEventArgs = new DataObjectCopyingEventArgs(data, false);
textArea.RaiseEvent(copyingEventArgs);
if (copyingEventArgs.CommandCancelled)
return false;
try {
Clipboard.SetDataObject(data, true);
} catch (ExternalException) {
// Apparently this exception sometimes happens randomly.
// The MS controls just ignore it, so we'll do the same.
return;
return false;
}
string text = textArea.Selection.GetText();
text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
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
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);
string text = textArea.Document.GetText(wholeLine);
// Ensure we use the appropriate newline sequence for the OS
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
// or to the SharpDevelop forums.
IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options)));
if (ConfirmDataFormat(textArea, data, DataFormats.Html)) {
IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options)));
}
if (ConfirmDataFormat(textArea, data, LineSelectedType)) {
MemoryStream lineSelected = new MemoryStream(1);
lineSelected.WriteByte(1);
data.SetData(LineSelectedType, lineSelected, false);
}
MemoryStream lineSelected = new MemoryStream(1);
lineSelected.WriteByte(1);
data.SetData(LineSelectedType, lineSelected, false);
var copyingEventArgs = new DataObjectCopyingEventArgs(data, false);
textArea.RaiseEvent(copyingEventArgs);
if (copyingEventArgs.CommandCancelled)
return false;
try {
Clipboard.SetDataObject(data, true);
} catch (ExternalException) {
// Apparently this exception sometimes happens randomly.
// The MS controls just ignore it, so we'll do the same.
return;
return false;
}
textArea.OnTextCopied(new TextEventArgs(text));
return true;
}
static void CanPaste(object target, CanExecuteRoutedEventArgs args)
@ -396,7 +421,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -396,7 +421,7 @@ namespace ICSharpCode.AvalonEdit.Editing
}
if (dataObject == null)
return;
Debug.WriteLine( dataObject.GetData(DataFormats.Html) as string );
Debug.WriteLine(dataObject.GetData(DataFormats.Html) as string);
// convert text back to correct newlines for this document
string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
@ -411,6 +436,27 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -411,6 +436,27 @@ namespace ICSharpCode.AvalonEdit.Editing
if (!string.IsNullOrEmpty(text)) {
bool fullLine = textArea.Options.CutCopyWholeLine && dataObject.GetDataPresent(LineSelectedType);
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) {
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
if (textArea.ReadOnlySectionProvider.CanInsert(currentLine.Offset)) {

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

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

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

@ -270,15 +270,30 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -270,15 +270,30 @@ namespace ICSharpCode.AvalonEdit.Editing
/// </summary>
public virtual DataObject CreateDataObject(TextArea textArea)
{
string text = GetText();
DataObject data = new DataObject();
// Ensure we use the appropriate newline sequence for the OS
DataObject data = new DataObject(TextUtilities.NormalizeNewLines(text, Environment.NewLine));
// we cannot use DataObject.SetText - then we cannot drag to SciTe
// (but dragging to Word works in both cases)
string text = TextUtilities.NormalizeNewLines(GetText(), Environment.NewLine);
// 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
// or to the SharpDevelop forums.
HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options)));
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.Html)) {
HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options)));
}
return data;
}
}

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

@ -234,6 +234,21 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -234,6 +234,21 @@ namespace ICSharpCode.AvalonEdit.Editing
string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
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
// is originating from the same control. This allows combining
// the undo groups when text is moved.
@ -320,6 +335,11 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -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();
this.currentDragDescriptor = dragDescriptor;

Loading…
Cancel
Save