1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
23 // Peter Bartok <pbartok@novell.com>
32 using System
.Collections
;
33 using System
.ComponentModel
;
37 using RTF
=System
.Windows
.Forms
.RTF
;
39 namespace System
.Windows
.Forms
{
40 public class RichTextBox
: TextBoxBase
{
41 #region Local Variables
42 internal bool auto_word_select
;
43 internal int bullet_indent
;
44 internal bool can_redo
;
45 internal bool detect_urls
;
46 internal string redo_action_name
;
47 internal int margin_right
;
48 internal string undo_action_name
;
51 private RTF
.TextMap rtf_text_map
;
52 private int rtf_skip_width
;
53 private int rtf_skip_count
;
54 private StringBuilder rtf_line
;
55 private SolidBrush rtf_color
;
56 private RTF
.Font rtf_rtffont
;
57 private int rtf_rtffont_size
;
58 private FontStyle rtf_rtfstyle
;
59 private HorizontalAlignment rtf_rtfalign
;
60 private int rtf_cursor_x
;
61 private int rtf_cursor_y
;
62 private int rtf_chars
;
63 #endregion // Local Variables
65 #region Public Constructors
66 public RichTextBox() {
67 accepts_return
= true;
68 auto_word_select
= false;
72 max_length
= Int32
.MaxValue
;
73 redo_action_name
= string.Empty
;
75 undo_action_name
= string.Empty
;
77 base.Multiline
= true;
78 document
.CRLFSize
= 1;
80 scrollbars
= RichTextBoxScrollBars
.Both
;
81 alignment
= HorizontalAlignment
.Left
;
82 LostFocus
+= new EventHandler(RichTextBox_LostFocus
);
83 GotFocus
+= new EventHandler(RichTextBox_GotFocus
);
84 BackColor
= ThemeEngine
.Current
.ColorWindow
;
85 ForeColor
= ThemeEngine
.Current
.ColorWindowText
;
86 base.HScrolled
+= new EventHandler(RichTextBox_HScrolled
);
87 base.VScrolled
+= new EventHandler(RichTextBox_VScrolled
);
90 SetStyle (ControlStyles
.StandardDoubleClick
, false);
93 #endregion // Public Constructors
95 #region Private & Internal Methods
96 private void RichTextBox_LostFocus(object sender
, EventArgs e
) {
100 private void RichTextBox_GotFocus(object sender
, EventArgs e
) {
103 #endregion // Private & Internal Methods
105 #region Public Instance Properties
106 public override bool AllowDrop
{
108 return base.AllowDrop
;
112 base.AllowDrop
= value;
116 [DefaultValue(false)]
118 public override bool AutoSize
{
124 base.AutoSize
= value;
128 [DefaultValue(false)]
129 public bool AutoWordSelection
{
131 return auto_word_select
;
135 auto_word_select
= true;
140 [EditorBrowsable(EditorBrowsableState
.Never
)]
141 public override System
.Drawing
.Image BackgroundImage
{
142 get { return base.BackgroundImage; }
143 set { base.BackgroundImage = value; }
148 public int BulletIndent
{
150 return bullet_indent
;
154 bullet_indent
= value;
159 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
160 public bool CanRedo
{
167 public bool DetectUrls
{
177 public override Font Font
{
188 if (PreferredHeight
!= Height
) {
189 Height
= PreferredHeight
;
195 // Font changes always set the whole doc to that font
196 start
= document
.GetLine(1);
197 end
= document
.GetLine(document
.Lines
);
198 document
.FormatText(start
, 1, end
, end
.text
.Length
+ 1, base.Font
, null, null, FormatSpecified
.Font
);
203 public override Color ForeColor
{
205 return base.ForeColor
;
209 base.ForeColor
= value;
213 [DefaultValue(Int32
.MaxValue
)]
214 public override int MaxLength
{
216 return base.max_length
;
220 base.max_length
= value;
225 public override bool Multiline
{
231 base.Multiline
= value;
236 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
238 public string RedoActionName
{
240 return redo_action_name
;
246 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
247 public int RightMargin
{
253 margin_right
= value;
259 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
265 start_line
= document
.GetLine(1);
266 end_line
= document
.GetLine(document
.Lines
);
267 return GenerateRTF(start_line
, 0, end_line
, end_line
.text
.Length
).ToString();
274 data
= new MemoryStream(Encoding
.ASCII
.GetBytes(value), false);
276 InsertRTFFromStream(data
, 0, 1);
284 [DefaultValue(RichTextBoxScrollBars
.Both
)]
286 public RichTextBoxScrollBars ScrollBars
{
298 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
299 public string SelectedRtf
{
301 return GenerateRTF(document
.selection_start
.line
, document
.selection_start
.pos
, document
.selection_end
.line
, document
.selection_end
.pos
).ToString();
313 if (document
.selection_visible
) {
314 document
.ReplaceSelection("", false);
317 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
319 data
= new MemoryStream(Encoding
.ASCII
.GetBytes(value), false);
320 InsertRTFFromStream(data
, document
.selection_start
.pos
, document
.selection_start
.line
.line_no
, out x
, out y
, out chars
);
323 document
.CharIndexToLineTag(sel_start
+ chars
+ (y
- document
.selection_start
.line
.line_no
) * 2, out line
, out tag
, out sel_start
);
324 document
.SetSelection(line
, sel_start
);
325 document
.PositionCaret(line
, sel_start
);
326 document
.DisplayCaret();
328 OnTextChanged(EventArgs
.Empty
);
334 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
335 public override string SelectedText
{
337 return base.SelectedText
;
341 base.SelectedText
= value;
346 [DefaultValue(HorizontalAlignment
.Left
)]
347 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
348 public HorizontalAlignment SelectionAlignment
{
350 HorizontalAlignment align
;
355 start
= document
.ParagraphStart(document
.selection_start
.line
);
356 align
= start
.alignment
;
358 end
= document
.ParagraphEnd(document
.selection_end
.line
);
363 if (line
.alignment
!= align
) {
364 return HorizontalAlignment
.Left
;
370 line
= document
.GetLine(line
.line_no
+ 1);
381 start
= document
.ParagraphStart(document
.selection_start
.line
);
383 end
= document
.ParagraphEnd(document
.selection_end
.line
);
388 line
.alignment
= value;
393 line
= document
.GetLine(line
.line_no
+ 1);
395 this.CalculateDocument();
400 [DefaultValue(false)]
401 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
403 public bool SelectionBullet
{
414 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
416 public int SelectionCharOffset
{
426 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
427 public Color SelectionColor
{
434 start
= document
.selection_start
.tag
;
435 end
= document
.selection_end
.tag
;
436 color
= ((SolidBrush
)document
.selection_start
.tag
.color
).Color
;
440 if (!color
.Equals(((SolidBrush
)tag
.color
).Color
)) {
448 tag
= document
.NextTag(tag
);
459 FontDefinition attributes
;
463 attributes
= new FontDefinition();
464 attributes
.color
= value;
466 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
467 sel_end
= document
.LineTagToCharIndex(document
.selection_end
.line
, document
.selection_end
.pos
);
469 document
.FormatText(document
.selection_start
.line
, document
.selection_start
.pos
+ 1, document
.selection_end
.line
, document
.selection_end
.pos
+ 1, attributes
);
471 document
.CharIndexToLineTag(sel_start
, out document
.selection_start
.line
, out document
.selection_start
.tag
, out document
.selection_start
.pos
);
472 document
.CharIndexToLineTag(sel_end
, out document
.selection_end
.line
, out document
.selection_end
.tag
, out document
.selection_end
.pos
);
474 document
.UpdateView(document
.selection_start
.line
, 0);
475 document
.AlignCaret();
480 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
481 public Font SelectionFont
{
488 start
= document
.selection_start
.tag
;
489 end
= document
.selection_end
.tag
;
490 font
= document
.selection_start
.tag
.font
;
494 if (!font
.Equals(tag
.font
)) {
502 tag
= document
.NextTag(tag
);
513 FontDefinition attributes
;
517 attributes
= new FontDefinition();
518 attributes
.font_obj
= value;
520 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
521 sel_end
= document
.LineTagToCharIndex(document
.selection_end
.line
, document
.selection_end
.pos
);
523 document
.FormatText(document
.selection_start
.line
, document
.selection_start
.pos
+ 1, document
.selection_end
.line
, document
.selection_end
.pos
+ 1, attributes
);
525 document
.CharIndexToLineTag(sel_start
, out document
.selection_start
.line
, out document
.selection_start
.tag
, out document
.selection_start
.pos
);
526 document
.CharIndexToLineTag(sel_end
, out document
.selection_end
.line
, out document
.selection_end
.tag
, out document
.selection_end
.pos
);
528 document
.UpdateView(document
.selection_start
.line
, 0);
529 document
.AlignCaret();
536 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
538 public int SelectionHangingIndent
{
549 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
551 public int SelectionIndent
{
561 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
562 public override int SelectionLength
{
564 return base.SelectionLength
;
568 base.SelectionLength
= value;
573 [DefaultValue(false)]
574 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
576 public bool SelectionProtected
{
587 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
589 public int SelectionRightIndent
{
599 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
601 public int[] SelectionTabs
{
611 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
612 public RichTextBoxSelectionTypes SelectionType
{
614 if (document
.selection_start
== document
.selection_end
) {
615 return RichTextBoxSelectionTypes
.Empty
;
619 if (SelectedText
.Length
> 1) {
620 return RichTextBoxSelectionTypes
.MultiChar
| RichTextBoxSelectionTypes
.Text
;
623 return RichTextBoxSelectionTypes
.Text
;
627 [DefaultValue(false)]
629 public bool ShowSelectionMargin
{
639 public override string Text
{
650 public override int TextLength
{
652 return base.TextLength
;
657 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
658 public string UndoActionName
{
660 return document
.undo
.UndoName
;
666 public float ZoomFactor
{
675 #endregion // Public Instance Properties
677 #region Protected Instance Properties
678 protected override CreateParams CreateParams
{
680 return base.CreateParams
;
684 protected override Size DefaultSize
{
686 return new Size(100, 96);
689 #endregion // Protected Instance Properties
691 #region Public Instance Methods
692 public bool CanPaste(DataFormats
.Format clipFormat
) {
693 if ((clipFormat
.Name
== DataFormats
.Rtf
) ||
694 (clipFormat
.Name
== DataFormats
.Text
) ||
695 (clipFormat
.Name
== DataFormats
.UnicodeText
)) {
701 public int Find(char[] characterSet
) {
702 return Find(characterSet
, -1, -1);
705 public int Find(char[] characterSet
, int start
) {
706 return Find(characterSet
, start
, -1);
709 public int Find(char[] characterSet
, int start
, int end
) {
710 Document
.Marker start_mark
;
711 Document
.Marker end_mark
;
712 Document
.Marker result
;
715 document
.GetMarker(out start_mark
, true);
721 start_mark
= new Document
.Marker();
723 document
.CharIndexToLineTag(start
, out line
, out tag
, out pos
);
724 start_mark
.line
= line
;
725 start_mark
.tag
= tag
;
726 start_mark
.pos
= pos
;
730 document
.GetMarker(out end_mark
, false);
736 end_mark
= new Document
.Marker();
738 document
.CharIndexToLineTag(end
, out line
, out tag
, out pos
);
739 end_mark
.line
= line
;
744 if (document
.FindChars(characterSet
, start_mark
, end_mark
, out result
)) {
745 return document
.LineTagToCharIndex(result
.line
, result
.pos
);
751 public int Find(string str
) {
752 return Find(str
, -1, -1, RichTextBoxFinds
.None
);
755 public int Find(string str
, int start
, int end
, RichTextBoxFinds options
) {
756 Document
.Marker start_mark
;
757 Document
.Marker end_mark
;
758 Document
.Marker result
;
761 document
.GetMarker(out start_mark
, true);
767 start_mark
= new Document
.Marker();
769 document
.CharIndexToLineTag(start
, out line
, out tag
, out pos
);
771 start_mark
.line
= line
;
772 start_mark
.tag
= tag
;
773 start_mark
.pos
= pos
;
777 document
.GetMarker(out end_mark
, false);
783 end_mark
= new Document
.Marker();
785 document
.CharIndexToLineTag(end
, out line
, out tag
, out pos
);
787 end_mark
.line
= line
;
792 if (document
.Find(str
, start_mark
, end_mark
, out result
, options
)) {
793 return document
.LineTagToCharIndex(result
.line
, result
.pos
);
799 public int Find(string str
, int start
, RichTextBoxFinds options
) {
800 return Find(str
, start
, -1, options
);
803 public int Find(string str
, RichTextBoxFinds options
) {
804 return Find(str
, -1, -1, options
);
807 public char GetCharFromPosition(Point pt
) {
811 PointToTagPos(pt
, out tag
, out pos
);
813 if (pos
>= tag
.line
.text
.Length
) {
817 return tag
.line
.text
[pos
];
821 public int GetCharIndexFromPosition(Point pt
) {
825 PointToTagPos(pt
, out tag
, out pos
);
827 return document
.LineTagToCharIndex(tag
.line
, pos
);
830 public int GetLineFromCharIndex(int index
) {
835 document
.CharIndexToLineTag(index
, out line
, out tag
, out pos
);
837 return line
.LineNo
- 1;
840 public Point
GetPositionFromCharIndex(int index
) {
845 document
.CharIndexToLineTag(index
, out line
, out tag
, out pos
);
847 return new Point((int)line
.widths
[pos
] + 1, line
.Y
+ 1);
850 public void LoadFile(System
.IO
.Stream data
, RichTextBoxStreamType fileType
) {
853 // FIXME - ignoring unicode
854 if (fileType
== RichTextBoxStreamType
.PlainText
) {
860 sb
= new StringBuilder((int)data
.Length
);
861 buffer
= new byte[1024];
863 throw new IOException("Not enough memory to load document");
867 while (count
< data
.Length
) {
868 count
+= data
.Read(buffer
, count
, 1024);
871 base.Text
= sb
.ToString();
875 InsertRTFFromStream(data
, 0, 1);
877 document
.PositionCaret (document
.GetLine (1), 0);
878 document
.SetSelectionToCaret (true);
882 [MonoTODO("Make smarter RTF detection?")]
883 public void LoadFile(string path
) {
884 if (path
.EndsWith(".rtf")) {
885 LoadFile(path
, RichTextBoxStreamType
.RichText
);
887 LoadFile(path
, RichTextBoxStreamType
.PlainText
);
891 public void LoadFile(string path
, RichTextBoxStreamType fileType
) {
898 data
= new FileStream(path
, FileMode
.Open
, FileAccess
.Read
, FileShare
.Read
, 1024);
900 LoadFile(data
, fileType
);
904 throw new IOException("Could not open file " + path
);
914 public void Paste(DataFormats
.Format clipFormat
) {
915 base.Paste(Clipboard
.GetDataObject(), clipFormat
, false);
922 public void SaveFile(Stream data
, RichTextBoxStreamType fileType
) {
928 if (fileType
== RichTextBoxStreamType
.UnicodePlainText
) {
929 encoding
= Encoding
.Unicode
;
931 encoding
= Encoding
.ASCII
;
935 case RichTextBoxStreamType
.PlainText
:
936 case RichTextBoxStreamType
.TextTextOleObjs
:
937 case RichTextBoxStreamType
.UnicodePlainText
: {
939 bytes
= encoding
.GetBytes(document
.Root
.text
.ToString());
940 data
.Write(bytes
, 0, bytes
.Length
);
944 for (i
= 1; i
< document
.Lines
; i
++) {
945 bytes
= encoding
.GetBytes(document
.GetLine(i
).text
.ToString() + Environment
.NewLine
);
946 data
.Write(bytes
, 0, bytes
.Length
);
948 bytes
= encoding
.GetBytes(document
.GetLine(document
.Lines
).text
.ToString());
949 data
.Write(bytes
, 0, bytes
.Length
);
954 // If we're here we're saving RTF
961 start_line
= document
.GetLine(1);
962 end_line
= document
.GetLine(document
.Lines
);
963 rtf
= GenerateRTF(start_line
, 0, end_line
, end_line
.text
.Length
);
965 bytes
= new Byte
[4096];
967 // Let's chunk it so we don't use up all memory...
968 for (i
= 0; i
< total
; i
+= 1024) {
969 if ((i
+ 1024) < total
) {
970 current
= encoding
.GetBytes(rtf
.ToString(i
, 1024), 0, 1024, bytes
, 0);
973 current
= encoding
.GetBytes(rtf
.ToString(i
, current
), 0, current
, bytes
, 0);
975 data
.Write(bytes
, 0, current
);
979 public void SaveFile(string path
) {
980 if (path
.EndsWith(".rtf")) {
981 SaveFile(path
, RichTextBoxStreamType
.RichText
);
983 SaveFile(path
, RichTextBoxStreamType
.PlainText
);
987 public void SaveFile(string path
, RichTextBoxStreamType fileType
) {
993 data
= new FileStream(path
, FileMode
.Create
, FileAccess
.Write
, FileShare
.None
, 1024, false);
994 SaveFile(data
, fileType
);
998 // throw new IOException("Could not write document to file " + path);
1008 #endregion // Public Instance Methods
1010 #region Protected Instance Methods
1011 protected virtual object CreateRichEditOleCallback() {
1012 throw new NotImplementedException();
1015 protected override void OnBackColorChanged(EventArgs e
) {
1016 base.OnBackColorChanged (e
);
1019 protected virtual void OnContentsResized(ContentsResizedEventArgs e
) {
1020 ContentsResizedEventHandler eh
= (ContentsResizedEventHandler
)(Events
[ContentsResizedEvent
]);
1025 protected override void OnContextMenuChanged(EventArgs e
) {
1026 base.OnContextMenuChanged (e
);
1029 protected override void OnHandleCreated(EventArgs e
) {
1030 base.OnHandleCreated (e
);
1033 protected override void OnHandleDestroyed(EventArgs e
) {
1034 base.OnHandleDestroyed (e
);
1037 protected virtual void OnHScroll(EventArgs e
) {
1038 EventHandler eh
= (EventHandler
)(Events
[HScrollEvent
]);
1043 [MonoTODO("Determine when to call this")]
1044 protected virtual void OnImeChange(EventArgs e
) {
1045 EventHandler eh
= (EventHandler
)(Events
[ImeChangeEvent
]);
1050 protected virtual void OnLinkClicked(LinkClickedEventArgs e
) {
1051 LinkClickedEventHandler eh
= (LinkClickedEventHandler
)(Events
[LinkClickedEvent
]);
1056 protected virtual void OnProtected(EventArgs e
) {
1057 EventHandler eh
= (EventHandler
)(Events
[ProtectedEvent
]);
1062 protected override void OnRightToLeftChanged(EventArgs e
) {
1063 base.OnRightToLeftChanged (e
);
1066 protected virtual void OnSelectionChanged(EventArgs e
) {
1067 EventHandler eh
= (EventHandler
)(Events
[SelectionChangedEvent
]);
1072 protected override void OnSystemColorsChanged(EventArgs e
) {
1073 base.OnSystemColorsChanged (e
);
1076 protected override void OnTextChanged(EventArgs e
) {
1077 base.OnTextChanged (e
);
1080 protected virtual void OnVScroll(EventArgs e
) {
1081 EventHandler eh
= (EventHandler
)(Events
[VScrollEvent
]);
1086 protected override void WndProc(ref Message m
) {
1087 base.WndProc (ref m
);
1089 #endregion // Protected Instance Methods
1092 static object ContentsResizedEvent
= new object ();
1093 static object HScrollEvent
= new object ();
1094 static object ImeChangeEvent
= new object ();
1095 static object LinkClickedEvent
= new object ();
1096 static object ProtectedEvent
= new object ();
1097 static object SelectionChangedEvent
= new object ();
1098 static object VScrollEvent
= new object ();
1101 [EditorBrowsable(EditorBrowsableState
.Never
)]
1102 public new event EventHandler BackgroundImageChanged
{
1103 add { base.BackgroundImageChanged += value; }
1104 remove { base.BackgroundImageChanged -= value; }
1107 public event ContentsResizedEventHandler ContentsResized
{
1108 add { Events.AddHandler (ContentsResizedEvent, value); }
1109 remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1113 [EditorBrowsable(EditorBrowsableState
.Never
)]
1114 public new event EventHandler DoubleClick
{
1115 add { base.DoubleClick += value; }
1116 remove { base.DoubleClick -= value; }
1120 [EditorBrowsable(EditorBrowsableState
.Never
)]
1121 public new event DragEventHandler DragDrop
{
1122 add { base.DragDrop += value; }
1123 remove { base.DragDrop -= value; }
1127 [EditorBrowsable(EditorBrowsableState
.Never
)]
1128 public new event DragEventHandler DragEnter
{
1129 add { base.DragEnter += value; }
1130 remove { base.DragEnter -= value; }
1134 [EditorBrowsable(EditorBrowsableState
.Never
)]
1135 public new event EventHandler DragLeave
{
1136 add { base.DragLeave += value; }
1137 remove { base.DragLeave -= value; }
1142 [EditorBrowsable(EditorBrowsableState
.Never
)]
1143 public new event DragEventHandler DragOver
{
1144 add { base.DragOver += value; }
1145 remove { base.DragOver -= value; }
1150 [EditorBrowsable(EditorBrowsableState
.Never
)]
1151 public new event GiveFeedbackEventHandler GiveFeedback
{
1152 add { base.GiveFeedback += value; }
1153 remove { base.GiveFeedback -= value; }
1156 public event EventHandler HScroll
{
1157 add { Events.AddHandler (HScrollEvent, value); }
1158 remove { Events.RemoveHandler (HScrollEvent, value); }
1161 public event EventHandler ImeChange
{
1162 add { Events.AddHandler (ImeChangeEvent, value); }
1163 remove { Events.RemoveHandler (ImeChangeEvent, value); }
1166 public event LinkClickedEventHandler LinkClicked
{
1167 add { Events.AddHandler (LinkClickedEvent, value); }
1168 remove { Events.RemoveHandler (LinkClickedEvent, value); }
1171 public event EventHandler Protected
{
1172 add { Events.AddHandler (ProtectedEvent, value); }
1173 remove { Events.RemoveHandler (ProtectedEvent, value); }
1177 [EditorBrowsable(EditorBrowsableState
.Never
)]
1178 public new event QueryContinueDragEventHandler QueryContinueDrag
{
1179 add { base.QueryContinueDrag += value; }
1180 remove { base.QueryContinueDrag -= value; }
1183 public event EventHandler SelectionChanged
{
1184 add { Events.AddHandler (SelectionChangedEvent, value); }
1185 remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1188 public event EventHandler VScroll
{
1189 add { Events.AddHandler (VScrollEvent, value); }
1190 remove { Events.RemoveHandler (VScrollEvent, value); }
1192 #endregion // Events
1194 #region Private Methods
1196 internal override void SelectWord ()
1198 document
.ExpandSelection(CaretSelection
.Word
, false);
1201 private void HandleControl(RTF
.RTF rtf
) {
1202 // Console.WriteLine ("HANDLING MAJOR: {0} MINOR: {1}", rtf.Major, rtf.Minor);
1204 case RTF
.Major
.Unicode
: {
1206 case Minor
.UnicodeCharBytes
: {
1207 rtf_skip_width
= rtf
.Param
;
1211 case Minor
.UnicodeChar
: {
1212 rtf_skip_count
+= rtf_skip_width
;
1213 rtf_line
.Append((char)rtf
.Param
);
1220 case RTF
.Major
.Destination
: {
1221 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1226 case RTF
.Major
.CharAttr
: {
1228 case Minor
.ForeColor
: {
1229 System
.Windows
.Forms
.RTF
.Color color
;
1231 color
= System
.Windows
.Forms
.RTF
.Color
.GetColor(rtf
, rtf
.Param
);
1233 if (color
!= null) {
1234 FlushText(rtf
, false);
1235 if (color
.Red
== -1 && color
.Green
== -1 && color
.Blue
== -1) {
1236 this.rtf_color
= new SolidBrush(ForeColor
);
1238 this.rtf_color
= new SolidBrush(Color
.FromArgb(color
.Red
, color
.Green
, color
.Blue
));
1240 FlushText (rtf
, false);
1245 case Minor
.FontSize
: {
1246 FlushText(rtf
, false);
1247 this.rtf_rtffont_size
= rtf
.Param
/ 2;
1251 case Minor
.FontNum
: {
1252 System
.Windows
.Forms
.RTF
.Font font
;
1254 font
= System
.Windows
.Forms
.RTF
.Font
.GetFont(rtf
, rtf
.Param
);
1256 FlushText(rtf
, false);
1257 this.rtf_rtffont
= font
;
1263 FlushText(rtf
, false);
1264 rtf_rtfstyle
= FontStyle
.Regular
;
1269 FlushText(rtf
, false);
1270 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1271 rtf_rtfstyle
|= FontStyle
.Bold
;
1273 rtf_rtfstyle
&= ~FontStyle
.Bold
;
1278 case Minor
.Italic
: {
1279 FlushText(rtf
, false);
1280 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1281 rtf_rtfstyle
|= FontStyle
.Italic
;
1283 rtf_rtfstyle
&= ~FontStyle
.Italic
;
1288 case Minor
.StrikeThru
: {
1289 FlushText(rtf
, false);
1290 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1291 rtf_rtfstyle
|= FontStyle
.Strikeout
;
1293 rtf_rtfstyle
&= ~FontStyle
.Strikeout
;
1298 case Minor
.Underline
: {
1299 FlushText(rtf
, false);
1300 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1301 rtf_rtfstyle
|= FontStyle
.Underline
;
1303 rtf_rtfstyle
= rtf_rtfstyle
& ~FontStyle
.Underline
;
1308 case Minor
.NoUnderline
: {
1309 FlushText(rtf
, false);
1310 rtf_rtfstyle
&= ~FontStyle
.Underline
;
1317 case RTF
.Major
.SpecialChar
: {
1318 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1325 private void SpecialChar(RTF
.RTF rtf
) {
1332 FlushText(rtf
, true);
1341 case Minor
.NoBrkSpace
: {
1347 rtf_line
.Append ("\t");
1348 // FlushText (rtf, false);
1352 case Minor
.NoReqHyphen
:
1353 case Minor
.NoBrkHyphen
: {
1354 rtf_line
.Append ("-");
1355 // FlushText (rtf, false);
1359 case Minor
.Bullet
: {
1360 Console
.WriteLine("*");
1364 case Minor
.WidowCtrl
:
1367 case Minor
.EmDash
: {
1368 rtf_line
.Append ("\u2014");
1372 case Minor
.EnDash
: {
1373 rtf_line
.Append ("\u2013");
1377 case Minor.LQuote: {
1378 Console.Write("\u2018");
1382 case Minor.RQuote: {
1383 Console.Write("\u2019");
1387 case Minor.LDblQuote: {
1388 Console.Write("\u201C");
1392 case Minor.RDblQuote: {
1393 Console.Write("\u201D");
1398 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1405 private void HandleText(RTF
.RTF rtf
) {
1406 if (rtf_skip_count
> 0) {
1411 if ((RTF
.StandardCharCode
)rtf
.Minor
!= RTF
.StandardCharCode
.nothing
) {
1412 rtf_line
.Append(rtf_text_map
[(RTF
.StandardCharCode
)rtf
.Minor
]);
1414 if ((int)rtf
.Major
> 31 && (int)rtf
.Major
< 128) {
1415 rtf_line
.Append((char)rtf
.Major
);
1417 //rtf_line.Append((char)rtf.Major);
1418 Console
.Write("[Literal:0x{0:X2}]", (int)rtf
.Major
);
1423 private void FlushText(RTF
.RTF rtf
, bool newline
) {
1427 length
= rtf_line
.Length
;
1428 if (!newline
&& (length
== 0)) {
1432 if (rtf_rtffont
== null) {
1433 // First font in table is default
1434 rtf_rtffont
= System
.Windows
.Forms
.RTF
.Font
.GetFont(rtf
, 0);
1437 font
= new Font(rtf_rtffont
.Name
, rtf_rtffont_size
, rtf_rtfstyle
);
1439 if (rtf_color
== null) {
1440 System
.Windows
.Forms
.RTF
.Color color
;
1442 // First color in table is default
1443 color
= System
.Windows
.Forms
.RTF
.Color
.GetColor(rtf
, 0);
1445 if ((color
== null) || (color
.Red
== -1 && color
.Green
== -1 && color
.Blue
== -1)) {
1446 rtf_color
= new SolidBrush(ForeColor
);
1448 rtf_color
= new SolidBrush(Color
.FromArgb(color
.Red
, color
.Green
, color
.Blue
));
1453 rtf_chars
+= rtf_line
.Length
;
1455 if (rtf_cursor_x
== 0) {
1456 document
.Add(rtf_cursor_y
, rtf_line
.ToString(), rtf_rtfalign
, font
, rtf_color
);
1460 line
= document
.GetLine(rtf_cursor_y
);
1461 if (rtf_line
.Length
> 0) {
1462 document
.InsertString(line
, rtf_cursor_x
, rtf_line
.ToString());
1463 document
.FormatText(line
, rtf_cursor_x
+ 1, line
, rtf_cursor_x
+ 1 + length
, font
, rtf_color
, null, FormatSpecified
.Font
| FormatSpecified
.Color
); // FormatText is 1-based
1466 document
.Split(line
, rtf_cursor_x
+ length
);
1474 rtf_cursor_x
+= length
;
1476 rtf_line
.Length
= 0; // Empty line
1479 private void InsertRTFFromStream(Stream data
, int cursor_x
, int cursor_y
) {
1484 InsertRTFFromStream(data
, cursor_x
, cursor_y
, out x
, out y
, out chars
);
1487 private void InsertRTFFromStream(Stream data
, int cursor_x
, int cursor_y
, out int to_x
, out int to_y
, out int chars
) {
1490 rtf
= new RTF
.RTF(data
);
1493 rtf
.ClassCallback
[RTF
.TokenClass
.Text
] = new RTF
.ClassDelegate(HandleText
);
1494 rtf
.ClassCallback
[RTF
.TokenClass
.Control
] = new RTF
.ClassDelegate(HandleControl
);
1498 rtf_line
= new StringBuilder();
1500 rtf_rtffont_size
= (int)this.Font
.Size
;
1501 rtf_rtfalign
= HorizontalAlignment
.Left
;
1502 rtf_rtfstyle
= FontStyle
.Regular
;
1504 rtf_cursor_x
= cursor_x
;
1505 rtf_cursor_y
= cursor_y
;
1507 rtf
.DefaultFont(this.Font
.Name
);
1509 rtf_text_map
= new RTF
.TextMap();
1510 RTF
.TextMap
.SetupStandardTable(rtf_text_map
.Table
);
1512 document
.SuspendRecalc ();
1515 rtf
.Read(); // That's it
1516 FlushText(rtf
, false);
1521 catch (RTF
.RTFException e
) {
1525 // Seems to be plain text or broken RTF
1526 Console
.WriteLine("RTF Parsing failure: {0}", e
.Message
);
1529 to_x
= rtf_cursor_x
;
1530 to_y
= rtf_cursor_y
;
1533 document
.RecalculateDocument(CreateGraphicsInternal(), cursor_y
, document
.Lines
, false);
1534 document
.ResumeRecalc (true);
1536 document
.Invalidate (document
.GetLine(cursor_y
), 0, document
.GetLine(document
.Lines
), -1);
1539 private void RichTextBox_HScrolled(object sender
, EventArgs e
) {
1543 private void RichTextBox_VScrolled(object sender
, EventArgs e
) {
1547 private void PointToTagPos(Point pt
, out LineTag tag
, out int pos
) {
1552 if (p
.X
>= document
.ViewPortWidth
) {
1553 p
.X
= document
.ViewPortWidth
- 1;
1554 } else if (p
.X
< 0) {
1558 if (p
.Y
>= document
.ViewPortHeight
) {
1559 p
.Y
= document
.ViewPortHeight
- 1;
1560 } else if (p
.Y
< 0) {
1564 tag
= document
.FindCursor(p
.X
+ document
.ViewPortX
, p
.Y
+ document
.ViewPortY
, out pos
);
1567 private void EmitRTFFontProperties(StringBuilder rtf
, int prev_index
, int font_index
, Font prev_font
, Font font
) {
1568 if (prev_index
!= font_index
) {
1569 rtf
.Append(String
.Format("\\f{0}", font_index
)); // Font table entry
1572 if ((prev_font
== null) || (prev_font
.Size
!= font
.Size
)) {
1573 rtf
.Append(String
.Format("\\fs{0}", (int)(font
.Size
* 2))); // Font size
1576 if ((prev_font
== null) || (font
.Bold
!= prev_font
.Bold
)) {
1580 if (prev_font
!= null) {
1586 if ((prev_font
== null) || (font
.Italic
!= prev_font
.Italic
)) {
1590 if (prev_font
!= null) {
1596 if ((prev_font
== null) || (font
.Strikeout
!= prev_font
.Strikeout
)) {
1597 if (font
.Strikeout
) {
1598 rtf
.Append("\\strike");
1600 if (prev_font
!= null) {
1601 rtf
.Append("\\strike0");
1606 if ((prev_font
== null) || (font
.Underline
!= prev_font
.Underline
)) {
1607 if (font
.Underline
) {
1610 if (prev_font
!= null) {
1611 rtf
.Append("\\ul0");
1617 [MonoTODO("Emit unicode and other special characters properly")]
1618 private void EmitRTFText(StringBuilder rtf
, string text
) {
1622 // start_pos and end_pos are 0-based
1623 private StringBuilder
GenerateRTF(Line start_line
, int start_pos
, Line end_line
, int end_pos
) {
1637 sb
= new StringBuilder();
1638 fonts
= new ArrayList(10);
1639 colors
= new ArrayList(10);
1641 // Two runs, first we parse to determine tables;
1642 // and unlike most of our processing here we work on tags
1645 line_no
= start_line
.line_no
;
1648 // Add default font and color; to optimize document content we don't
1649 // use this.Font and this.ForeColor but the font/color from the first tag
1650 tag
= LineTag
.FindTag(start_line
, pos
);
1652 color
= ((SolidBrush
)tag
.color
).Color
;
1653 fonts
.Add(font
.Name
);
1656 while (line_no
<= end_line
.line_no
) {
1657 line
= document
.GetLine(line_no
);
1658 tag
= LineTag
.FindTag(line
, pos
);
1660 if (line_no
!= end_line
.line_no
) {
1661 line_len
= line
.text
.Length
;
1666 while (pos
< line_len
) {
1667 if (tag
.font
.Name
!= font
.Name
) {
1669 if (!fonts
.Contains(font
.Name
)) {
1670 fonts
.Add(font
.Name
);
1674 if (((SolidBrush
)tag
.color
).Color
!= color
) {
1675 color
= ((SolidBrush
)tag
.color
).Color
;
1676 if (!colors
.Contains(color
)) {
1681 pos
= tag
.start
+ tag
.length
- 1;
1688 // We have the tables, emit the header
1689 sb
.Append("{\\rtf1\\ansi");
1690 sb
.Append("\\ansicpg1252"); // FIXME - is this correct?
1693 sb
.Append(String
.Format("\\deff{0}", fonts
.IndexOf(this.Font
.Name
)));
1696 sb
.Append("\\deflang1033\n"); // FIXME - always 1033?
1698 // Emit the font table
1699 sb
.Append("{\\fonttbl");
1700 for (i
= 0; i
< fonts
.Count
; i
++) {
1701 sb
.Append(String
.Format("{{\\f{0}", i
)); // {Font
1702 sb
.Append("\\fnil"); // Family
1703 sb
.Append("\\fcharset0 "); // Charset ANSI<space>
1704 sb
.Append((string)fonts
[i
]); // Font name
1705 sb
.Append(";}"); // }
1709 // Emit the color table (if needed)
1710 if ((colors
.Count
> 1) || ((((Color
)colors
[0]).R
!= this.ForeColor
.R
) || (((Color
)colors
[0]).G
!= this.ForeColor
.G
) || (((Color
)colors
[0]).B
!= this.ForeColor
.B
))) {
1711 sb
.Append("{\\colortbl "); // Header and NO! default color
1712 for (i
= 0; i
< colors
.Count
; i
++) {
1713 sb
.Append(String
.Format("\\red{0}", ((Color
)colors
[i
]).R
));
1714 sb
.Append(String
.Format("\\green{0}", ((Color
)colors
[i
]).G
));
1715 sb
.Append(String
.Format("\\blue{0}", ((Color
)colors
[i
]).B
));
1721 sb
.Append("{\\*\\generator Mono RichTextBox;}");
1722 // Emit initial paragraph settings
1723 tag
= LineTag
.FindTag(start_line
, start_pos
);
1724 sb
.Append("\\pard"); // Reset to default paragraph properties
1725 EmitRTFFontProperties(sb
, -1, fonts
.IndexOf(tag
.font
.Name
), null, tag
.font
); // Font properties
1726 sb
.Append(" "); // Space separator
1729 color
= (Color
)colors
[0];
1731 line_no
= start_line
.line_no
;
1734 while (line_no
<= end_line
.line_no
) {
1735 line
= document
.GetLine(line_no
);
1736 tag
= LineTag
.FindTag(line
, pos
);
1738 if (line_no
!= end_line
.line_no
) {
1739 line_len
= line
.text
.Length
;
1744 while (pos
< line_len
) {
1747 if (tag
.font
!= font
) {
1748 EmitRTFFontProperties(sb
, fonts
.IndexOf(font
.Name
), fonts
.IndexOf(tag
.font
.Name
), font
, tag
.font
);
1752 if (((SolidBrush
)tag
.color
).Color
!= color
) {
1753 color
= ((SolidBrush
)tag
.color
).Color
;
1754 sb
.Append(String
.Format("\\cf{0}", colors
.IndexOf(color
)));
1756 if (length
!= sb
.Length
) {
1757 sb
.Append(" "); // Emit space to separate keywords from text
1760 // Emit the string itself
1761 if (line_no
!= end_line
.line_no
) {
1762 EmitRTFText(sb
, tag
.line
.text
.ToString(pos
, tag
.start
+ tag
.length
- pos
- 1));
1764 if (end_pos
< (tag
.start
+ tag
.length
- 1)) {
1765 // Emit partial tag only, end_pos is inside this tag
1766 EmitRTFText(sb
, tag
.line
.text
.ToString(pos
, end_pos
- pos
));
1768 EmitRTFText(sb
, tag
.line
.text
.ToString(pos
, tag
.start
+ tag
.length
- pos
- 1));
1772 pos
= tag
.start
+ tag
.length
- 1;
1775 if (pos
>= line
.text
.Length
) {
1776 if (!line
.soft_break
) {
1777 sb
.Append("\\par\n");
1788 #endregion // Private Methods