Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit 234136f

Browse files
fix #232: Raise DataObject events on clipboard and drag'n'drop operations in AvalonEdit
1 parent 543912d commit 234136f

4 files changed

Lines changed: 108 additions & 25 deletions

File tree

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

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -312,64 +312,89 @@ static void OnCut(object target, ExecutedRoutedEventArgs args)
312312
if (textArea != null && textArea.Document != null) {
313313
if (textArea.Selection.IsEmpty && textArea.Options.CutCopyWholeLine) {
314314
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
315-
CopyWholeLine(textArea, currentLine);
316-
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(new SimpleSegment(currentLine.Offset, currentLine.TotalLength));
317-
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
318-
textArea.Document.Remove(segmentsToDelete[i]);
315+
if (CopyWholeLine(textArea, currentLine)) {
316+
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(new SimpleSegment(currentLine.Offset, currentLine.TotalLength));
317+
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
318+
textArea.Document.Remove(segmentsToDelete[i]);
319+
}
319320
}
320321
} else {
321-
CopySelectedText(textArea);
322-
textArea.RemoveSelectedText();
322+
if (CopySelectedText(textArea))
323+
textArea.RemoveSelectedText();
323324
}
324325
textArea.Caret.BringCaretToView();
325326
args.Handled = true;
326327
}
327328
}
328329

329-
static void CopySelectedText(TextArea textArea)
330+
static bool CopySelectedText(TextArea textArea)
330331
{
331332
var data = textArea.Selection.CreateDataObject(textArea);
333+
var copyingEventArgs = new DataObjectCopyingEventArgs(data, false);
334+
textArea.RaiseEvent(copyingEventArgs);
335+
if (copyingEventArgs.CommandCancelled)
336+
return false;
332337

333338
try {
334339
Clipboard.SetDataObject(data, true);
335340
} catch (ExternalException) {
336341
// Apparently this exception sometimes happens randomly.
337342
// The MS controls just ignore it, so we'll do the same.
338-
return;
343+
return false;
339344
}
340345

341346
string text = textArea.Selection.GetText();
342347
text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
343348
textArea.OnTextCopied(new TextEventArgs(text));
349+
return true;
344350
}
345351

346352
const string LineSelectedType = "MSDEVLineSelect"; // This is the type VS 2003 and 2005 use for flagging a whole line copy
347353

348-
static void CopyWholeLine(TextArea textArea, DocumentLine line)
354+
public static bool ConfirmDataFormat(TextArea textArea, DataObject dataObject, string format)
355+
{
356+
var e = new DataObjectSettingDataEventArgs(dataObject, format);
357+
textArea.RaiseEvent(e);
358+
return !e.CommandCancelled;
359+
}
360+
361+
static bool CopyWholeLine(TextArea textArea, DocumentLine line)
349362
{
350363
ISegment wholeLine = new SimpleSegment(line.Offset, line.TotalLength);
351364
string text = textArea.Document.GetText(wholeLine);
352365
// Ensure we use the appropriate newline sequence for the OS
353366
text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
354-
DataObject data = new DataObject(text);
367+
DataObject data = new DataObject();
368+
if (ConfirmDataFormat(textArea, data, DataFormats.UnicodeText))
369+
data.SetText(text);
355370

356371
// Also copy text in HTML format to clipboard - good for pasting text into Word
357372
// or to the SharpDevelop forums.
358-
IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
359-
HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options)));
373+
if (ConfirmDataFormat(textArea, data, DataFormats.Html)) {
374+
IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
375+
HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options)));
376+
}
377+
378+
if (ConfirmDataFormat(textArea, data, LineSelectedType)) {
379+
MemoryStream lineSelected = new MemoryStream(1);
380+
lineSelected.WriteByte(1);
381+
data.SetData(LineSelectedType, lineSelected, false);
382+
}
360383

361-
MemoryStream lineSelected = new MemoryStream(1);
362-
lineSelected.WriteByte(1);
363-
data.SetData(LineSelectedType, lineSelected, false);
384+
var copyingEventArgs = new DataObjectCopyingEventArgs(data, false);
385+
textArea.RaiseEvent(copyingEventArgs);
386+
if (copyingEventArgs.CommandCancelled)
387+
return false;
364388

365389
try {
366390
Clipboard.SetDataObject(data, true);
367391
} catch (ExternalException) {
368392
// Apparently this exception sometimes happens randomly.
369393
// The MS controls just ignore it, so we'll do the same.
370-
return;
394+
return false;
371395
}
372396
textArea.OnTextCopied(new TextEventArgs(text));
397+
return true;
373398
}
374399

375400
static void CanPaste(object target, CanExecuteRoutedEventArgs args)
@@ -396,7 +421,7 @@ static void OnPaste(object target, ExecutedRoutedEventArgs args)
396421
}
397422
if (dataObject == null)
398423
return;
399-
Debug.WriteLine( dataObject.GetData(DataFormats.Html) as string );
424+
Debug.WriteLine(dataObject.GetData(DataFormats.Html) as string);
400425

401426
// convert text back to correct newlines for this document
402427
string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
@@ -411,6 +436,27 @@ static void OnPaste(object target, ExecutedRoutedEventArgs args)
411436
if (!string.IsNullOrEmpty(text)) {
412437
bool fullLine = textArea.Options.CutCopyWholeLine && dataObject.GetDataPresent(LineSelectedType);
413438
bool rectangular = dataObject.GetDataPresent(RectangleSelection.RectangularSelectionDataType);
439+
440+
string pasteFormat;
441+
// fill the suggested DataFormat used for the paste action:
442+
if (fullLine)
443+
pasteFormat = LineSelectedType;
444+
else if (rectangular && textArea.Selection.IsEmpty && !(textArea.Selection is RectangleSelection))
445+
pasteFormat = RectangleSelection.RectangularSelectionDataType;
446+
else
447+
pasteFormat = DataFormats.UnicodeText;
448+
449+
var pastingEventArgs = new DataObjectPastingEventArgs(dataObject, false, pasteFormat);
450+
textArea.RaiseEvent(pastingEventArgs);
451+
if (pastingEventArgs.CommandCancelled)
452+
return;
453+
454+
// DataObject.PastingEvent handlers might have changed the format to apply.
455+
pasteFormat = pastingEventArgs.FormatToApply;
456+
457+
fullLine = pasteFormat == LineSelectedType;
458+
rectangular = pasteFormat == RectangleSelection.RectangularSelectionDataType;
459+
414460
if (fullLine) {
415461
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
416462
if (textArea.ReadOnlySectionProvider.CanInsert(currentLine.Offset)) {

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,11 @@ public override System.Windows.DataObject CreateDataObject(TextArea textArea)
396396
{
397397
var data = base.CreateDataObject(textArea);
398398

399-
MemoryStream isRectangle = new MemoryStream(1);
400-
isRectangle.WriteByte(1);
401-
data.SetData(RectangularSelectionDataType, isRectangle, false);
399+
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, RectangularSelectionDataType)) {
400+
MemoryStream isRectangle = new MemoryStream(1);
401+
isRectangle.WriteByte(1);
402+
data.SetData(RectangularSelectionDataType, isRectangle, false);
403+
}
402404
return data;
403405
}
404406

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,30 @@ public virtual bool Contains(int offset)
270270
/// </summary>
271271
public virtual DataObject CreateDataObject(TextArea textArea)
272272
{
273-
string text = GetText();
273+
DataObject data = new DataObject();
274+
274275
// Ensure we use the appropriate newline sequence for the OS
275-
DataObject data = new DataObject(TextUtilities.NormalizeNewLines(text, Environment.NewLine));
276-
// we cannot use DataObject.SetText - then we cannot drag to SciTe
277-
// (but dragging to Word works in both cases)
276+
string text = TextUtilities.NormalizeNewLines(GetText(), Environment.NewLine);
277+
278+
// Enable drag/drop to Word, Notepad++ and others
279+
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.UnicodeText)) {
280+
data.SetText(text);
281+
}
282+
283+
// Enable drag/drop to SciTe:
284+
// We cannot use SetText, thus we need to use typeof(string).FullName as data format.
285+
// new DataObject(object) calls SetData(object), which in turn calls SetData(Type, data),
286+
// which then uses Type.FullName as format.
287+
// We immitate that behavior here as well:
288+
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, typeof(string).FullName)) {
289+
data.SetData(typeof(string).FullName, text);
290+
}
278291

279292
// Also copy text in HTML format to clipboard - good for pasting text into Word
280293
// or to the SharpDevelop forums.
281-
HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options)));
294+
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.Html)) {
295+
HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options)));
296+
}
282297
return data;
283298
}
284299
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,21 @@ void textArea_Drop(object sender, DragEventArgs e)
234234
string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
235235
text = TextUtilities.NormalizeNewLines(text, newLine);
236236

237+
string pasteFormat;
238+
// fill the suggested DataFormat used for the paste action:
239+
if (rectangular)
240+
pasteFormat = RectangleSelection.RectangularSelectionDataType;
241+
else
242+
pasteFormat = DataFormats.UnicodeText;
243+
244+
var pastingEventArgs = new DataObjectPastingEventArgs(e.Data, true, pasteFormat);
245+
textArea.RaiseEvent(pastingEventArgs);
246+
if (pastingEventArgs.CommandCancelled)
247+
return;
248+
249+
// DataObject.PastingEvent handlers might have changed the format to apply.
250+
rectangular = pastingEventArgs.FormatToApply == RectangleSelection.RectangularSelectionDataType;
251+
237252
// Mark the undo group with the currentDragDescriptor, if the drag
238253
// is originating from the same control. This allows combining
239254
// the undo groups when text is moved.
@@ -320,6 +335,11 @@ void StartDrag()
320335
}
321336
}
322337

338+
var copyingEventArgs = new DataObjectCopyingEventArgs(dataObject, true);
339+
textArea.RaiseEvent(copyingEventArgs);
340+
if (copyingEventArgs.CommandCancelled)
341+
return;
342+
323343
object dragDescriptor = new object();
324344
this.currentDragDescriptor = dragDescriptor;
325345

0 commit comments

Comments
 (0)