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>
30 using System.Collections;
31 using System.ComponentModel;
33 using System.Drawing.Imaging;
36 using System.Runtime.InteropServices;
37 using RTF=System.Windows.Forms.RTF;
39 namespace System.Windows.Forms {
41 [ClassInterface (ClassInterfaceType.AutoDispatch)]
42 [Docking (DockingBehavior.Ask)]
44 [Designer ("System.Windows.Forms.Design.RichTextBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
46 public class RichTextBox : TextBoxBase {
47 #region Local Variables
48 internal bool auto_word_select;
49 internal int bullet_indent;
50 internal bool detect_urls;
51 internal int margin_right;
54 private RTF.TextMap rtf_text_map;
55 private int rtf_skip_width;
56 private int rtf_skip_count;
57 private StringBuilder rtf_line;
58 private SolidBrush rtf_color;
59 private RTF.Font rtf_rtffont;
60 private int rtf_rtffont_size;
61 private FontStyle rtf_rtfstyle;
62 private HorizontalAlignment rtf_rtfalign;
63 private int rtf_cursor_x;
64 private int rtf_cursor_y;
65 private int rtf_chars;
66 private int rtf_par_line_left_indent;
69 private bool enable_auto_drag_drop;
70 private RichTextBoxLanguageOptions language_option;
71 private bool rich_text_shortcuts_enabled;
72 private Color selection_back_color;
74 #endregion // Local Variables
76 #region Public Constructors
77 public RichTextBox() {
78 accepts_return = true;
79 auto_word_select = false;
82 max_length = Int32.MaxValue;
85 base.Multiline = true;
86 document.CRLFSize = 1;
87 shortcuts_enabled = true;
89 scrollbars = RichTextBoxScrollBars.Both;
90 alignment = HorizontalAlignment.Left;
91 LostFocus += new EventHandler(RichTextBox_LostFocus);
92 GotFocus += new EventHandler(RichTextBox_GotFocus);
93 BackColor = ThemeEngine.Current.ColorWindow;
95 backcolor_set = false;
96 language_option = RichTextBoxLanguageOptions.AutoFontSizeAdjust;
97 rich_text_shortcuts_enabled = true;
98 selection_back_color = DefaultBackColor;
100 ForeColor = ThemeEngine.Current.ColorWindowText;
102 base.HScrolled += new EventHandler(RichTextBox_HScrolled);
103 base.VScrolled += new EventHandler(RichTextBox_VScrolled);
106 SetStyle (ControlStyles.StandardDoubleClick, false);
109 #endregion // Public Constructors
111 #region Private & Internal Methods
112 internal override Color ChangeBackColor (Color backColor)
114 if (backColor == Color.Empty) {
116 backcolor_set = false;
118 backColor = SystemColors.Window;
121 backColor = SystemColors.Window;
127 private void RichTextBox_LostFocus(object sender, EventArgs e) {
131 private void RichTextBox_GotFocus(object sender, EventArgs e) {
134 #endregion // Private & Internal Methods
136 #region Public Instance Properties
140 public override bool AllowDrop {
142 return base.AllowDrop;
146 base.AllowDrop = value;
150 [DefaultValue(false)]
152 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
153 [RefreshProperties (RefreshProperties.Repaint)]
154 [EditorBrowsable (EditorBrowsableState.Never)]
159 public override bool AutoSize {
165 base.AutoSize = value;
169 [DefaultValue(false)]
170 public bool AutoWordSelection {
172 return auto_word_select;
176 auto_word_select = true;
181 [EditorBrowsable(EditorBrowsableState.Never)]
182 public override System.Drawing.Image BackgroundImage {
183 get { return base.BackgroundImage; }
184 set { base.BackgroundImage = value; }
189 [EditorBrowsable (EditorBrowsableState.Never)]
190 public override ImageLayout BackgroundImageLayout {
191 get { return base.BackgroundImageLayout; }
192 set { base.BackgroundImageLayout = value; }
198 public int BulletIndent {
200 return bullet_indent;
204 bullet_indent = value;
209 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
210 public bool CanRedo {
212 return document.undo.CanRedo;
217 public bool DetectUrls {
229 [DefaultValue (false)]
230 public bool EnableAutoDragDrop {
231 get { return enable_auto_drag_drop; }
232 set { enable_auto_drag_drop = value; }
236 public override Font Font {
247 if (PreferredHeight != Height) {
248 Height = PreferredHeight;
254 // Font changes always set the whole doc to that font
255 start = document.GetLine(1);
256 end = document.GetLine(document.Lines);
257 document.FormatText(start, 1, end, end.text.Length + 1, base.Font, null, null, FormatSpecified.Font);
262 public override Color ForeColor {
264 return base.ForeColor;
268 base.ForeColor = value;
275 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
276 public RichTextBoxLanguageOptions LanguageOption {
277 get { return language_option; }
278 set { language_option = value; }
282 [DefaultValue(Int32.MaxValue)]
283 public override int MaxLength {
285 return base.max_length;
289 base.max_length = value;
294 public override bool Multiline {
296 return base.Multiline;
300 base.Multiline = value;
305 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
307 public string RedoActionName {
309 return document.undo.RedoActionName;
316 [DefaultValue (true)]
317 [EditorBrowsable (EditorBrowsableState.Never)]
318 public bool RichTextShortcutsEnabled {
319 get { return rich_text_shortcuts_enabled; }
320 set { rich_text_shortcuts_enabled = value; }
326 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
327 public int RightMargin {
333 margin_right = value;
338 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
340 [RefreshProperties (RefreshProperties.All)]
349 start_line = document.GetLine(1);
350 end_line = document.GetLine(document.Lines);
351 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
358 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
360 InsertRTFFromStream(data, 0, 1);
368 [DefaultValue(RichTextBoxScrollBars.Both)]
370 public RichTextBoxScrollBars ScrollBars {
376 if (!Enum.IsDefined (typeof (RichTextBoxScrollBars), value))
377 throw new InvalidEnumArgumentException ("value", (int) value,
378 typeof (RichTextBoxScrollBars));
380 if (value != scrollbars) {
382 CalculateDocument ();
389 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
390 public string SelectedRtf {
392 return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
404 if (document.selection_visible) {
405 document.ReplaceSelection("", false);
408 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
410 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
411 InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y, out chars);
414 document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
415 document.SetSelection(line, sel_start);
416 document.PositionCaret(line, sel_start);
417 document.DisplayCaret();
419 OnTextChanged(EventArgs.Empty);
425 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
426 public override string SelectedText {
428 return base.SelectedText;
432 base.SelectedText = value;
437 [DefaultValue(HorizontalAlignment.Left)]
438 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
439 public HorizontalAlignment SelectionAlignment {
441 HorizontalAlignment align;
446 start = document.ParagraphStart(document.selection_start.line);
447 align = start.alignment;
449 end = document.ParagraphEnd(document.selection_end.line);
454 if (line.alignment != align) {
455 return HorizontalAlignment.Left;
461 line = document.GetLine(line.line_no + 1);
472 start = document.ParagraphStart(document.selection_start.line);
474 end = document.ParagraphEnd(document.selection_end.line);
479 line.alignment = value;
484 line = document.GetLine(line.line_no + 1);
486 this.CalculateDocument();
493 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
494 public Color SelectionBackColor {
495 get { return selection_back_color; }
496 set { selection_back_color = value; }
501 [DefaultValue(false)]
502 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
504 public bool SelectionBullet {
515 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
517 public int SelectionCharOffset {
527 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
528 public Color SelectionColor {
535 start = document.selection_start.line.FindTag (document.selection_start.pos);
536 end = document.selection_start.line.FindTag (document.selection_end.pos);
537 color = start.color.Color;
540 while (tag != null && tag != end) {
542 if (!color.Equals (tag.color.Color))
545 tag = document.NextTag (tag);
555 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
556 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
558 document.FormatText (document.selection_start.line, document.selection_start.pos + 1,
559 document.selection_end.line, document.selection_end.pos + 1, null,
560 new SolidBrush (value), null, FormatSpecified.Color);
562 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
563 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
565 document.UpdateView(document.selection_start.line, 0);
566 document.AlignCaret();
571 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
572 public Font SelectionFont {
579 start = document.selection_start.line.FindTag (document.selection_start.pos);
580 end = document.selection_start.line.FindTag (document.selection_end.pos);
583 if (selection_length > 1) {
585 while (tag != null && tag != end) {
587 if (!font.Equals(tag.font))
590 tag = document.NextTag (tag);
601 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
602 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
604 document.FormatText (document.selection_start.line, document.selection_start.pos + 1,
605 document.selection_end.line, document.selection_end.pos + 1, value,
606 null, null, FormatSpecified.Font);
608 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
609 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
611 document.UpdateView(document.selection_start.line, 0);
612 document.AlignCaret();
619 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
621 public int SelectionHangingIndent {
632 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
634 public int SelectionIndent {
644 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
645 public override int SelectionLength {
647 return base.SelectionLength;
651 base.SelectionLength = value;
656 [DefaultValue(false)]
657 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
659 public bool SelectionProtected {
670 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
672 public int SelectionRightIndent {
682 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
684 public int[] SelectionTabs {
694 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
695 public RichTextBoxSelectionTypes SelectionType {
697 if (document.selection_start == document.selection_end) {
698 return RichTextBoxSelectionTypes.Empty;
702 if (SelectedText.Length > 1) {
703 return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
706 return RichTextBoxSelectionTypes.Text;
710 [DefaultValue(false)]
712 public bool ShowSelectionMargin {
723 [RefreshProperties (RefreshProperties.All)]
725 public override string Text {
736 public override int TextLength {
738 return base.TextLength;
743 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
744 public string UndoActionName {
746 return document.undo.UndoActionName;
752 public float ZoomFactor {
761 #endregion // Public Instance Properties
763 #region Protected Instance Properties
764 protected override CreateParams CreateParams {
766 return base.CreateParams;
770 protected override Size DefaultSize {
772 return new Size(100, 96);
775 #endregion // Protected Instance Properties
777 #region Public Instance Methods
778 public bool CanPaste(DataFormats.Format clipFormat) {
779 if ((clipFormat.Name == DataFormats.Rtf) ||
780 (clipFormat.Name == DataFormats.Text) ||
781 (clipFormat.Name == DataFormats.UnicodeText)) {
787 public int Find(char[] characterSet) {
788 return Find(characterSet, -1, -1);
791 public int Find(char[] characterSet, int start) {
792 return Find(characterSet, start, -1);
795 public int Find(char[] characterSet, int start, int end) {
796 Document.Marker start_mark;
797 Document.Marker end_mark;
798 Document.Marker result;
801 document.GetMarker(out start_mark, true);
807 start_mark = new Document.Marker();
809 document.CharIndexToLineTag(start, out line, out tag, out pos);
810 start_mark.line = line;
811 start_mark.tag = tag;
812 start_mark.pos = pos;
816 document.GetMarker(out end_mark, false);
822 end_mark = new Document.Marker();
824 document.CharIndexToLineTag(end, out line, out tag, out pos);
825 end_mark.line = line;
830 if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
831 return document.LineTagToCharIndex(result.line, result.pos);
837 public int Find(string str) {
838 return Find(str, -1, -1, RichTextBoxFinds.None);
841 public int Find(string str, int start, int end, RichTextBoxFinds options) {
842 Document.Marker start_mark;
843 Document.Marker end_mark;
844 Document.Marker result;
847 document.GetMarker(out start_mark, true);
853 start_mark = new Document.Marker();
855 document.CharIndexToLineTag(start, out line, out tag, out pos);
857 start_mark.line = line;
858 start_mark.tag = tag;
859 start_mark.pos = pos;
863 document.GetMarker(out end_mark, false);
869 end_mark = new Document.Marker();
871 document.CharIndexToLineTag(end, out line, out tag, out pos);
873 end_mark.line = line;
878 if (document.Find(str, start_mark, end_mark, out result, options)) {
879 return document.LineTagToCharIndex(result.line, result.pos);
885 public int Find(string str, int start, RichTextBoxFinds options) {
886 return Find(str, start, -1, options);
889 public int Find(string str, RichTextBoxFinds options) {
890 return Find(str, -1, -1, options);
895 public char GetCharFromPosition(Point pt) {
899 PointToTagPos(pt, out tag, out pos);
901 if (pos >= tag.line.text.Length) {
905 return tag.line.text[pos];
908 internal override char GetCharFromPositionInternal (Point p)
913 PointToTagPos (p, out tag, out pos);
915 if (pos >= tag.line.text.Length)
918 return tag.line.text[pos];
926 int GetCharIndexFromPosition(Point pt) {
930 PointToTagPos(pt, out tag, out pos);
932 return document.LineTagToCharIndex(tag.line, pos);
939 int GetLineFromCharIndex(int index) {
944 document.CharIndexToLineTag(index, out line, out tag, out pos);
946 return line.LineNo - 1;
953 Point GetPositionFromCharIndex(int index) {
958 document.CharIndexToLineTag(index, out line, out tag, out pos);
960 return new Point((int)line.widths[pos] + 1, line.Y + 1);
963 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
967 // FIXME - ignoring unicode
968 if (fileType == RichTextBoxStreamType.PlainText) {
973 sb = new StringBuilder ((int) data.Length);
974 buffer = new char [1024];
976 throw new IOException("Not enough memory to load document");
979 StreamReader sr = new StreamReader (data, Encoding.Default, true);
980 int charsRead = sr.Read (buffer, 0, buffer.Length);
981 while (charsRead > 0) {
982 sb.Append (buffer, 0, charsRead);
983 charsRead = sr.Read (buffer, 0, buffer.Length);
985 base.Text = sb.ToString();
989 InsertRTFFromStream(data, 0, 1);
991 document.PositionCaret (document.GetLine (1), 0);
992 document.SetSelectionToCaret (true);
996 [MonoTODO("Make smarter RTF detection?")]
997 public void LoadFile(string path) {
998 if (path.EndsWith(".rtf")) {
999 LoadFile(path, RichTextBoxStreamType.RichText);
1001 LoadFile(path, RichTextBoxStreamType.PlainText);
1005 public void LoadFile(string path, RichTextBoxStreamType fileType) {
1012 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
1014 LoadFile(data, fileType);
1017 catch (Exception ex) {
1018 throw new IOException("Could not open file " + path, ex);
1028 public void Paste(DataFormats.Format clipFormat) {
1029 base.Paste(Clipboard.GetDataObject(), clipFormat, false);
1034 document.undo.Redo ();
1037 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
1043 if (fileType == RichTextBoxStreamType.UnicodePlainText) {
1044 encoding = Encoding.Unicode;
1046 encoding = Encoding.ASCII;
1050 case RichTextBoxStreamType.PlainText:
1051 case RichTextBoxStreamType.TextTextOleObjs:
1052 case RichTextBoxStreamType.UnicodePlainText: {
1054 bytes = encoding.GetBytes(document.Root.text.ToString());
1055 data.Write(bytes, 0, bytes.Length);
1059 for (i = 1; i < document.Lines; i++) {
1060 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
1061 data.Write(bytes, 0, bytes.Length);
1063 bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
1064 data.Write(bytes, 0, bytes.Length);
1069 // If we're here we're saving RTF
1076 start_line = document.GetLine(1);
1077 end_line = document.GetLine(document.Lines);
1078 rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
1080 bytes = new Byte[4096];
1082 // Let's chunk it so we don't use up all memory...
1083 for (i = 0; i < total; i += 1024) {
1084 if ((i + 1024) < total) {
1085 current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
1087 current = total - i;
1088 current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
1090 data.Write(bytes, 0, current);
1094 public void SaveFile(string path) {
1095 if (path.EndsWith(".rtf")) {
1096 SaveFile(path, RichTextBoxStreamType.RichText);
1098 SaveFile(path, RichTextBoxStreamType.PlainText);
1102 public void SaveFile(string path, RichTextBoxStreamType fileType) {
1108 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
1109 SaveFile(data, fileType);
1113 // throw new IOException("Could not write document to file " + path);
1124 [EditorBrowsable (EditorBrowsableState.Never)]
1125 public new void DrawToBitmap (Bitmap bitmap, Rectangle clip)
1127 Graphics dc = Graphics.FromImage (bitmap);
1129 if (backcolor_set || (Enabled && !read_only)) {
1130 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip);
1132 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl), clip);
1135 // Draw the viewable document
1136 document.Draw (dc, clip);
1140 #endregion // Public Instance Methods
1142 #region Protected Instance Methods
1143 protected virtual object CreateRichEditOleCallback() {
1144 throw new NotImplementedException();
1147 protected override void OnBackColorChanged(EventArgs e) {
1148 base.OnBackColorChanged (e);
1151 protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
1152 ContentsResizedEventHandler eh = (ContentsResizedEventHandler)(Events [ContentsResizedEvent]);
1157 protected override void OnContextMenuChanged(EventArgs e) {
1158 base.OnContextMenuChanged (e);
1161 protected override void OnHandleCreated(EventArgs e) {
1162 base.OnHandleCreated (e);
1165 protected override void OnHandleDestroyed(EventArgs e) {
1166 base.OnHandleDestroyed (e);
1169 protected virtual void OnHScroll(EventArgs e) {
1170 EventHandler eh = (EventHandler)(Events [HScrollEvent]);
1175 [MonoTODO("Determine when to call this")]
1176 protected virtual void OnImeChange(EventArgs e) {
1177 EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
1182 protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
1183 LinkClickedEventHandler eh = (LinkClickedEventHandler)(Events [LinkClickedEvent]);
1188 protected virtual void OnProtected(EventArgs e) {
1189 EventHandler eh = (EventHandler)(Events [ProtectedEvent]);
1194 protected override void OnRightToLeftChanged(EventArgs e) {
1195 base.OnRightToLeftChanged (e);
1198 protected virtual void OnSelectionChanged(EventArgs e) {
1199 EventHandler eh = (EventHandler)(Events [SelectionChangedEvent]);
1205 protected override void OnSystemColorsChanged(EventArgs e) {
1206 base.OnSystemColorsChanged (e);
1209 protected override void OnTextChanged(EventArgs e) {
1210 base.OnTextChanged (e);
1214 protected virtual void OnVScroll(EventArgs e) {
1215 EventHandler eh = (EventHandler)(Events [VScrollEvent]);
1220 protected override void WndProc(ref Message m) {
1221 base.WndProc (ref m);
1225 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
1227 return base.ProcessCmdKey (ref msg, keyData);
1230 #endregion // Protected Instance Methods
1233 static object ContentsResizedEvent = new object ();
1234 static object HScrollEvent = new object ();
1235 static object ImeChangeEvent = new object ();
1236 static object LinkClickedEvent = new object ();
1237 static object ProtectedEvent = new object ();
1238 static object SelectionChangedEvent = new object ();
1239 static object VScrollEvent = new object ();
1242 [EditorBrowsable(EditorBrowsableState.Never)]
1243 public new event EventHandler BackgroundImageChanged {
1244 add { base.BackgroundImageChanged += value; }
1245 remove { base.BackgroundImageChanged -= value; }
1250 [EditorBrowsable (EditorBrowsableState.Never)]
1251 public new event EventHandler BackgroundImageLayoutChanged {
1252 add { base.BackgroundImageLayoutChanged += value; }
1253 remove { base.BackgroundImageLayoutChanged -= value; }
1257 public event ContentsResizedEventHandler ContentsResized {
1258 add { Events.AddHandler (ContentsResizedEvent, value); }
1259 remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1264 [EditorBrowsable(EditorBrowsableState.Never)]
1265 public new event EventHandler DoubleClick {
1266 add { base.DoubleClick += value; }
1267 remove { base.DoubleClick -= value; }
1273 [EditorBrowsable(EditorBrowsableState.Never)]
1275 public new event DragEventHandler DragDrop {
1276 add { base.DragDrop += value; }
1277 remove { base.DragDrop -= value; }
1282 [EditorBrowsable(EditorBrowsableState.Never)]
1284 public new event DragEventHandler DragEnter {
1285 add { base.DragEnter += value; }
1286 remove { base.DragEnter -= value; }
1290 [EditorBrowsable(EditorBrowsableState.Never)]
1291 public new event EventHandler DragLeave {
1292 add { base.DragLeave += value; }
1293 remove { base.DragLeave -= value; }
1298 [EditorBrowsable(EditorBrowsableState.Never)]
1299 public new event DragEventHandler DragOver {
1300 add { base.DragOver += value; }
1301 remove { base.DragOver -= value; }
1306 [EditorBrowsable(EditorBrowsableState.Never)]
1307 public new event GiveFeedbackEventHandler GiveFeedback {
1308 add { base.GiveFeedback += value; }
1309 remove { base.GiveFeedback -= value; }
1312 public event EventHandler HScroll {
1313 add { Events.AddHandler (HScrollEvent, value); }
1314 remove { Events.RemoveHandler (HScrollEvent, value); }
1317 public event EventHandler ImeChange {
1318 add { Events.AddHandler (ImeChangeEvent, value); }
1319 remove { Events.RemoveHandler (ImeChangeEvent, value); }
1322 public event LinkClickedEventHandler LinkClicked {
1323 add { Events.AddHandler (LinkClickedEvent, value); }
1324 remove { Events.RemoveHandler (LinkClickedEvent, value); }
1327 public event EventHandler Protected {
1328 add { Events.AddHandler (ProtectedEvent, value); }
1329 remove { Events.RemoveHandler (ProtectedEvent, value); }
1333 [EditorBrowsable(EditorBrowsableState.Never)]
1334 public new event QueryContinueDragEventHandler QueryContinueDrag {
1335 add { base.QueryContinueDrag += value; }
1336 remove { base.QueryContinueDrag -= value; }
1339 public event EventHandler SelectionChanged {
1340 add { Events.AddHandler (SelectionChangedEvent, value); }
1341 remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1344 public event EventHandler VScroll {
1345 add { Events.AddHandler (VScrollEvent, value); }
1346 remove { Events.RemoveHandler (VScrollEvent, value); }
1348 #endregion // Events
1350 #region Private Methods
1352 internal override void SelectWord ()
1354 document.ExpandSelection(CaretSelection.Word, false);
1357 private void HandleControl(RTF.RTF rtf) {
1359 case RTF.Major.Unicode: {
1361 case RTF.Minor.UnicodeCharBytes: {
1362 rtf_skip_width = rtf.Param;
1366 case RTF.Minor.UnicodeChar: {
1367 rtf_skip_count += rtf_skip_width;
1368 rtf_line.Append((char)rtf.Param);
1375 case RTF.Major.Destination: {
1376 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1381 case RTF.Major.PictAttr:
1382 if (rtf.Picture != null && rtf.Picture.IsValid ()) {
1383 Line line = document.GetLine (rtf_cursor_y);
1384 document.InsertPicture (line, 0, rtf.Picture);
1387 FlushText (rtf, true);
1392 case RTF.Major.CharAttr: {
1394 case RTF.Minor.ForeColor: {
1395 System.Windows.Forms.RTF.Color color;
1397 color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
1399 if (color != null) {
1400 FlushText(rtf, false);
1401 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
1402 this.rtf_color = new SolidBrush(ForeColor);
1404 this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1406 FlushText (rtf, false);
1411 case RTF.Minor.FontSize: {
1412 FlushText(rtf, false);
1413 this.rtf_rtffont_size = rtf.Param / 2;
1417 case RTF.Minor.FontNum: {
1418 System.Windows.Forms.RTF.Font font;
1420 font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
1422 FlushText(rtf, false);
1423 this.rtf_rtffont = font;
1428 case RTF.Minor.Plain: {
1429 FlushText(rtf, false);
1430 rtf_rtfstyle = FontStyle.Regular;
1434 case RTF.Minor.Bold: {
1435 FlushText(rtf, false);
1436 if (rtf.Param == RTF.RTF.NoParam) {
1437 rtf_rtfstyle |= FontStyle.Bold;
1439 rtf_rtfstyle &= ~FontStyle.Bold;
1444 case RTF.Minor.Italic: {
1445 FlushText(rtf, false);
1446 if (rtf.Param == RTF.RTF.NoParam) {
1447 rtf_rtfstyle |= FontStyle.Italic;
1449 rtf_rtfstyle &= ~FontStyle.Italic;
1454 case RTF.Minor.StrikeThru: {
1455 FlushText(rtf, false);
1456 if (rtf.Param == RTF.RTF.NoParam) {
1457 rtf_rtfstyle |= FontStyle.Strikeout;
1459 rtf_rtfstyle &= ~FontStyle.Strikeout;
1464 case RTF.Minor.Underline: {
1465 FlushText(rtf, false);
1466 if (rtf.Param == RTF.RTF.NoParam) {
1467 rtf_rtfstyle |= FontStyle.Underline;
1469 rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline;
1474 case RTF.Minor.NoUnderline: {
1475 FlushText(rtf, false);
1476 rtf_rtfstyle &= ~FontStyle.Underline;
1483 case RTF.Major.ParAttr: {
1484 switch (rtf.Minor) {
1485 case RTF.Minor.LeftIndent:
1486 rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * CreateGraphics ().DpiX + 0.5F);
1492 case RTF.Major.SpecialChar: {
1493 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1500 private void SpecialChar(RTF.RTF rtf) {
1502 case RTF.Minor.Page:
1503 case RTF.Minor.Sect:
1505 case RTF.Minor.Line:
1506 case RTF.Minor.Par: {
1507 FlushText(rtf, true);
1511 case RTF.Minor.Cell: {
1516 case RTF.Minor.NoBrkSpace: {
1521 case RTF.Minor.Tab: {
1522 rtf_line.Append ("\t");
1523 // FlushText (rtf, false);
1527 case RTF.Minor.NoReqHyphen:
1528 case RTF.Minor.NoBrkHyphen: {
1529 rtf_line.Append ("-");
1530 // FlushText (rtf, false);
1534 case RTF.Minor.Bullet: {
1535 Console.WriteLine("*");
1539 case RTF.Minor.WidowCtrl:
1542 case RTF.Minor.EmDash: {
1543 rtf_line.Append ("\u2014");
1547 case RTF.Minor.EnDash: {
1548 rtf_line.Append ("\u2013");
1552 case RTF.Minor.LQuote: {
1553 Console.Write("\u2018");
1557 case RTF.Minor.RQuote: {
1558 Console.Write("\u2019");
1562 case RTF.Minor.LDblQuote: {
1563 Console.Write("\u201C");
1567 case RTF.Minor.RDblQuote: {
1568 Console.Write("\u201D");
1573 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1580 private void HandleText(RTF.RTF rtf) {
1581 if (rtf_skip_count > 0) {
1587 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1588 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1590 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1591 rtf_line.Append((char)rtf.Major);
1593 //rtf_line.Append((char)rtf.Major);
1594 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1598 rtf_line.Append (rtf.EncodedText);
1601 private void FlushText(RTF.RTF rtf, bool newline) {
1605 length = rtf_line.Length;
1606 if (!newline && (length == 0)) {
1610 if (rtf_rtffont == null) {
1611 // First font in table is default
1612 rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0);
1615 font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1617 if (rtf_color == null) {
1618 System.Windows.Forms.RTF.Color color;
1620 // First color in table is default
1621 color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0);
1623 if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
1624 rtf_color = new SolidBrush(ForeColor);
1626 rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1631 rtf_chars += rtf_line.Length;
1635 if (rtf_cursor_x == 0) {
1636 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color,
1637 newline ? LineEnding.Rich : LineEnding.Wrap);
1638 if (rtf_par_line_left_indent != 0) {
1639 Line line = document.GetLine (rtf_cursor_y);
1640 line.indent = rtf_par_line_left_indent;
1645 line = document.GetLine(rtf_cursor_y);
1646 line.indent = rtf_par_line_left_indent;
1647 if (rtf_line.Length > 0) {
1648 document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1649 document.FormatText (line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length,
1650 font, rtf_color, null,
1651 FormatSpecified.Font | FormatSpecified.Color);
1654 document.Split(line, rtf_cursor_x + length);
1655 line = document.GetLine (rtf_cursor_y);
1656 line.ending = LineEnding.Rich;
1664 rtf_cursor_x += length;
1666 rtf_line.Length = 0; // Empty line
1669 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1674 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
1677 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) {
1680 rtf = new RTF.RTF(data);
1683 rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1684 rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1688 rtf_line = new StringBuilder();
1690 rtf_rtffont_size = (int)this.Font.Size;
1691 rtf_rtfalign = HorizontalAlignment.Left;
1692 rtf_rtfstyle = FontStyle.Regular;
1694 rtf_cursor_x = cursor_x;
1695 rtf_cursor_y = cursor_y;
1697 rtf.DefaultFont(this.Font.Name);
1699 rtf_text_map = new RTF.TextMap();
1700 RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1702 document.SuspendRecalc ();
1705 rtf.Read(); // That's it
1706 FlushText(rtf, false);
1711 catch (RTF.RTFException e) {
1715 // Seems to be plain text or broken RTF
1716 Console.WriteLine("RTF Parsing failure: {0}", e.Message);
1719 to_x = rtf_cursor_x;
1720 to_y = rtf_cursor_y;
1723 document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
1724 document.ResumeRecalc (true);
1726 document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1729 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1733 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1737 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1742 if (p.X >= document.ViewPortWidth) {
1743 p.X = document.ViewPortWidth - 1;
1744 } else if (p.X < 0) {
1748 if (p.Y >= document.ViewPortHeight) {
1749 p.Y = document.ViewPortHeight - 1;
1750 } else if (p.Y < 0) {
1754 tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1757 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1758 if (prev_index != font_index) {
1759 rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry
1762 if ((prev_font == null) || (prev_font.Size != font.Size)) {
1763 rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size
1766 if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1770 if (prev_font != null) {
1776 if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1780 if (prev_font != null) {
1786 if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1787 if (font.Strikeout) {
1788 rtf.Append("\\strike");
1790 if (prev_font != null) {
1791 rtf.Append("\\strike0");
1796 if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1797 if (font.Underline) {
1800 if (prev_font != null) {
1801 rtf.Append("\\ul0");
1807 [MonoTODO("Emit unicode and other special characters properly")]
1808 private void EmitRTFText(StringBuilder rtf, string text) {
1812 // start_pos and end_pos are 0-based
1813 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1827 sb = new StringBuilder();
1828 fonts = new ArrayList(10);
1829 colors = new ArrayList(10);
1831 // Two runs, first we parse to determine tables;
1832 // and unlike most of our processing here we work on tags
1835 line_no = start_line.line_no;
1838 // Add default font and color; to optimize document content we don't
1839 // use this.Font and this.ForeColor but the font/color from the first tag
1840 tag = LineTag.FindTag(start_line, pos);
1842 color = ((SolidBrush)tag.color).Color;
1843 fonts.Add(font.Name);
1846 while (line_no <= end_line.line_no) {
1847 line = document.GetLine(line_no);
1848 tag = LineTag.FindTag(line, pos);
1850 if (line_no != end_line.line_no) {
1851 line_len = line.text.Length;
1856 while (pos < line_len) {
1857 if (tag.font.Name != font.Name) {
1859 if (!fonts.Contains(font.Name)) {
1860 fonts.Add(font.Name);
1864 if (((SolidBrush)tag.color).Color != color) {
1865 color = ((SolidBrush)tag.color).Color;
1866 if (!colors.Contains(color)) {
1871 pos = tag.start + tag.Length - 1;
1878 // We have the tables, emit the header
1879 sb.Append("{\\rtf1\\ansi");
1880 sb.Append("\\ansicpg1252"); // FIXME - is this correct?
1883 sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1886 sb.Append("\\deflang1033\n"); // FIXME - always 1033?
1888 // Emit the font table
1889 sb.Append("{\\fonttbl");
1890 for (i = 0; i < fonts.Count; i++) {
1891 sb.Append(String.Format("{{\\f{0}", i)); // {Font
1892 sb.Append("\\fnil"); // Family
1893 sb.Append("\\fcharset0 "); // Charset ANSI<space>
1894 sb.Append((string)fonts[i]); // Font name
1895 sb.Append(";}"); // }
1899 // Emit the color table (if needed)
1900 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))) {
1901 sb.Append("{\\colortbl "); // Header and NO! default color
1902 for (i = 0; i < colors.Count; i++) {
1903 sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1904 sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1905 sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1911 sb.Append("{\\*\\generator Mono RichTextBox;}");
1912 // Emit initial paragraph settings
1913 tag = LineTag.FindTag(start_line, start_pos);
1914 sb.Append("\\pard"); // Reset to default paragraph properties
1915 EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font); // Font properties
1916 sb.Append(" "); // Space separator
1919 color = (Color)colors[0];
1921 line_no = start_line.line_no;
1924 while (line_no <= end_line.line_no) {
1925 line = document.GetLine(line_no);
1926 tag = LineTag.FindTag(line, pos);
1928 if (line_no != end_line.line_no) {
1929 line_len = line.text.Length;
1934 while (pos < line_len) {
1937 if (tag.font != font) {
1938 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1942 if (((SolidBrush)tag.color).Color != color) {
1943 color = ((SolidBrush)tag.color).Color;
1944 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1946 if (length != sb.Length) {
1947 sb.Append(" "); // Emit space to separate keywords from text
1950 // Emit the string itself
1951 if (line_no != end_line.line_no) {
1952 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.Length - pos - 1));
1954 if (end_pos < (tag.start + tag.Length - 1)) {
1955 // Emit partial tag only, end_pos is inside this tag
1956 EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1958 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.Length - pos - 1));
1962 pos = tag.start + tag.Length - 1;
1965 if (pos >= line.text.Length) {
1966 if (line.ending != LineEnding.Wrap) {
1967 sb.Append("\\par\n");
1978 #endregion // Private Methods