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 private bool reuse_line; // Sometimes we are loading text with already available lines
52 internal int margin_right;
54 private StringBuilder rtf_line;
56 private RtfSectionStyle rtf_style; // Replaces individual style
57 // properties so we can revert
58 private Stack rtf_section_stack;
60 private RTF.TextMap rtf_text_map;
61 private int rtf_skip_count;
62 private int rtf_cursor_x;
63 private int rtf_cursor_y;
64 private int rtf_chars;
67 private bool enable_auto_drag_drop;
68 private RichTextBoxLanguageOptions language_option;
69 private bool rich_text_shortcuts_enabled;
70 private Color selection_back_color;
72 #endregion // Local Variables
74 #region Public Constructors
75 public RichTextBox() {
76 accepts_return = true;
78 auto_word_select = false;
80 base.MaxLength = Int32.MaxValue;
83 base.Multiline = true;
84 document.CRLFSize = 1;
85 shortcuts_enabled = true;
86 base.EnableLinks = true;
89 rtf_style = new RtfSectionStyle ();
90 rtf_section_stack = null;
92 scrollbars = RichTextBoxScrollBars.Both;
93 alignment = HorizontalAlignment.Left;
94 LostFocus += new EventHandler(RichTextBox_LostFocus);
95 GotFocus += new EventHandler(RichTextBox_GotFocus);
96 BackColor = ThemeEngine.Current.ColorWindow;
98 backcolor_set = false;
99 language_option = RichTextBoxLanguageOptions.AutoFontSizeAdjust;
100 rich_text_shortcuts_enabled = true;
101 selection_back_color = DefaultBackColor;
103 ForeColor = ThemeEngine.Current.ColorWindowText;
105 base.HScrolled += new EventHandler(RichTextBox_HScrolled);
106 base.VScrolled += new EventHandler(RichTextBox_VScrolled);
109 SetStyle (ControlStyles.StandardDoubleClick, false);
112 #endregion // Public Constructors
114 #region Private & Internal Methods
116 internal override void HandleLinkClicked (LinkRectangle link)
118 OnLinkClicked (new LinkClickedEventArgs (link.LinkTag.LinkText));
121 internal override Color ChangeBackColor (Color backColor)
123 if (backColor == Color.Empty) {
125 backcolor_set = false;
127 backColor = SystemColors.Window;
130 backColor = SystemColors.Window;
136 internal override void RaiseSelectionChanged()
138 OnSelectionChanged (EventArgs.Empty);
141 private void RichTextBox_LostFocus(object sender, EventArgs e) {
145 private void RichTextBox_GotFocus(object sender, EventArgs e) {
148 #endregion // Private & Internal Methods
150 #region Public Instance Properties
154 public override bool AllowDrop {
156 return base.AllowDrop;
160 base.AllowDrop = value;
164 [DefaultValue(false)]
166 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
167 [RefreshProperties (RefreshProperties.Repaint)]
168 [EditorBrowsable (EditorBrowsableState.Never)]
173 public override bool AutoSize {
179 base.AutoSize = value;
183 [MonoTODO ("Value not respected, always true")]
184 [DefaultValue(false)]
185 public bool AutoWordSelection {
186 get { return auto_word_select; }
187 set { auto_word_select = value; }
191 [EditorBrowsable(EditorBrowsableState.Never)]
192 public override System.Drawing.Image BackgroundImage {
193 get { return base.BackgroundImage; }
194 set { base.BackgroundImage = value; }
199 [EditorBrowsable (EditorBrowsableState.Never)]
200 public override ImageLayout BackgroundImageLayout {
201 get { return base.BackgroundImageLayout; }
202 set { base.BackgroundImageLayout = value; }
208 public int BulletIndent {
210 return bullet_indent;
214 bullet_indent = value;
219 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
220 public bool CanRedo {
222 return document.undo.CanRedo;
227 public bool DetectUrls {
228 get { return base.EnableLinks; }
229 set { base.EnableLinks = value; }
233 [MonoTODO ("Stub, does nothing")]
234 [DefaultValue (false)]
235 public bool EnableAutoDragDrop {
236 get { return enable_auto_drag_drop; }
237 set { enable_auto_drag_drop = value; }
241 public override Font Font {
252 if (PreferredHeight != Height) {
253 Height = PreferredHeight;
259 // Font changes always set the whole doc to that font
260 start = document.GetLine(1);
261 end = document.GetLine(document.Lines);
262 document.FormatText(start, 1, end, end.text.Length + 1, base.Font, Color.Empty, Color.Empty, FormatSpecified.Font);
267 public override Color ForeColor {
269 return base.ForeColor;
273 base.ForeColor = value;
278 [MonoTODO ("Stub, does nothing")]
280 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
281 public RichTextBoxLanguageOptions LanguageOption {
282 get { return language_option; }
283 set { language_option = value; }
287 [DefaultValue(Int32.MaxValue)]
288 public override int MaxLength {
289 get { return base.MaxLength; }
290 set { base.MaxLength = value; }
294 public override bool Multiline {
296 return base.Multiline;
300 base.Multiline = value;
305 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
306 public string RedoActionName {
308 return document.undo.RedoActionName;
313 [MonoTODO ("Stub, does nothing")]
315 [DefaultValue (true)]
316 [EditorBrowsable (EditorBrowsableState.Never)]
317 public bool RichTextShortcutsEnabled {
318 get { return rich_text_shortcuts_enabled; }
319 set { rich_text_shortcuts_enabled = value; }
325 [MonoTODO ("Stub, does nothing")]
326 [MonoInternalNote ("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 int cursor_x = document.selection_start.pos;
412 int cursor_y = document.selection_start.line.line_no;
414 // The RFT parser by default, when finds our x cursor in 0, it thinks if needs to
415 // add a new line; but in *this* scenario the line is already created, so force it to reuse it.
416 // Hackish, but works without touching the heart of the buggy parser.
420 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
423 int nl_length = document.LineEndingLength (XplatUI.RunningOnUnix ? LineEnding.Rich : LineEnding.Hard);
424 document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * nl_length,
425 out line, out tag, out sel_start);
426 if (sel_start >= line.text.Length)
427 sel_start = line.text.Length -1;
429 document.SetSelection(line, sel_start);
430 document.PositionCaret(line, sel_start);
431 document.DisplayCaret();
433 OnTextChanged(EventArgs.Empty);
439 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
440 public override string SelectedText {
442 return base.SelectedText;
446 // TextBox/TextBoxBase don't set Modified in this same property
448 base.SelectedText = value;
453 [DefaultValue(HorizontalAlignment.Left)]
454 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
455 public HorizontalAlignment SelectionAlignment {
457 HorizontalAlignment align;
462 start = document.ParagraphStart(document.selection_start.line);
463 align = start.alignment;
465 end = document.ParagraphEnd(document.selection_end.line);
470 if (line.alignment != align) {
471 return HorizontalAlignment.Left;
477 line = document.GetLine(line.line_no + 1);
488 start = document.ParagraphStart(document.selection_start.line);
490 end = document.ParagraphEnd(document.selection_end.line);
495 line.alignment = value;
500 line = document.GetLine(line.line_no + 1);
502 this.CalculateDocument();
507 [MonoTODO ("Stub, does nothing")]
509 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
510 public Color SelectionBackColor {
511 get { return selection_back_color; }
512 set { selection_back_color = value; }
517 [DefaultValue(false)]
518 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
519 [MonoTODO ("Stub, does nothing")]
520 public bool SelectionBullet {
531 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
532 [MonoTODO ("Stub, does nothing")]
533 public int SelectionCharOffset {
543 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
544 public Color SelectionColor {
551 if (selection_length > 0) {
552 start = document.selection_start.line.FindTag (document.selection_start.pos + 1);
553 end = document.selection_start.line.FindTag (document.selection_end.pos);
555 start = document.selection_start.line.FindTag (document.selection_start.pos);
562 while (tag != null) {
564 if (!color.Equals (tag.Color))
570 tag = document.NextTag (tag);
577 if (value == Color.Empty)
578 value = DefaultForeColor;
583 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
584 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
586 document.FormatText (document.selection_start.line, document.selection_start.pos + 1,
587 document.selection_end.line, document.selection_end.pos + 1, null,
588 value, Color.Empty, FormatSpecified.Color);
590 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
591 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
593 document.UpdateView(document.selection_start.line, 0);
595 //Re-Align the caret in case its changed size or position
596 //probably not necessary here
597 document.AlignCaret(false);
602 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
603 public Font SelectionFont {
610 if (selection_length > 0) {
611 start = document.selection_start.line.FindTag (document.selection_start.pos + 1);
612 end = document.selection_start.line.FindTag (document.selection_end.pos);
614 start = document.selection_start.line.FindTag (document.selection_start.pos);
620 if (selection_length > 1) {
622 while (tag != null) {
624 if (!font.Equals(tag.Font))
630 tag = document.NextTag (tag);
641 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
642 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
644 document.FormatText (document.selection_start.line, document.selection_start.pos + 1,
645 document.selection_end.line, document.selection_end.pos + 1, value,
646 Color.Empty, Color.Empty, FormatSpecified.Font);
648 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
649 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
651 document.UpdateView(document.selection_start.line, 0);
652 //Re-Align the caret in case its changed size or position
653 Document.AlignCaret (false);
660 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
661 [MonoTODO ("Stub, does nothing")]
662 public int SelectionHangingIndent {
673 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
674 [MonoTODO ("Stub, does nothing")]
675 public int SelectionIndent {
685 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
686 public override int SelectionLength {
688 return base.SelectionLength;
692 base.SelectionLength = value;
697 [DefaultValue(false)]
698 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
699 [MonoTODO ("Stub, does nothing")]
700 public bool SelectionProtected {
711 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
712 [MonoTODO ("Stub, does nothing")]
713 public int SelectionRightIndent {
723 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
724 [MonoTODO ("Stub, does nothing")]
725 public int[] SelectionTabs {
735 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
736 public RichTextBoxSelectionTypes SelectionType {
738 if (document.selection_start == document.selection_end) {
739 return RichTextBoxSelectionTypes.Empty;
743 if (SelectedText.Length > 1) {
744 return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
747 return RichTextBoxSelectionTypes.Text;
751 [DefaultValue(false)]
752 [MonoTODO ("Stub, does nothing")]
753 public bool ShowSelectionMargin {
764 [RefreshProperties (RefreshProperties.All)]
766 public override string Text {
777 public override int TextLength {
779 return base.TextLength;
784 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
785 public string UndoActionName {
787 return document.undo.UndoActionName;
793 public float ZoomFactor {
802 #endregion // Public Instance Properties
804 #region Protected Instance Properties
805 protected override CreateParams CreateParams {
807 return base.CreateParams;
811 protected override Size DefaultSize {
813 return new Size(100, 96);
816 #endregion // Protected Instance Properties
818 #region Public Instance Methods
819 public bool CanPaste(DataFormats.Format clipFormat) {
820 if ((clipFormat.Name == DataFormats.Rtf) ||
821 (clipFormat.Name == DataFormats.Text) ||
822 (clipFormat.Name == DataFormats.UnicodeText)) {
828 public int Find(char[] characterSet) {
829 return Find(characterSet, -1, -1);
832 public int Find(char[] characterSet, int start) {
833 return Find(characterSet, start, -1);
836 public int Find(char[] characterSet, int start, int end) {
837 Document.Marker start_mark;
838 Document.Marker end_mark;
839 Document.Marker result;
842 document.GetMarker(out start_mark, true);
848 start_mark = new Document.Marker();
850 document.CharIndexToLineTag(start, out line, out tag, out pos);
851 start_mark.line = line;
852 start_mark.tag = tag;
853 start_mark.pos = pos;
857 document.GetMarker(out end_mark, false);
863 end_mark = new Document.Marker();
865 document.CharIndexToLineTag(end, out line, out tag, out pos);
866 end_mark.line = line;
871 if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
872 return document.LineTagToCharIndex(result.line, result.pos);
878 public int Find(string str) {
879 return Find(str, -1, -1, RichTextBoxFinds.None);
882 public int Find(string str, int start, int end, RichTextBoxFinds options) {
883 Document.Marker start_mark;
884 Document.Marker end_mark;
885 Document.Marker result;
888 document.GetMarker(out start_mark, true);
894 start_mark = new Document.Marker();
896 document.CharIndexToLineTag(start, out line, out tag, out pos);
898 start_mark.line = line;
899 start_mark.tag = tag;
900 start_mark.pos = pos;
904 document.GetMarker(out end_mark, false);
910 end_mark = new Document.Marker();
912 document.CharIndexToLineTag(end, out line, out tag, out pos);
914 end_mark.line = line;
919 if (document.Find(str, start_mark, end_mark, out result, options)) {
920 return document.LineTagToCharIndex(result.line, result.pos);
926 public int Find(string str, int start, RichTextBoxFinds options) {
927 return Find(str, start, -1, options);
930 public int Find(string str, RichTextBoxFinds options) {
931 return Find(str, -1, -1, options);
936 public char GetCharFromPosition(Point pt) {
940 PointToTagPos(pt, out tag, out pos);
942 if (pos >= tag.Line.text.Length) {
946 return tag.Line.text[pos];
949 internal override char GetCharFromPositionInternal (Point p)
954 PointToTagPos (p, out tag, out pos);
956 if (pos >= tag.Line.text.Length)
959 return tag.Line.text[pos];
967 int GetCharIndexFromPosition(Point pt) {
971 PointToTagPos(pt, out tag, out pos);
973 return document.LineTagToCharIndex(tag.Line, pos);
980 int GetLineFromCharIndex(int index) {
985 document.CharIndexToLineTag(index, out line, out tag, out pos);
987 return line.LineNo - 1;
994 Point GetPositionFromCharIndex(int index) {
999 document.CharIndexToLineTag(index, out line, out tag, out pos);
1000 return new Point(line.X + (int)line.widths[pos] + document.OffsetX - document.ViewPortX,
1001 line.Y + document.OffsetY - document.ViewPortY);
1004 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
1008 // FIXME - ignoring unicode
1009 if (fileType == RichTextBoxStreamType.PlainText) {
1014 sb = new StringBuilder ((int) data.Length);
1015 buffer = new char [1024];
1017 throw new IOException("Not enough memory to load document");
1020 StreamReader sr = new StreamReader (data, Encoding.Default, true);
1021 int charsRead = sr.Read (buffer, 0, buffer.Length);
1022 while (charsRead > 0) {
1023 sb.Append (buffer, 0, charsRead);
1024 charsRead = sr.Read (buffer, 0, buffer.Length);
1027 // Remove the EOF converted to an extra EOL by the StreamReader
1028 if (sb.Length > 0 && sb [sb.Length - 1] == '\n')
1029 sb.Remove (sb.Length - 1, 1);
1031 base.Text = sb.ToString();
1035 InsertRTFFromStream(data, 0, 1);
1037 document.PositionCaret (document.GetLine (1), 0);
1038 document.SetSelectionToCaret (true);
1042 public void LoadFile(string path) {
1043 LoadFile (path, RichTextBoxStreamType.RichText);
1046 public void LoadFile(string path, RichTextBoxStreamType fileType) {
1053 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
1055 LoadFile(data, fileType);
1058 catch (Exception ex) {
1059 throw new IOException("Could not open file " + path, ex);
1069 public void Paste(DataFormats.Format clipFormat) {
1070 base.Paste(Clipboard.GetDataObject(), clipFormat, false);
1075 if (document.undo.Redo ())
1076 OnTextChanged (EventArgs.Empty);
1079 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
1085 if (fileType == RichTextBoxStreamType.UnicodePlainText) {
1086 encoding = Encoding.Unicode;
1088 encoding = Encoding.ASCII;
1092 case RichTextBoxStreamType.PlainText:
1093 case RichTextBoxStreamType.TextTextOleObjs:
1094 case RichTextBoxStreamType.UnicodePlainText: {
1096 bytes = encoding.GetBytes(document.Root.text.ToString());
1097 data.Write(bytes, 0, bytes.Length);
1101 for (i = 1; i < document.Lines; i++) {
1102 // Normalize the new lines to the system ones
1103 string line_text = document.GetLine (i).TextWithoutEnding () + Environment.NewLine;
1104 bytes = encoding.GetBytes(line_text);
1105 data.Write(bytes, 0, bytes.Length);
1107 bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
1108 data.Write(bytes, 0, bytes.Length);
1113 // If we're here we're saving RTF
1120 start_line = document.GetLine(1);
1121 end_line = document.GetLine(document.Lines);
1122 rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
1124 bytes = new Byte[4096];
1126 // Let's chunk it so we don't use up all memory...
1127 for (i = 0; i < total; i += 1024) {
1128 if ((i + 1024) < total) {
1129 current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
1131 current = total - i;
1132 current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
1134 data.Write(bytes, 0, current);
1138 public void SaveFile(string path) {
1139 if (path.EndsWith(".rtf")) {
1140 SaveFile(path, RichTextBoxStreamType.RichText);
1142 SaveFile(path, RichTextBoxStreamType.PlainText);
1146 public void SaveFile(string path, RichTextBoxStreamType fileType) {
1152 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
1153 SaveFile(data, fileType);
1157 // throw new IOException("Could not write document to file " + path);
1168 [EditorBrowsable (EditorBrowsableState.Never)]
1169 public new void DrawToBitmap (Bitmap bitmap, Rectangle targetBounds)
1171 Graphics dc = Graphics.FromImage (bitmap);
1173 Draw (dc, targetBounds);
1177 #endregion // Public Instance Methods
1179 #region Protected Instance Methods
1180 protected virtual object CreateRichEditOleCallback() {
1181 throw new NotImplementedException();
1184 protected override void OnBackColorChanged(EventArgs e) {
1185 base.OnBackColorChanged (e);
1188 protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
1189 ContentsResizedEventHandler eh = (ContentsResizedEventHandler)(Events [ContentsResizedEvent]);
1194 protected override void OnContextMenuChanged(EventArgs e) {
1195 base.OnContextMenuChanged (e);
1198 protected override void OnHandleCreated(EventArgs e) {
1199 base.OnHandleCreated (e);
1202 protected override void OnHandleDestroyed(EventArgs e) {
1203 base.OnHandleDestroyed (e);
1206 protected virtual void OnHScroll(EventArgs e) {
1207 EventHandler eh = (EventHandler)(Events [HScrollEvent]);
1212 [MonoTODO ("Stub, never called")]
1213 protected virtual void OnImeChange(EventArgs e) {
1214 EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
1219 protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
1220 LinkClickedEventHandler eh = (LinkClickedEventHandler)(Events [LinkClickedEvent]);
1225 protected virtual void OnProtected(EventArgs e) {
1226 EventHandler eh = (EventHandler)(Events [ProtectedEvent]);
1231 protected override void OnRightToLeftChanged(EventArgs e) {
1232 base.OnRightToLeftChanged (e);
1235 protected virtual void OnSelectionChanged(EventArgs e) {
1236 EventHandler eh = (EventHandler)(Events [SelectionChangedEvent]);
1242 protected override void OnSystemColorsChanged(EventArgs e) {
1243 base.OnSystemColorsChanged (e);
1246 protected override void OnTextChanged(EventArgs e) {
1247 base.OnTextChanged (e);
1251 protected virtual void OnVScroll(EventArgs e) {
1252 EventHandler eh = (EventHandler)(Events [VScrollEvent]);
1257 protected override void WndProc(ref Message m) {
1258 base.WndProc (ref m);
1262 protected override bool ProcessCmdKey (ref Message m, Keys keyData)
1264 return base.ProcessCmdKey (ref m, keyData);
1267 #endregion // Protected Instance Methods
1270 static object ContentsResizedEvent = new object ();
1271 static object HScrollEvent = new object ();
1272 static object ImeChangeEvent = new object ();
1273 static object LinkClickedEvent = new object ();
1274 static object ProtectedEvent = new object ();
1275 static object SelectionChangedEvent = new object ();
1276 static object VScrollEvent = new object ();
1279 [EditorBrowsable(EditorBrowsableState.Never)]
1280 public new event EventHandler BackgroundImageChanged {
1281 add { base.BackgroundImageChanged += value; }
1282 remove { base.BackgroundImageChanged -= value; }
1287 [EditorBrowsable (EditorBrowsableState.Never)]
1288 public new event EventHandler BackgroundImageLayoutChanged {
1289 add { base.BackgroundImageLayoutChanged += value; }
1290 remove { base.BackgroundImageLayoutChanged -= value; }
1294 public event ContentsResizedEventHandler ContentsResized {
1295 add { Events.AddHandler (ContentsResizedEvent, value); }
1296 remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1301 [EditorBrowsable(EditorBrowsableState.Never)]
1302 public new event EventHandler DoubleClick {
1303 add { base.DoubleClick += value; }
1304 remove { base.DoubleClick -= value; }
1310 [EditorBrowsable(EditorBrowsableState.Never)]
1312 public new event DragEventHandler DragDrop {
1313 add { base.DragDrop += value; }
1314 remove { base.DragDrop -= value; }
1319 [EditorBrowsable(EditorBrowsableState.Never)]
1321 public new event DragEventHandler DragEnter {
1322 add { base.DragEnter += value; }
1323 remove { base.DragEnter -= value; }
1327 [EditorBrowsable(EditorBrowsableState.Never)]
1328 public new event EventHandler DragLeave {
1329 add { base.DragLeave += value; }
1330 remove { base.DragLeave -= value; }
1335 [EditorBrowsable(EditorBrowsableState.Never)]
1336 public new event DragEventHandler DragOver {
1337 add { base.DragOver += value; }
1338 remove { base.DragOver -= value; }
1343 [EditorBrowsable(EditorBrowsableState.Never)]
1344 public new event GiveFeedbackEventHandler GiveFeedback {
1345 add { base.GiveFeedback += value; }
1346 remove { base.GiveFeedback -= value; }
1349 public event EventHandler HScroll {
1350 add { Events.AddHandler (HScrollEvent, value); }
1351 remove { Events.RemoveHandler (HScrollEvent, value); }
1354 public event EventHandler ImeChange {
1355 add { Events.AddHandler (ImeChangeEvent, value); }
1356 remove { Events.RemoveHandler (ImeChangeEvent, value); }
1359 public event LinkClickedEventHandler LinkClicked {
1360 add { Events.AddHandler (LinkClickedEvent, value); }
1361 remove { Events.RemoveHandler (LinkClickedEvent, value); }
1364 public event EventHandler Protected {
1365 add { Events.AddHandler (ProtectedEvent, value); }
1366 remove { Events.RemoveHandler (ProtectedEvent, value); }
1370 [EditorBrowsable(EditorBrowsableState.Never)]
1371 public new event QueryContinueDragEventHandler QueryContinueDrag {
1372 add { base.QueryContinueDrag += value; }
1373 remove { base.QueryContinueDrag -= value; }
1376 [MonoTODO ("Event never raised")]
1377 public event EventHandler SelectionChanged {
1378 add { Events.AddHandler (SelectionChangedEvent, value); }
1379 remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1382 public event EventHandler VScroll {
1383 add { Events.AddHandler (VScrollEvent, value); }
1384 remove { Events.RemoveHandler (VScrollEvent, value); }
1386 #endregion // Events
1388 #region Private Methods
1390 internal override void SelectWord ()
1392 document.ExpandSelection(CaretSelection.Word, false);
1395 private class RtfSectionStyle : ICloneable {
1396 internal Color rtf_color;
1397 internal RTF.Font rtf_rtffont;
1398 internal int rtf_rtffont_size;
1399 internal FontStyle rtf_rtfstyle;
1400 internal HorizontalAlignment rtf_rtfalign;
1401 internal int rtf_par_line_left_indent;
1402 internal bool rtf_visible;
1403 internal int rtf_skip_width;
1405 public object Clone ()
1407 RtfSectionStyle new_style = new RtfSectionStyle ();
1409 new_style.rtf_color = rtf_color;
1410 new_style.rtf_par_line_left_indent = rtf_par_line_left_indent;
1411 new_style.rtf_rtfalign = rtf_rtfalign;
1412 new_style.rtf_rtffont = rtf_rtffont;
1413 new_style.rtf_rtffont_size = rtf_rtffont_size;
1414 new_style.rtf_rtfstyle = rtf_rtfstyle;
1415 new_style.rtf_visible = rtf_visible;
1416 new_style.rtf_skip_width = rtf_skip_width;
1422 // To allow us to keep track of the sections and revert formatting
1423 // as we go in and out of sections of the document.
1424 private void HandleGroup (RTF.RTF rtf)
1426 //start group - save the current formatting on to a stack
1427 //end group - go back to the formatting at the current group
1428 if (rtf_section_stack == null) {
1429 rtf_section_stack = new Stack ();
1432 if (rtf.Major == RTF.Major.BeginGroup) {
1433 rtf_section_stack.Push (rtf_style.Clone ());
1434 //spec specifies resetting unicode ignore at begin group as an attempt at error
1437 } else if (rtf.Major == RTF.Major.EndGroup) {
1438 if (rtf_section_stack.Count > 0) {
1439 FlushText (rtf, false);
1441 rtf_style = (RtfSectionStyle) rtf_section_stack.Pop ();
1446 [MonoInternalNote ("Add QuadJust support for justified alignment")]
1447 private void HandleControl(RTF.RTF rtf) {
1449 case RTF.Major.Unicode: {
1451 case RTF.Minor.UnicodeCharBytes: {
1452 rtf_style.rtf_skip_width = rtf.Param;
1456 case RTF.Minor.UnicodeChar: {
1457 FlushText (rtf, false);
1458 rtf_skip_count += rtf_style.rtf_skip_width;
1459 rtf_line.Append((char)rtf.Param);
1466 case RTF.Major.Destination: {
1467 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1472 case RTF.Major.PictAttr:
1473 if (rtf.Picture != null && rtf.Picture.IsValid ()) {
1474 Line line = document.GetLine (rtf_cursor_y);
1475 document.InsertPicture (line, 0, rtf.Picture);
1478 FlushText (rtf, true);
1483 case RTF.Major.CharAttr: {
1485 case RTF.Minor.ForeColor: {
1486 System.Windows.Forms.RTF.Color color;
1488 color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
1490 if (color != null) {
1491 FlushText(rtf, false);
1492 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
1493 this.rtf_style.rtf_color = ForeColor;
1495 this.rtf_style.rtf_color = Color.FromArgb(color.Red, color.Green, color.Blue);
1497 FlushText (rtf, false);
1502 case RTF.Minor.FontSize: {
1503 FlushText(rtf, false);
1504 this.rtf_style.rtf_rtffont_size = rtf.Param / 2;
1508 case RTF.Minor.FontNum: {
1509 System.Windows.Forms.RTF.Font font;
1511 font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
1513 FlushText(rtf, false);
1514 this.rtf_style.rtf_rtffont = font;
1519 case RTF.Minor.Plain: {
1520 FlushText(rtf, false);
1521 rtf_style.rtf_rtfstyle = FontStyle.Regular;
1525 case RTF.Minor.Bold: {
1526 FlushText(rtf, false);
1527 if (rtf.Param == RTF.RTF.NoParam) {
1528 rtf_style.rtf_rtfstyle |= FontStyle.Bold;
1530 rtf_style.rtf_rtfstyle &= ~FontStyle.Bold;
1535 case RTF.Minor.Italic: {
1536 FlushText(rtf, false);
1537 if (rtf.Param == RTF.RTF.NoParam) {
1538 rtf_style.rtf_rtfstyle |= FontStyle.Italic;
1540 rtf_style.rtf_rtfstyle &= ~FontStyle.Italic;
1545 case RTF.Minor.StrikeThru: {
1546 FlushText(rtf, false);
1547 if (rtf.Param == RTF.RTF.NoParam) {
1548 rtf_style.rtf_rtfstyle |= FontStyle.Strikeout;
1550 rtf_style.rtf_rtfstyle &= ~FontStyle.Strikeout;
1555 case RTF.Minor.Underline: {
1556 FlushText(rtf, false);
1557 if (rtf.Param == RTF.RTF.NoParam) {
1558 rtf_style.rtf_rtfstyle |= FontStyle.Underline;
1560 rtf_style.rtf_rtfstyle = rtf_style.rtf_rtfstyle & ~FontStyle.Underline;
1565 case RTF.Minor.Invisible: {
1566 FlushText (rtf, false);
1567 rtf_style.rtf_visible = false;
1571 case RTF.Minor.NoUnderline: {
1572 FlushText(rtf, false);
1573 rtf_style.rtf_rtfstyle &= ~FontStyle.Underline;
1580 case RTF.Major.ParAttr: {
1581 switch (rtf.Minor) {
1583 case RTF.Minor.ParDef:
1584 FlushText (rtf, false);
1585 rtf_style.rtf_par_line_left_indent = 0;
1586 rtf_style.rtf_rtfalign = HorizontalAlignment.Left;
1589 case RTF.Minor.LeftIndent:
1590 rtf_style.rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * CreateGraphics ().DpiX + 0.5F);
1593 case RTF.Minor.QuadCenter:
1594 FlushText (rtf, false);
1595 rtf_style.rtf_rtfalign = HorizontalAlignment.Center;
1598 case RTF.Minor.QuadJust:
1599 FlushText (rtf, false);
1600 rtf_style.rtf_rtfalign = HorizontalAlignment.Center;
1603 case RTF.Minor.QuadLeft:
1604 FlushText (rtf, false);
1605 rtf_style.rtf_rtfalign = HorizontalAlignment.Left;
1608 case RTF.Minor.QuadRight:
1609 FlushText (rtf, false);
1610 rtf_style.rtf_rtfalign = HorizontalAlignment.Right;
1616 case RTF.Major.SpecialChar: {
1617 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1624 private void SpecialChar(RTF.RTF rtf) {
1626 case RTF.Minor.Page:
1627 case RTF.Minor.Sect:
1629 case RTF.Minor.Line:
1630 case RTF.Minor.Par: {
1631 FlushText(rtf, true);
1635 case RTF.Minor.Cell: {
1640 case RTF.Minor.NoBrkSpace: {
1645 case RTF.Minor.Tab: {
1646 rtf_line.Append ("\t");
1647 // FlushText (rtf, false);
1651 case RTF.Minor.NoReqHyphen:
1652 case RTF.Minor.NoBrkHyphen: {
1653 rtf_line.Append ("-");
1654 // FlushText (rtf, false);
1658 case RTF.Minor.Bullet: {
1659 Console.WriteLine("*");
1663 case RTF.Minor.WidowCtrl:
1666 case RTF.Minor.EmDash: {
1667 rtf_line.Append ("\u2014");
1671 case RTF.Minor.EnDash: {
1672 rtf_line.Append ("\u2013");
1676 case RTF.Minor.LQuote: {
1677 Console.Write("\u2018");
1681 case RTF.Minor.RQuote: {
1682 Console.Write("\u2019");
1686 case RTF.Minor.LDblQuote: {
1687 Console.Write("\u201C");
1691 case RTF.Minor.RDblQuote: {
1692 Console.Write("\u201D");
1697 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1704 private void HandleText(RTF.RTF rtf) {
1705 string str = rtf.EncodedText;
1707 //todo - simplistically skips characters, should skip bytes?
1708 if (rtf_skip_count > 0 && str.Length > 0) {
1709 int iToRemove = Math.Min (rtf_skip_count, str.Length);
1711 str = str.Substring (iToRemove);
1712 rtf_skip_count-=iToRemove;
1716 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1717 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1719 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1720 rtf_line.Append((char)rtf.Major);
1722 //rtf_line.Append((char)rtf.Major);
1723 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1728 if (rtf_style.rtf_visible)
1729 rtf_line.Append (str);
1732 private void FlushText(RTF.RTF rtf, bool newline) {
1736 length = rtf_line.Length;
1737 if (!newline && (length == 0)) {
1741 if (rtf_style.rtf_rtffont == null) {
1742 // First font in table is default
1743 rtf_style.rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont (rtf, 0);
1746 font = new Font (rtf_style.rtf_rtffont.Name, rtf_style.rtf_rtffont_size, rtf_style.rtf_rtfstyle);
1748 if (rtf_style.rtf_color == Color.Empty) {
1749 System.Windows.Forms.RTF.Color color;
1751 // First color in table is default
1752 color = System.Windows.Forms.RTF.Color.GetColor (rtf, 0);
1754 if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
1755 rtf_style.rtf_color = ForeColor;
1757 rtf_style.rtf_color = Color.FromArgb (color.Red, color.Green, color.Blue);
1762 rtf_chars += rtf_line.Length;
1764 // Try to re-use if we are told so - this usually happens when we are inserting a flow of rtf text
1765 // with an already alive line.
1766 if (rtf_cursor_x == 0 && !reuse_line) {
1767 if (newline && rtf_line.ToString ().EndsWith (Environment.NewLine) == false)
1768 rtf_line.Append (Environment.NewLine);
1770 document.Add (rtf_cursor_y, rtf_line.ToString (), rtf_style.rtf_rtfalign, font, rtf_style.rtf_color,
1771 newline ? LineEnding.Rich : LineEnding.Wrap);
1772 if (rtf_style.rtf_par_line_left_indent != 0) {
1773 Line line = document.GetLine (rtf_cursor_y);
1774 line.indent = rtf_style.rtf_par_line_left_indent;
1779 line = document.GetLine (rtf_cursor_y);
1780 line.indent = rtf_style.rtf_par_line_left_indent;
1781 if (rtf_line.Length > 0) {
1782 document.InsertString (line, rtf_cursor_x, rtf_line.ToString ());
1783 document.FormatText (line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length,
1784 font, rtf_style.rtf_color, Color.Empty,
1785 FormatSpecified.Font | FormatSpecified.Color);
1788 line = document.GetLine (rtf_cursor_y);
1789 line.ending = LineEnding.Rich;
1791 if (line.Text.EndsWith (Environment.NewLine) == false)
1792 line.Text += Environment.NewLine;
1795 reuse_line = false; // sanity assignment - in this case we have already re-used one line.
1802 rtf_cursor_x += length;
1804 rtf_line.Length = 0; // Empty line
1807 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1812 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
1815 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) {
1818 rtf = new RTF.RTF(data);
1821 rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1822 rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1823 rtf.ClassCallback[RTF.TokenClass.Group] = new RTF.ClassDelegate(HandleGroup);
1826 rtf_line = new StringBuilder();
1827 rtf_style.rtf_color = Color.Empty;
1828 rtf_style.rtf_rtffont_size = (int)this.Font.Size;
1829 rtf_style.rtf_rtfalign = HorizontalAlignment.Left;
1830 rtf_style.rtf_rtfstyle = FontStyle.Regular;
1831 rtf_style.rtf_rtffont = null;
1832 rtf_style.rtf_visible = true;
1833 rtf_style.rtf_skip_width = 1;
1834 rtf_cursor_x = cursor_x;
1835 rtf_cursor_y = cursor_y;
1837 rtf.DefaultFont(this.Font.Name);
1839 rtf_text_map = new RTF.TextMap();
1840 RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1842 document.SuspendRecalc ();
1845 rtf.Read(); // That's it
1846 FlushText(rtf, false);
1851 catch (RTF.RTFException e) {
1855 // Seems to be plain text or broken RTF
1856 Console.WriteLine("RTF Parsing failure: {0}", e.Message);
1859 to_x = rtf_cursor_x;
1860 to_y = rtf_cursor_y;
1863 // clear the section stack if it was used
1864 if (rtf_section_stack != null)
1865 rtf_section_stack.Clear();
1867 document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
1868 document.ResumeRecalc (true);
1870 document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1873 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1877 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1881 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1886 if (p.X >= document.ViewPortWidth) {
1887 p.X = document.ViewPortWidth - 1;
1888 } else if (p.X < 0) {
1892 if (p.Y >= document.ViewPortHeight) {
1893 p.Y = document.ViewPortHeight - 1;
1894 } else if (p.Y < 0) {
1898 tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1901 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1902 if (prev_index != font_index) {
1903 rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry
1906 if ((prev_font == null) || (prev_font.Size != font.Size)) {
1907 rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size
1910 if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1914 if (prev_font != null) {
1920 if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1924 if (prev_font != null) {
1930 if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1931 if (font.Strikeout) {
1932 rtf.Append("\\strike");
1934 if (prev_font != null) {
1935 rtf.Append("\\strike0");
1940 if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1941 if (font.Underline) {
1944 if (prev_font != null) {
1945 rtf.Append("\\ul0");
1951 static readonly char [] ReservedRTFChars = new char [] { '\\', '{', '}' };
1953 [MonoInternalNote ("Emit unicode and other special characters properly")]
1954 private void EmitRTFText(StringBuilder rtf, string text) {
1955 int start = rtf.Length;
1956 int count = text.Length;
1960 // This method emits user text *only*, so it's safe to escape any reserved rtf chars
1961 // Escape '\' first, since it is used later to escape the other chars
1962 if (text.IndexOfAny (ReservedRTFChars) > -1) {
1963 rtf.Replace ("\\", "\\\\", start, count);
1964 rtf.Replace ("{", "\\{", start, count);
1965 rtf.Replace ("}", "\\}", start, count);
1969 // start_pos and end_pos are 0-based
1970 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1984 sb = new StringBuilder();
1985 fonts = new ArrayList(10);
1986 colors = new ArrayList(10);
1988 // Two runs, first we parse to determine tables;
1989 // and unlike most of our processing here we work on tags
1992 line_no = start_line.line_no;
1995 // Add default font and color; to optimize document content we don't
1996 // use this.Font and this.ForeColor but the font/color from the first tag
1997 tag = LineTag.FindTag(start_line, pos);
2000 fonts.Add(font.Name);
2003 while (line_no <= end_line.line_no) {
2004 line = document.GetLine(line_no);
2005 tag = LineTag.FindTag(line, pos);
2007 if (line_no != end_line.line_no) {
2008 line_len = line.text.Length;
2013 while (pos < line_len) {
2014 if (tag.Font.Name != font.Name) {
2016 if (!fonts.Contains(font.Name)) {
2017 fonts.Add(font.Name);
2021 if (tag.Color != color) {
2023 if (!colors.Contains(color)) {
2028 pos = tag.Start + tag.Length - 1;
2035 // We have the tables, emit the header
2036 sb.Append("{\\rtf1\\ansi");
2037 sb.Append("\\ansicpg1252"); // FIXME - is this correct?
2040 sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
2043 sb.Append("\\deflang1033" + Environment.NewLine); // FIXME - always 1033?
2045 // Emit the font table
2046 sb.Append("{\\fonttbl");
2047 for (i = 0; i < fonts.Count; i++) {
2048 sb.Append(String.Format("{{\\f{0}", i)); // {Font
2049 sb.Append("\\fnil"); // Family
2050 sb.Append("\\fcharset0 "); // Charset ANSI<space>
2051 sb.Append((string)fonts[i]); // Font name
2052 sb.Append(";}"); // }
2055 sb.Append(Environment.NewLine);
2057 // Emit the color table (if needed)
2058 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))) {
2059 sb.Append("{\\colortbl "); // Header and NO! default color
2060 for (i = 0; i < colors.Count; i++) {
2061 sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
2062 sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
2063 sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
2067 sb.Append(Environment.NewLine);
2070 sb.Append("{\\*\\generator Mono RichTextBox;}");
2071 // Emit initial paragraph settings
2072 tag = LineTag.FindTag(start_line, start_pos);
2073 sb.Append("\\pard"); // Reset to default paragraph properties
2074 EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.Font.Name), null, tag.Font); // Font properties
2075 sb.Append(" "); // Space separator
2078 color = (Color)colors[0];
2080 line_no = start_line.line_no;
2083 while (line_no <= end_line.line_no) {
2084 line = document.GetLine(line_no);
2085 tag = LineTag.FindTag(line, pos);
2087 if (line_no != end_line.line_no) {
2088 line_len = line.text.Length;
2093 while (pos < line_len) {
2096 if (tag.Font != font) {
2097 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.Font.Name), font, tag.Font);
2101 if (tag.Color != color) {
2103 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
2105 if (length != sb.Length) {
2106 sb.Append(" "); // Emit space to separate keywords from text
2109 // Emit the string itself
2110 if (line_no != end_line.line_no) {
2111 EmitRTFText(sb, tag.Line.text.ToString(pos, tag.Start + tag.Length - pos - 1));
2113 if (end_pos < (tag.Start + tag.Length - 1)) {
2114 // Emit partial tag only, end_pos is inside this tag
2115 EmitRTFText(sb, tag.Line.text.ToString(pos, end_pos - pos));
2117 EmitRTFText(sb, tag.Line.text.ToString(pos, tag.Start + tag.Length - pos - 1));
2121 pos = tag.Start + tag.Length - 1;
2124 if (pos >= line.text.Length) {
2125 if (line.ending != LineEnding.Wrap) {
2127 sb.Append(Environment.NewLine);
2135 sb.Append(Environment.NewLine);
2139 #endregion // Private Methods