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 Novell, Inc. (http://www.novell.com)
23 // Peter Bartok <pbartok@novell.com>
30 using System.Collections;
31 using System.ComponentModel;
35 using RTF=System.Windows.Forms.RTF;
37 namespace System.Windows.Forms {
38 public class RichTextBox : TextBoxBase {
39 #region Local Variables
40 internal bool auto_word_select;
41 internal int bullet_indent;
42 internal bool can_redo;
43 internal bool detect_urls;
44 internal string redo_action_name;
45 internal int margin_right;
46 internal string undo_action_name;
49 private RTF.TextMap rtf_text_map;
50 private int rtf_skip_width;
51 private int rtf_skip_count;
52 private StringBuilder rtf_line;
53 private Font rtf_font;
54 private SolidBrush rtf_color;
55 private RTF.Font rtf_rtffont;
56 private int rtf_rtffont_size;
57 private FontStyle rtf_rtfstyle;
58 private HorizontalAlignment rtf_rtfalign;
59 private int rtf_cursor_x;
60 private int rtf_cursor_y;
61 #endregion // Local Variables
63 #region Public Constructors
64 public RichTextBox() {
65 accepts_return = true;
66 auto_word_select = false;
70 max_length = Int32.MaxValue;
71 redo_action_name = string.Empty;
73 undo_action_name = string.Empty;
75 base.Multiline = true;
76 document.CRLFSize = 1;
78 scrollbars = RichTextBoxScrollBars.Both;
79 alignment = HorizontalAlignment.Left;
80 LostFocus += new EventHandler(RichTextBox_LostFocus);
81 GotFocus += new EventHandler(RichTextBox_GotFocus);
82 BackColor = ThemeEngine.Current.ColorWindow;
83 ForeColor = ThemeEngine.Current.ColorWindowText;
84 base.HScrolled += new EventHandler(RichTextBox_HScrolled);
85 base.VScrolled += new EventHandler(RichTextBox_VScrolled);
87 #endregion // Public Constructors
89 #region Private & Internal Methods
90 private void RichTextBox_LostFocus(object sender, EventArgs e) {
95 private void RichTextBox_GotFocus(object sender, EventArgs e) {
99 #endregion // Private & Internal Methods
101 #region Public Instance Properties
102 public override bool AllowDrop {
104 return base.AllowDrop;
108 base.AllowDrop = value;
112 [DefaultValue(false)]
114 public override bool AutoSize {
120 base.AutoSize = value;
124 [DefaultValue(false)]
125 public bool AutoWordSelection {
127 return auto_word_select;
131 auto_word_select = true;
136 [EditorBrowsable(EditorBrowsableState.Never)]
137 public override System.Drawing.Image BackgroundImage {
139 return background_image;
143 base.BackgroundImage = value;
149 public int BulletIndent {
151 return bullet_indent;
155 bullet_indent = value;
160 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
161 public bool CanRedo {
168 public bool DetectUrls {
178 public override Font Font {
189 if (PreferredHeight != Height) {
190 Height = PreferredHeight;
196 // Font changes always set the whole doc to that font
197 start = document.GetLine(1);
198 end = document.GetLine(document.Lines);
199 document.FormatText(start, 1, end, end.text.Length, base.Font, new SolidBrush(this.ForeColor));
204 public override Color ForeColor {
206 return base.ForeColor;
210 base.ForeColor = value;
214 [DefaultValue(Int32.MaxValue)]
215 public override int MaxLength {
217 return base.max_length;
221 base.max_length = value;
226 public override bool Multiline {
232 base.Multiline = value;
237 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
239 public string RedoActionName {
241 return redo_action_name;
247 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
248 public int RightMargin {
254 margin_right = value;
260 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
261 [MonoTODO("Implement setter")]
269 start_line = document.GetLine(1);
270 end_line = document.GetLine(document.Lines);
271 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
278 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
280 InsertRTFFromStream(data, 0, 1);
286 [DefaultValue(RichTextBoxScrollBars.Both)]
288 public RichTextBoxScrollBars ScrollBars {
300 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
301 [MonoTODO("Implement setter")]
302 public string SelectedRtf {
304 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("");
317 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
318 InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y);
321 line = document.GetLine(y);
322 document.SetSelection(document.GetLine(y), x);
323 document.PositionCaret(line, x);
325 OnTextChanged(EventArgs.Empty);
331 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
332 public override string SelectedText {
334 return base.SelectedText;
338 base.SelectedText = value;
343 [DefaultValue(HorizontalAlignment.Left)]
344 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
345 public HorizontalAlignment SelectionAlignment {
347 HorizontalAlignment align;
352 start = document.ParagraphStart(document.selection_start.line);
353 align = start.alignment;
355 end = document.ParagraphEnd(document.selection_end.line);
360 if (line.alignment != align) {
361 return HorizontalAlignment.Left;
367 line = document.GetLine(line.line_no + 1);
378 start = document.ParagraphStart(document.selection_start.line);
380 end = document.ParagraphEnd(document.selection_end.line);
385 line.alignment = value;
390 line = document.GetLine(line.line_no + 1);
392 this.CalculateDocument();
397 public Color SelectionColor {
399 throw new NotImplementedException();
406 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
407 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
408 Console.WriteLine("FIXME - SelectionColor should not alter font");
409 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos, document.selection_start.tag.font, new SolidBrush(value));
411 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
412 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
414 document.UpdateView(document.selection_start.line, 0);
415 document.AlignCaret();
420 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
421 public Font SelectionFont {
428 start = document.selection_start.tag;
429 end = document.selection_end.tag;
430 font = document.selection_start.tag.font;
434 if (!font.Equals(tag.font)) {
442 tag = document.NextTag(tag);
456 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
457 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
459 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos, value, document.selection_start.tag.color);
461 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
462 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
464 document.UpdateView(document.selection_start.line, 0);
465 document.AlignCaret();
471 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
472 public RichTextBoxSelectionTypes SelectionType {
474 if (document.selection_start == document.selection_end) {
475 return RichTextBoxSelectionTypes.Empty;
479 if (SelectedText.Length > 1) {
480 return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
483 return RichTextBoxSelectionTypes.Text;
488 public override string Text {
499 public override int TextLength {
501 return base.TextLength;
506 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
507 public string UndoActionName {
509 return undo_action_name;
515 public float ZoomFactor {
524 #endregion // Public Instance Properties
526 #region Protected Instance Properties
527 protected override CreateParams CreateParams {
529 return base.CreateParams;
533 protected override Size DefaultSize {
535 return new Size(100, 96);
538 #endregion // Protected Instance Properties
540 #region Public Instance Methods
541 public int Find(char[] characterSet) {
542 return Find(characterSet, -1, -1);
545 public int Find(char[] characterSet, int start) {
546 return Find(characterSet, start, -1);
549 public int Find(char[] characterSet, int start, int end) {
550 Document.Marker start_mark;
551 Document.Marker end_mark;
552 Document.Marker result;
555 document.GetMarker(out start_mark, true);
561 start_mark = new Document.Marker();
563 document.CharIndexToLineTag(start, out line, out tag, out pos);
564 start_mark.line = line;
565 start_mark.tag = tag;
566 start_mark.pos = pos;
570 document.GetMarker(out end_mark, false);
576 end_mark = new Document.Marker();
578 document.CharIndexToLineTag(end, out line, out tag, out pos);
579 end_mark.line = line;
584 if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
585 return document.LineTagToCharIndex(result.line, result.pos);
591 public int Find(string str) {
592 return Find(str, -1, -1, RichTextBoxFinds.None);
595 public int Find(string str, int start, int end, RichTextBoxFinds options) {
596 Document.Marker start_mark;
597 Document.Marker end_mark;
598 Document.Marker result;
601 document.GetMarker(out start_mark, true);
607 start_mark = new Document.Marker();
609 document.CharIndexToLineTag(start, out line, out tag, out pos);
611 start_mark.line = line;
612 start_mark.tag = tag;
613 start_mark.pos = pos;
617 document.GetMarker(out end_mark, false);
623 end_mark = new Document.Marker();
625 document.CharIndexToLineTag(end, out line, out tag, out pos);
627 end_mark.line = line;
632 if (document.Find(str, start_mark, end_mark, out result, options)) {
633 return document.LineTagToCharIndex(result.line, result.pos);
639 public int Find(string str, int start, RichTextBoxFinds options) {
640 return Find(str, start, -1, options);
643 public int Find(string str, RichTextBoxFinds options) {
644 return Find(str, -1, -1, options);
647 public char GetCharFromPosition(Point pt) {
651 PointToTagPos(pt, out tag, out pos);
653 if (pos >= tag.line.text.Length) {
657 return tag.line.text[pos];
661 public int GetCharIndexFromPosition(Point pt) {
665 PointToTagPos(pt, out tag, out pos);
667 return document.LineTagToCharIndex(tag.line, pos);
670 public int GetLineFromCharIndex(int index) {
675 document.CharIndexToLineTag(index, out line, out tag, out pos);
677 return line.LineNo - 1;
680 public Point GetPositionFromCharIndex(int index) {
685 document.CharIndexToLineTag(index, out line, out tag, out pos);
687 return new Point((int)line.widths[pos] + 1, line.Y + 1);
690 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
691 RTF.RTF rtf; // Not 'using SWF.RTF' to avoid ambiguities with font and color
695 // FIXME - ignoring unicode
696 if (fileType == RichTextBoxStreamType.PlainText) {
702 sb = new StringBuilder((int)data.Length);
703 buffer = new byte[1024];
707 throw new IOException("Not enough memory to load document");
711 while (count < data.Length) {
712 count += data.Read(buffer, count, 1024);
715 base.Text = sb.ToString();
719 InsertRTFFromStream(data, 0, 1);
722 [MonoTODO("Make smarter RTF detection")]
723 public void LoadFile(string path) {
724 if (path.EndsWith(".rtf")) {
725 LoadFile(path, RichTextBoxStreamType.RichText);
727 LoadFile(path, RichTextBoxStreamType.PlainText);
731 public void LoadFile(string path, RichTextBoxStreamType fileType) {
737 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
738 LoadFile(data, fileType);
742 throw new IOException("Could not open file " + path);
752 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
758 if (fileType == RichTextBoxStreamType.UnicodePlainText) {
759 encoding = Encoding.Unicode;
761 encoding = Encoding.ASCII;
765 case RichTextBoxStreamType.PlainText:
766 case RichTextBoxStreamType.TextTextOleObjs:
767 case RichTextBoxStreamType.UnicodePlainText: {
769 bytes = encoding.GetBytes(document.Root.text.ToString());
770 data.Write(bytes, 0, bytes.Length);
774 for (i = 1; i < document.Lines; i++) {
775 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
776 data.Write(bytes, 0, bytes.Length);
778 bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
779 data.Write(bytes, 0, bytes.Length);
784 // If we're here we're saving RTF
791 start_line = document.GetLine(1);
792 end_line = document.GetLine(document.Lines);
793 rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
795 bytes = new Byte[4096];
797 // Let's chunk it so we don't use up all memory...
798 for (i = 0; i < total; i += 1024) {
799 if ((i + 1024) < total) {
800 current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
803 current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
805 data.Write(bytes, 0, current);
809 public void SaveFile(string path) {
810 if (path.EndsWith(".rtf")) {
811 SaveFile(path, RichTextBoxStreamType.RichText);
813 SaveFile(path, RichTextBoxStreamType.PlainText);
817 public void SaveFile(string path, RichTextBoxStreamType fileType) {
823 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
824 SaveFile(data, fileType);
828 // throw new IOException("Could not write document to file " + path);
838 #endregion // Public Instance Methods
840 #region Protected Instance Methods
841 protected override void OnBackColorChanged(EventArgs e) {
842 base.OnBackColorChanged (e);
845 protected override void OnContextMenuChanged(EventArgs e) {
846 base.OnContextMenuChanged (e);
849 protected override void OnHandleCreated(EventArgs e) {
850 base.OnHandleCreated (e);
853 protected override void OnHandleDestroyed(EventArgs e) {
854 base.OnHandleDestroyed (e);
857 protected virtual void OnHScroll(EventArgs e) {
858 if (HScroll != null) {
863 protected override void OnRightToLeftChanged(EventArgs e) {
864 base.OnRightToLeftChanged (e);
867 protected override void OnSystemColorsChanged(EventArgs e) {
868 base.OnSystemColorsChanged (e);
871 protected override void OnTextChanged(EventArgs e) {
872 base.OnTextChanged (e);
875 protected virtual void OnVScroll(EventArgs e) {
876 if (VScroll != null) {
881 protected override void WndProc(ref Message m) {
882 base.WndProc (ref m);
884 #endregion // Protected Instance Methods
888 [EditorBrowsable(EditorBrowsableState.Never)]
889 public event EventHandler BackgroundImageChanged;
891 public event ContentsResizedEventHandler ContentsResized;
894 [EditorBrowsable(EditorBrowsableState.Never)]
895 public event EventHandler DoubleClick;
898 [EditorBrowsable(EditorBrowsableState.Never)]
899 public event DragEventHandler DragDrop;
902 [EditorBrowsable(EditorBrowsableState.Never)]
903 public event DragEventHandler DragEnter;
906 [EditorBrowsable(EditorBrowsableState.Never)]
907 public event EventHandler DragLeave;
910 [EditorBrowsable(EditorBrowsableState.Never)]
911 public event DragEventHandler DragOver;
914 [EditorBrowsable(EditorBrowsableState.Never)]
915 public event GiveFeedbackEventHandler GiveFeedback;
917 public event EventHandler HScroll;
918 public event EventHandler ImeChange;
919 public event LinkClickedEventHandler LinkClicked;
920 public event EventHandler Protected;
923 [EditorBrowsable(EditorBrowsableState.Never)]
924 public event QueryContinueDragEventHandler QueryContinueDrag;
925 public event EventHandler SelectionChanged;
926 public event EventHandler VScroll;
929 #region Private Methods
930 private void HandleControl(RTF.RTF rtf) {
932 case RTF.Major.Unicode: {
934 case Minor.UnicodeCharBytes: {
935 rtf_skip_width = rtf.Param;
939 case Minor.UnicodeChar: {
940 rtf_skip_count += rtf_skip_width;
941 rtf_line.Append((char)rtf.Param);
948 case RTF.Major.Destination: {
949 Console.Write("[Got Destination control {0}]", rtf.Minor);
954 case RTF.Major.CharAttr: {
956 case Minor.ForeColor: {
957 System.Windows.Forms.RTF.Color color;
959 color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
962 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
963 this.rtf_color = new SolidBrush(ForeColor);
965 this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
971 case Minor.FontSize: {
972 this.rtf_rtffont_size = rtf.Param / 2;
976 case Minor.FontNum: {
977 System.Windows.Forms.RTF.Font font;
979 font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
982 this.rtf_rtffont = font;
989 rtf_rtfstyle = FontStyle.Regular;
995 if (rtf.Param == RTF.RTF.NoParam) {
996 rtf_rtfstyle |= FontStyle.Bold;
998 rtf_rtfstyle &= ~FontStyle.Bold;
1003 case Minor.Italic: {
1005 if (rtf.Param == RTF.RTF.NoParam) {
1006 rtf_rtfstyle |= FontStyle.Italic;
1008 rtf_rtfstyle &= ~FontStyle.Italic;
1013 case Minor.StrikeThru: {
1015 if (rtf.Param == RTF.RTF.NoParam) {
1016 rtf_rtfstyle |= FontStyle.Strikeout;
1018 rtf_rtfstyle &= ~FontStyle.Strikeout;
1023 case Minor.Underline: {
1025 if (rtf.Param == RTF.RTF.NoParam) {
1026 rtf_rtfstyle |= FontStyle.Underline;
1028 rtf_rtfstyle &= ~FontStyle.Underline;
1033 case Minor.NoUnderline: {
1035 rtf_rtfstyle &= ~FontStyle.Underline;
1042 case RTF.Major.SpecialChar: {
1043 Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1050 private void SpecialChar(RTF.RTF rtf) {
1066 case Minor.NoBrkSpace: {
1072 Console.Write("\t");
1076 case Minor.NoBrkHyphen: {
1081 case Minor.Bullet: {
1086 case Minor.EmDash: {
1087 Console.Write("
\97");
1091 case Minor.EnDash: {
1092 Console.Write("
\96");
1096 case Minor.LQuote: {
1097 Console.Write("
\91");
1101 case Minor.RQuote: {
1102 Console.Write("
\92");
1106 case Minor.LDblQuote: {
1107 Console.Write("
\93");
1111 case Minor.RDblQuote: {
1112 Console.Write("
\94");
1123 private void HandleText(RTF.RTF rtf) {
1124 if (rtf_skip_count > 0) {
1129 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1130 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1132 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1133 rtf_line.Append((char)rtf.Major);
1135 //rtf_line.Append((char)rtf.Major);
1136 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1141 private void FlushText(bool newline) {
1145 length = rtf_line.Length;
1150 if (rtf_rtffont != null) {
1151 font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1156 if (rtf_cursor_x == 0) {
1157 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color);
1161 line = document.GetLine(rtf_cursor_y);
1162 document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1163 document.FormatText(line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, font, rtf_color); // FormatText is 1-based
1170 rtf_cursor_x += length;
1172 rtf_line.Length = 0; // Empty line
1175 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1179 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y);
1181 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y) {
1184 rtf = new RTF.RTF(data);
1187 rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1188 rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1192 rtf_line = new StringBuilder();
1194 rtf_color = new SolidBrush(ForeColor);
1195 rtf_rtffont_size = this.Font.Height;
1196 rtf_rtfalign = HorizontalAlignment.Left;
1198 rtf_cursor_x = cursor_x;
1199 rtf_cursor_y = cursor_y;
1201 rtf_text_map = new RTF.TextMap();
1202 RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1205 rtf.Read(); // That's it
1209 catch (RTF.RTFException) {
1210 // Seems to be plain text...
1214 to_x = rtf_cursor_x;
1215 to_y = rtf_cursor_y;
1217 document.RecalculateDocument(CreateGraphics(), cursor_y, document.Lines, false);
1218 document.Invalidate(document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1221 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1225 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1229 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1234 if (p.X >= document.ViewPortWidth) {
1235 p.X = document.ViewPortWidth - 1;
1236 } else if (p.X < 0) {
1240 if (p.Y >= document.ViewPortHeight) {
1241 p.Y = document.ViewPortHeight - 1;
1242 } else if (p.Y < 0) {
1246 tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1249 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1250 if (prev_index != font_index) {
1251 rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry
1254 if ((prev_font == null) || (prev_font.Height != font.Height)) {
1255 rtf.Append(String.Format("\\fs{0}", font.Height * 2)); // Font size
1258 if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1262 if (prev_font != null) {
1268 if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1272 if (prev_font != null) {
1278 if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1279 if (font.Strikeout) {
1280 rtf.Append("\\strike");
1282 if (prev_font != null) {
1283 rtf.Append("\\strike0");
1288 if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1289 if (font.Underline) {
1292 if (prev_font != null) {
1293 rtf.Append("\\ul0");
1299 [MonoTODO("Emit unicode and other special characters properly")]
1300 private void EmitRTFText(StringBuilder rtf, string text) {
1304 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1318 sb = new StringBuilder();
1319 fonts = new ArrayList(10);
1320 colors = new ArrayList(10);
1322 // Two runs, first we parse to determine tables;
1323 // and unlike most of our processing here we work on tags
1326 line_no = start_line.line_no;
1329 // Add default font and color; to optimize document content we don't
1330 // use this.Font and this.ForeColor but the font/color from the first tag
1331 tag = LineTag.FindTag(start_line, pos);
1333 color = ((SolidBrush)tag.color).Color;
1334 fonts.Add(font.Name);
1337 while (line_no <= end_line.line_no) {
1338 line = document.GetLine(line_no);
1339 tag = LineTag.FindTag(line, pos);
1341 if (line_no != end_line.line_no) {
1342 line_len = line.text.Length;
1347 while (pos < line_len) {
1348 if (tag.font.Name != font.Name) {
1350 if (!fonts.Contains(font.Name)) {
1351 fonts.Add(font.Name);
1355 if (((SolidBrush)tag.color).Color != color) {
1356 color = ((SolidBrush)tag.color).Color;
1357 if (!colors.Contains(color)) {
1369 // We have the tables, emit the header
1370 sb.Append("{\\rtf1\\ansi");
1371 sb.Append("\\ansicpg1252"); // FIXME - is this correct?
1374 sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1377 sb.Append("\\deflang1033\n"); // FIXME - always 1033?
1379 // Emit the font table
1380 sb.Append("{\\fonttbl");
1381 for (i = 0; i < fonts.Count; i++) {
1382 sb.Append(String.Format("{{\\f{0}", i)); // {Font
1383 sb.Append("\\fnil"); // Family
1384 sb.Append("\\fcharset0 "); // Charset ANSI<space>
1385 sb.Append((string)fonts[i]); // Font name
1386 sb.Append(";}"); // }
1390 // Emit the color table (if needed)
1391 if (colors.Count > 1) {
1392 sb.Append("{\\colortbl "); // Header and NO! default color
1393 for (i = 0; i < colors.Count; i++) {
1394 sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1395 sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1396 sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1402 sb.Append("{\\*\\generator Mono RichTextBox;}");
1403 // Emit initial paragraph settings
1404 tag = LineTag.FindTag(start_line, start_pos);
1405 sb.Append("\\pard"); // Reset to default paragraph properties
1406 EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font); // Font properties
1407 sb.Append(" "); // Space separator
1410 color = (Color)colors[0];
1412 line_no = start_line.line_no;
1415 while (line_no <= end_line.line_no) {
1416 line = document.GetLine(line_no);
1417 tag = LineTag.FindTag(line, pos);
1419 if (line_no != end_line.line_no) {
1420 line_len = line.text.Length;
1425 while (pos < line_len) {
1428 if (tag.font != font) {
1429 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1433 if (((SolidBrush)tag.color).Color != color) {
1434 color = ((SolidBrush)tag.color).Color;
1435 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1437 if (length != sb.Length) {
1438 sb.Append(" "); // Emit space to separate keywords from text
1441 // Emit the string itself
1442 if (line_no != end_line.line_no) {
1443 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1445 if (end_pos < (tag.start + tag.length - 1)) {
1446 // Emit partial tag only, end_pos is inside this tag
1447 EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1449 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1456 if (!line.soft_break) {
1457 sb.Append("\\par\n");
1467 #endregion // Private Methods