/PythonConsoleControl/PythonEditingCommandHandler.cs

http://revitpythonshell.googlecode.com/ · C# · 227 lines · 183 code · 23 blank · 21 comment · 28 complexity · 6373d94d565e68c36406b90278a95141 MD5 · raw file

  1. // Copyright (c) 2010 Joe Moorhouse
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Diagnostics;
  7. using System.Globalization;
  8. using System.IO;
  9. using System.Runtime.InteropServices;
  10. using System.Windows;
  11. using System.Windows.Documents;
  12. using System.Windows.Input;
  13. using System.Reflection;
  14. using ICSharpCode.AvalonEdit;
  15. using ICSharpCode.AvalonEdit.Document;
  16. using ICSharpCode.AvalonEdit.Highlighting;
  17. using ICSharpCode.AvalonEdit.Utils;
  18. using ICSharpCode.AvalonEdit.Editing;
  19. namespace PythonConsoleControl
  20. {
  21. /// <summary>
  22. /// Commands that only involve the text editor are outsourced to here.
  23. /// </summary>
  24. class PythonEditingCommandHandler
  25. {
  26. PythonTextEditor textEditor;
  27. TextArea textArea;
  28. public PythonEditingCommandHandler(PythonTextEditor textEditor)
  29. {
  30. this.textEditor = textEditor;
  31. this.textArea = textEditor.textArea;
  32. }
  33. internal static void CanCutOrCopy(object target, CanExecuteRoutedEventArgs args)
  34. {
  35. // HasSomethingSelected for copy and cut commands
  36. TextArea textArea = GetTextArea(target);
  37. if (textArea != null && textArea.Document != null)
  38. {
  39. args.CanExecute = textArea.Options.CutCopyWholeLine || !textArea.Selection.IsEmpty;
  40. args.Handled = true;
  41. }
  42. }
  43. internal static TextArea GetTextArea(object target)
  44. {
  45. return target as TextArea;
  46. }
  47. internal static void OnCopy(object target, ExecutedRoutedEventArgs args)
  48. {
  49. TextArea textArea = GetTextArea(target);
  50. if (textArea != null && textArea.Document != null)
  51. {
  52. if (textArea.Selection.IsEmpty && textArea.Options.CutCopyWholeLine)
  53. {
  54. DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
  55. CopyWholeLine(textArea, currentLine);
  56. }
  57. else
  58. {
  59. CopySelectedText(textArea);
  60. }
  61. args.Handled = true;
  62. }
  63. }
  64. internal static void OnCut(object target, ExecutedRoutedEventArgs args)
  65. {
  66. TextArea textArea = GetTextArea(target);
  67. if (textArea != null && textArea.Document != null)
  68. {
  69. if (textArea.Selection.IsEmpty && textArea.Options.CutCopyWholeLine)
  70. {
  71. DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
  72. CopyWholeLine(textArea, currentLine);
  73. textArea.Document.Remove(currentLine.Offset, currentLine.TotalLength);
  74. }
  75. else
  76. {
  77. CopySelectedText(textArea);
  78. textArea.Selection.ReplaceSelectionWithText(textArea, string.Empty);
  79. }
  80. textArea.Caret.BringCaretToView();
  81. args.Handled = true;
  82. }
  83. }
  84. internal static void CopySelectedText(TextArea textArea)
  85. {
  86. var data = textArea.Selection.CreateDataObject(textArea);
  87. try
  88. {
  89. Clipboard.SetDataObject(data, true);
  90. }
  91. catch (ExternalException)
  92. {
  93. // Apparently this exception sometimes happens randomly.
  94. // The MS controls just ignore it, so we'll do the same.
  95. return;
  96. }
  97. string text = textArea.Selection.GetText(textArea.Document);
  98. text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
  99. //textArea.OnTextCopied(new TextEventArgs(text));
  100. }
  101. internal static void CopyWholeLine(TextArea textArea, DocumentLine line)
  102. {
  103. ISegment wholeLine = new VerySimpleSegment(line.Offset, line.TotalLength);
  104. string text = textArea.Document.GetText(wholeLine);
  105. // Ensure we use the appropriate newline sequence for the OS
  106. text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
  107. DataObject data = new DataObject(text);
  108. // Also copy text in HTML format to clipboard - good for pasting text into Word
  109. // or to the SharpDevelop forums.
  110. IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
  111. HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options)));
  112. MemoryStream lineSelected = new MemoryStream(1);
  113. lineSelected.WriteByte(1);
  114. data.SetData(LineSelectedType, lineSelected, false);
  115. try
  116. {
  117. Clipboard.SetDataObject(data, true);
  118. }
  119. catch (ExternalException)
  120. {
  121. // Apparently this exception sometimes happens randomly.
  122. // The MS controls just ignore it, so we'll do the same.
  123. return;
  124. }
  125. //textArea.OnTextCopied(new TextEventArgs(text));
  126. }
  127. internal static ExecutedRoutedEventHandler OnDelete(RoutedUICommand selectingCommand)
  128. {
  129. return (target, args) =>
  130. {
  131. TextArea textArea = GetTextArea(target);
  132. if (textArea != null && textArea.Document != null)
  133. {
  134. // call BeginUpdate before running the 'selectingCommand'
  135. // so that undoing the delete does not select the deleted character
  136. using (textArea.Document.RunUpdate())
  137. {
  138. Type textAreaType = textArea.GetType();
  139. MethodInfo method;
  140. if (textArea.Selection.IsEmpty)
  141. {
  142. TextViewPosition oldCaretPosition = textArea.Caret.Position;
  143. selectingCommand.Execute(args.Parameter, textArea);
  144. bool hasSomethingDeletable = false;
  145. foreach (ISegment s in textArea.Selection.Segments)
  146. {
  147. method = textAreaType.GetMethod("GetDeletableSegments", BindingFlags.Instance | BindingFlags.NonPublic);
  148. //textArea.GetDeletableSegments(s).Length > 0)
  149. if ((int)method.Invoke(textArea, new Object[]{s}) > 0)
  150. {
  151. hasSomethingDeletable = true;
  152. break;
  153. }
  154. }
  155. if (!hasSomethingDeletable)
  156. {
  157. // If nothing in the selection is deletable; then reset caret+selection
  158. // to the previous value. This prevents the caret from moving through read-only sections.
  159. textArea.Caret.Position = oldCaretPosition;
  160. textArea.Selection = Selection.Empty;
  161. }
  162. }
  163. method = textAreaType.GetMethod("RemoveSelectedText", BindingFlags.Instance | BindingFlags.NonPublic);
  164. method.Invoke(textArea, new Object[]{});
  165. //textArea.RemoveSelectedText();
  166. }
  167. textArea.Caret.BringCaretToView();
  168. args.Handled = true;
  169. }
  170. };
  171. }
  172. internal static void CanDelete(object target, CanExecuteRoutedEventArgs args)
  173. {
  174. // HasSomethingSelected for delete command
  175. TextArea textArea = GetTextArea(target);
  176. if (textArea != null && textArea.Document != null)
  177. {
  178. args.CanExecute = !textArea.Selection.IsEmpty;
  179. args.Handled = true;
  180. }
  181. }
  182. const string LineSelectedType = "MSDEVLineSelect"; // This is the type VS 2003 and 2005 use for flagging a whole line copy
  183. struct VerySimpleSegment : ISegment
  184. {
  185. public readonly int Offset, Length;
  186. int ISegment.Offset {
  187. get { return Offset; }
  188. }
  189. int ISegment.Length {
  190. get { return Length; }
  191. }
  192. public int EndOffset {
  193. get {
  194. return Offset + Length;
  195. }
  196. }
  197. public VerySimpleSegment(int offset, int length)
  198. {
  199. this.Offset = offset;
  200. this.Length = length;
  201. }
  202. }
  203. }
  204. }