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;
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 SolidBrush rtf_color;
54 private RTF.Font rtf_rtffont;
55 private int rtf_rtffont_size;
56 private FontStyle rtf_rtfstyle;
57 private HorizontalAlignment rtf_rtfalign;
58 private int rtf_cursor_x;
59 private int rtf_cursor_y;
60 private int rtf_chars;
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);
88 SetStyle (ControlStyles.StandardDoubleClick, false);
91 #endregion // Public Constructors
93 #region Private & Internal Methods
94 private void RichTextBox_LostFocus(object sender, EventArgs e) {
98 private void RichTextBox_GotFocus(object sender, EventArgs e) {
101 #endregion // Private & Internal Methods
103 #region Public Instance Properties
104 public override bool AllowDrop {
106 return base.AllowDrop;
110 base.AllowDrop = value;
114 [DefaultValue(false)]
116 public override bool AutoSize {
122 base.AutoSize = value;
126 [DefaultValue(false)]
127 public bool AutoWordSelection {
129 return auto_word_select;
133 auto_word_select = true;
138 [EditorBrowsable(EditorBrowsableState.Never)]
139 public override System.Drawing.Image BackgroundImage {
140 get { return base.BackgroundImage; }
141 set { base.BackgroundImage = value; }
146 public int BulletIndent {
148 return bullet_indent;
152 bullet_indent = value;
157 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
158 public bool CanRedo {
165 public bool DetectUrls {
175 public override Font Font {
186 if (PreferredHeight != Height) {
187 Height = PreferredHeight;
193 // Font changes always set the whole doc to that font
194 start = document.GetLine(1);
195 end = document.GetLine(document.Lines);
196 document.FormatText(start, 1, end, end.text.Length + 1, base.Font, new SolidBrush(this.ForeColor));
201 public override Color ForeColor {
203 return base.ForeColor;
207 base.ForeColor = value;
211 [DefaultValue(Int32.MaxValue)]
212 public override int MaxLength {
214 return base.max_length;
218 base.max_length = value;
223 public override bool Multiline {
229 base.Multiline = value;
234 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
236 public string RedoActionName {
238 return redo_action_name;
244 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
245 public int RightMargin {
251 margin_right = value;
257 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
263 start_line = document.GetLine(1);
264 end_line = document.GetLine(document.Lines);
265 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
272 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
274 InsertRTFFromStream(data, 0, 1);
282 [DefaultValue(RichTextBoxScrollBars.Both)]
284 public RichTextBoxScrollBars ScrollBars {
296 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
297 public string SelectedRtf {
299 return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
311 if (document.selection_visible) {
312 document.ReplaceSelection("", false);
315 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
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, out chars);
321 document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
322 document.SetSelection(line, sel_start);
323 document.PositionCaret(line, sel_start);
324 document.DisplayCaret();
326 OnTextChanged(EventArgs.Empty);
332 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
333 public override string SelectedText {
335 return base.SelectedText;
339 base.SelectedText = value;
344 [DefaultValue(HorizontalAlignment.Left)]
345 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
346 public HorizontalAlignment SelectionAlignment {
348 HorizontalAlignment align;
353 start = document.ParagraphStart(document.selection_start.line);
354 align = start.alignment;
356 end = document.ParagraphEnd(document.selection_end.line);
361 if (line.alignment != align) {
362 return HorizontalAlignment.Left;
368 line = document.GetLine(line.line_no + 1);
379 start = document.ParagraphStart(document.selection_start.line);
381 end = document.ParagraphEnd(document.selection_end.line);
386 line.alignment = value;
391 line = document.GetLine(line.line_no + 1);
393 this.CalculateDocument();
398 [DefaultValue(false)]
399 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
401 public bool SelectionBullet {
412 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
414 public int SelectionCharOffset {
424 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
425 public Color SelectionColor {
432 start = document.selection_start.tag;
433 end = document.selection_end.tag;
434 color = ((SolidBrush)document.selection_start.tag.color).Color;
438 if (!color.Equals(((SolidBrush)tag.color).Color)) {
446 tag = document.NextTag(tag);
457 FontDefinition attributes;
461 attributes = new FontDefinition();
462 attributes.color = value;
464 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
465 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
467 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
469 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
470 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
472 document.UpdateView(document.selection_start.line, 0);
473 document.AlignCaret();
478 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
479 public Font SelectionFont {
486 start = document.selection_start.tag;
487 end = document.selection_end.tag;
488 font = document.selection_start.tag.font;
492 if (!font.Equals(tag.font)) {
500 tag = document.NextTag(tag);
511 FontDefinition attributes;
515 attributes = new FontDefinition();
516 attributes.font_obj = value;
518 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
519 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
521 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
523 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
524 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
526 document.UpdateView(document.selection_start.line, 0);
527 document.AlignCaret();
534 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
536 public int SelectionHangingIndent {
547 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
549 public int SelectionIndent {
559 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
560 public override int SelectionLength {
562 return base.SelectionLength;
566 base.SelectionLength = value;
571 [DefaultValue(false)]
572 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
574 public bool SelectionProtected {
585 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
587 public int SelectionRightIndent {
597 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
599 public int[] SelectionTabs {
609 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
610 public RichTextBoxSelectionTypes SelectionType {
612 if (document.selection_start == document.selection_end) {
613 return RichTextBoxSelectionTypes.Empty;
617 if (SelectedText.Length > 1) {
618 return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
621 return RichTextBoxSelectionTypes.Text;
625 [DefaultValue(false)]
627 public bool ShowSelectionMargin {
637 public override string Text {
648 public override int TextLength {
650 return base.TextLength;
655 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
656 public string UndoActionName {
658 return document.undo.UndoName;
664 public float ZoomFactor {
673 #endregion // Public Instance Properties
675 #region Protected Instance Properties
676 protected override CreateParams CreateParams {
678 return base.CreateParams;
682 protected override Size DefaultSize {
684 return new Size(100, 96);
687 #endregion // Protected Instance Properties
689 #region Public Instance Methods
690 public bool CanPaste(DataFormats.Format clipFormat) {
691 if ((clipFormat.Name == DataFormats.Rtf) ||
692 (clipFormat.Name == DataFormats.Text) ||
693 (clipFormat.Name == DataFormats.UnicodeText)) {
699 public int Find(char[] characterSet) {
700 return Find(characterSet, -1, -1);
703 public int Find(char[] characterSet, int start) {
704 return Find(characterSet, start, -1);
707 public int Find(char[] characterSet, int start, int end) {
708 Document.Marker start_mark;
709 Document.Marker end_mark;
710 Document.Marker result;
713 document.GetMarker(out start_mark, true);
719 start_mark = new Document.Marker();
721 document.CharIndexToLineTag(start, out line, out tag, out pos);
722 start_mark.line = line;
723 start_mark.tag = tag;
724 start_mark.pos = pos;
728 document.GetMarker(out end_mark, false);
734 end_mark = new Document.Marker();
736 document.CharIndexToLineTag(end, out line, out tag, out pos);
737 end_mark.line = line;
742 if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
743 return document.LineTagToCharIndex(result.line, result.pos);
749 public int Find(string str) {
750 return Find(str, -1, -1, RichTextBoxFinds.None);
753 public int Find(string str, int start, int end, RichTextBoxFinds options) {
754 Document.Marker start_mark;
755 Document.Marker end_mark;
756 Document.Marker result;
759 document.GetMarker(out start_mark, true);
765 start_mark = new Document.Marker();
767 document.CharIndexToLineTag(start, out line, out tag, out pos);
769 start_mark.line = line;
770 start_mark.tag = tag;
771 start_mark.pos = pos;
775 document.GetMarker(out end_mark, false);
781 end_mark = new Document.Marker();
783 document.CharIndexToLineTag(end, out line, out tag, out pos);
785 end_mark.line = line;
790 if (document.Find(str, start_mark, end_mark, out result, options)) {
791 return document.LineTagToCharIndex(result.line, result.pos);
797 public int Find(string str, int start, RichTextBoxFinds options) {
798 return Find(str, start, -1, options);
801 public int Find(string str, RichTextBoxFinds options) {
802 return Find(str, -1, -1, options);
805 public char GetCharFromPosition(Point pt) {
809 PointToTagPos(pt, out tag, out pos);
811 if (pos >= tag.line.text.Length) {
815 return tag.line.text[pos];
819 public int GetCharIndexFromPosition(Point pt) {
823 PointToTagPos(pt, out tag, out pos);
825 return document.LineTagToCharIndex(tag.line, pos);
828 public int GetLineFromCharIndex(int index) {
833 document.CharIndexToLineTag(index, out line, out tag, out pos);
835 return line.LineNo - 1;
838 public Point GetPositionFromCharIndex(int index) {
843 document.CharIndexToLineTag(index, out line, out tag, out pos);
845 return new Point((int)line.widths[pos] + 1, line.Y + 1);
848 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
851 // FIXME - ignoring unicode
852 if (fileType == RichTextBoxStreamType.PlainText) {
858 sb = new StringBuilder((int)data.Length);
859 buffer = new byte[1024];
863 throw new IOException("Not enough memory to load document");
867 while (count < data.Length) {
868 count += data.Read(buffer, count, 1024);
871 base.Text = sb.ToString();
875 InsertRTFFromStream(data, 0, 1);
877 document.PositionCaret (document.GetLine (1), 0);
878 document.SetSelectionToCaret (true);
882 [MonoTODO("Make smarter RTF detection?")]
883 public void LoadFile(string path) {
884 if (path.EndsWith(".rtf")) {
885 LoadFile(path, RichTextBoxStreamType.RichText);
887 LoadFile(path, RichTextBoxStreamType.PlainText);
891 public void LoadFile(string path, RichTextBoxStreamType fileType) {
897 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
898 LoadFile(data, fileType);
902 throw new IOException("Could not open file " + path);
912 public void Paste(DataFormats.Format clipFormat) {
913 base.Paste(Clipboard.GetDataObject(), clipFormat, false);
920 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
926 if (fileType == RichTextBoxStreamType.UnicodePlainText) {
927 encoding = Encoding.Unicode;
929 encoding = Encoding.ASCII;
933 case RichTextBoxStreamType.PlainText:
934 case RichTextBoxStreamType.TextTextOleObjs:
935 case RichTextBoxStreamType.UnicodePlainText: {
937 bytes = encoding.GetBytes(document.Root.text.ToString());
938 data.Write(bytes, 0, bytes.Length);
942 for (i = 1; i < document.Lines; i++) {
943 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
944 data.Write(bytes, 0, bytes.Length);
946 bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
947 data.Write(bytes, 0, bytes.Length);
952 // If we're here we're saving RTF
959 start_line = document.GetLine(1);
960 end_line = document.GetLine(document.Lines);
961 rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
963 bytes = new Byte[4096];
965 // Let's chunk it so we don't use up all memory...
966 for (i = 0; i < total; i += 1024) {
967 if ((i + 1024) < total) {
968 current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
971 current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
973 data.Write(bytes, 0, current);
977 public void SaveFile(string path) {
978 if (path.EndsWith(".rtf")) {
979 SaveFile(path, RichTextBoxStreamType.RichText);
981 SaveFile(path, RichTextBoxStreamType.PlainText);
985 public void SaveFile(string path, RichTextBoxStreamType fileType) {
991 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
992 SaveFile(data, fileType);
996 // throw new IOException("Could not write document to file " + path);
1006 #endregion // Public Instance Methods
1008 #region Protected Instance Methods
1009 protected virtual object CreateRichEditOleCallback() {
1010 throw new NotImplementedException();
1013 protected override void OnBackColorChanged(EventArgs e) {
1014 base.OnBackColorChanged (e);
1017 protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
1018 ContentsResizedEventHandler eh = (ContentsResizedEventHandler)(Events [ContentsResizedEvent]);
1023 protected override void OnContextMenuChanged(EventArgs e) {
1024 base.OnContextMenuChanged (e);
1027 protected override void OnHandleCreated(EventArgs e) {
1028 base.OnHandleCreated (e);
1031 protected override void OnHandleDestroyed(EventArgs e) {
1032 base.OnHandleDestroyed (e);
1035 protected virtual void OnHScroll(EventArgs e) {
1036 EventHandler eh = (EventHandler)(Events [HScrollEvent]);
1041 [MonoTODO("Determine when to call this")]
1042 protected virtual void OnImeChange(EventArgs e) {
1043 EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
1048 protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
1049 LinkClickedEventHandler eh = (LinkClickedEventHandler)(Events [LinkClickedEvent]);
1054 protected virtual void OnProtected(EventArgs e) {
1055 EventHandler eh = (EventHandler)(Events [ProtectedEvent]);
1060 protected override void OnRightToLeftChanged(EventArgs e) {
1061 base.OnRightToLeftChanged (e);
1064 protected virtual void OnSelectionChanged(EventArgs e) {
1065 EventHandler eh = (EventHandler)(Events [SelectionChangedEvent]);
1070 protected override void OnSystemColorsChanged(EventArgs e) {
1071 base.OnSystemColorsChanged (e);
1074 protected override void OnTextChanged(EventArgs e) {
1075 base.OnTextChanged (e);
1078 protected virtual void OnVScroll(EventArgs e) {
1079 EventHandler eh = (EventHandler)(Events [VScrollEvent]);
1084 protected override void WndProc(ref Message m) {
1085 base.WndProc (ref m);
1087 #endregion // Protected Instance Methods
1090 static object ContentsResizedEvent = new object ();
1091 static object HScrollEvent = new object ();
1092 static object ImeChangeEvent = new object ();
1093 static object LinkClickedEvent = new object ();
1094 static object ProtectedEvent = new object ();
1095 static object SelectionChangedEvent = new object ();
1096 static object VScrollEvent = new object ();
1099 [EditorBrowsable(EditorBrowsableState.Never)]
1100 public new event EventHandler BackgroundImageChanged {
1101 add { base.BackgroundImageChanged += value; }
1102 remove { base.BackgroundImageChanged -= value; }
1105 public event ContentsResizedEventHandler ContentsResized {
1106 add { Events.AddHandler (ContentsResizedEvent, value); }
1107 remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1111 [EditorBrowsable(EditorBrowsableState.Never)]
1112 public new event EventHandler DoubleClick {
1113 add { base.DoubleClick += value; }
1114 remove { base.DoubleClick -= value; }
1118 [EditorBrowsable(EditorBrowsableState.Never)]
1119 public new event DragEventHandler DragDrop {
1120 add { base.DragDrop += value; }
1121 remove { base.DragDrop -= value; }
1125 [EditorBrowsable(EditorBrowsableState.Never)]
1126 public new event DragEventHandler DragEnter {
1127 add { base.DragEnter += value; }
1128 remove { base.DragEnter -= value; }
1132 [EditorBrowsable(EditorBrowsableState.Never)]
1133 public new event EventHandler DragLeave {
1134 add { base.DragLeave += value; }
1135 remove { base.DragLeave -= value; }
1140 [EditorBrowsable(EditorBrowsableState.Never)]
1141 public new event DragEventHandler DragOver {
1142 add { base.DragOver += value; }
1143 remove { base.DragOver -= value; }
1148 [EditorBrowsable(EditorBrowsableState.Never)]
1149 public new event GiveFeedbackEventHandler GiveFeedback {
1150 add { base.GiveFeedback += value; }
1151 remove { base.GiveFeedback -= value; }
1154 public event EventHandler HScroll {
1155 add { Events.AddHandler (HScrollEvent, value); }
1156 remove { Events.RemoveHandler (HScrollEvent, value); }
1159 public event EventHandler ImeChange {
1160 add { Events.AddHandler (ImeChangeEvent, value); }
1161 remove { Events.RemoveHandler (ImeChangeEvent, value); }
1164 public event LinkClickedEventHandler LinkClicked {
1165 add { Events.AddHandler (LinkClickedEvent, value); }
1166 remove { Events.RemoveHandler (LinkClickedEvent, value); }
1169 public event EventHandler Protected {
1170 add { Events.AddHandler (ProtectedEvent, value); }
1171 remove { Events.RemoveHandler (ProtectedEvent, value); }
1175 [EditorBrowsable(EditorBrowsableState.Never)]
1176 public new event QueryContinueDragEventHandler QueryContinueDrag {
1177 add { base.QueryContinueDrag += value; }
1178 remove { base.QueryContinueDrag -= value; }
1181 public event EventHandler SelectionChanged {
1182 add { Events.AddHandler (SelectionChangedEvent, value); }
1183 remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1186 public event EventHandler VScroll {
1187 add { Events.AddHandler (VScrollEvent, value); }
1188 remove { Events.RemoveHandler (VScrollEvent, value); }
1190 #endregion // Events
1192 #region Private Methods
1194 internal override void SelectWord ()
1196 document.ExpandSelection(CaretSelection.Word, false);
1199 private void HandleControl(RTF.RTF rtf) {
1200 // Console.WriteLine ("HANDLING MAJOR: {0} MINOR: {1}", rtf.Major, rtf.Minor);
1202 case RTF.Major.Unicode: {
1204 case Minor.UnicodeCharBytes: {
1205 rtf_skip_width = rtf.Param;
1209 case Minor.UnicodeChar: {
1210 rtf_skip_count += rtf_skip_width;
1211 rtf_line.Append((char)rtf.Param);
1218 case RTF.Major.Destination: {
1219 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1224 case RTF.Major.CharAttr: {
1226 case Minor.ForeColor: {
1227 System.Windows.Forms.RTF.Color color;
1229 color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
1230 if (color != null) {
1231 FlushText(rtf, false);
1232 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
1233 this.rtf_color = new SolidBrush(ForeColor);
1235 this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1241 case Minor.FontSize: {
1242 FlushText(rtf, false);
1243 this.rtf_rtffont_size = rtf.Param / 2;
1247 case Minor.FontNum: {
1248 System.Windows.Forms.RTF.Font font;
1250 font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
1252 FlushText(rtf, false);
1253 this.rtf_rtffont = font;
1259 FlushText(rtf, false);
1260 rtf_rtfstyle = FontStyle.Regular;
1265 FlushText(rtf, false);
1266 if (rtf.Param == RTF.RTF.NoParam) {
1267 rtf_rtfstyle |= FontStyle.Bold;
1269 rtf_rtfstyle &= ~FontStyle.Bold;
1274 case Minor.Italic: {
1275 FlushText(rtf, false);
1276 if (rtf.Param == RTF.RTF.NoParam) {
1277 rtf_rtfstyle |= FontStyle.Italic;
1279 rtf_rtfstyle &= ~FontStyle.Italic;
1284 case Minor.StrikeThru: {
1285 FlushText(rtf, false);
1286 if (rtf.Param == RTF.RTF.NoParam) {
1287 rtf_rtfstyle |= FontStyle.Strikeout;
1289 rtf_rtfstyle &= ~FontStyle.Strikeout;
1294 case Minor.Underline: {
1295 FlushText(rtf, false);
1296 if (rtf.Param == RTF.RTF.NoParam) {
1297 rtf_rtfstyle |= FontStyle.Underline;
1299 rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline;
1304 case Minor.NoUnderline: {
1305 FlushText(rtf, false);
1306 rtf_rtfstyle &= ~FontStyle.Underline;
1313 case RTF.Major.SpecialChar: {
1314 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1321 private void SpecialChar(RTF.RTF rtf) {
1328 FlushText(rtf, true);
1337 case Minor.NoBrkSpace: {
1343 rtf_line.Append ("\t");
1344 // FlushText (rtf, false);
1348 case Minor.NoReqHyphen:
1349 case Minor.NoBrkHyphen: {
1350 rtf_line.Append ("-");
1351 // FlushText (rtf, false);
1355 case Minor.Bullet: {
1356 Console.WriteLine("*");
1360 case Minor.WidowCtrl:
1363 case Minor.EmDash: {
1364 rtf_line.Append ("\u2014");
1368 case Minor.EnDash: {
1369 rtf_line.Append ("\u2013");
1373 case Minor.LQuote: {
1374 Console.Write("\u2018");
1378 case Minor.RQuote: {
1379 Console.Write("\u2019");
1383 case Minor.LDblQuote: {
1384 Console.Write("\u201C");
1388 case Minor.RDblQuote: {
1389 Console.Write("\u201D");
1394 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1401 private void HandleText(RTF.RTF rtf) {
1402 if (rtf_skip_count > 0) {
1407 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1408 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1410 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1411 rtf_line.Append((char)rtf.Major);
1413 //rtf_line.Append((char)rtf.Major);
1414 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1419 private void FlushText(RTF.RTF rtf, bool newline) {
1423 length = rtf_line.Length;
1424 if (!newline && (length == 0)) {
1428 if (rtf_rtffont == null) {
1429 // First font in table is default
1430 rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0);
1433 font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1435 if (rtf_color == null) {
1436 System.Windows.Forms.RTF.Color color;
1438 // First color in table is default
1439 color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0);
1441 if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
1442 rtf_color = new SolidBrush(ForeColor);
1444 rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1448 rtf_chars += rtf_line.Length;
1450 if (rtf_cursor_x == 0) {
1451 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color);
1455 line = document.GetLine(rtf_cursor_y);
1456 if (rtf_line.Length > 0) {
1457 document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1458 document.FormatText(line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, font, rtf_color); // FormatText is 1-based
1461 document.Split(line, rtf_cursor_x + length);
1469 rtf_cursor_x += length;
1471 rtf_line.Length = 0; // Empty line
1474 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1479 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
1482 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) {
1485 rtf = new RTF.RTF(data);
1488 rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1489 rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1493 rtf_line = new StringBuilder();
1495 rtf_rtffont_size = (int)this.Font.Size;
1496 rtf_rtfalign = HorizontalAlignment.Left;
1497 rtf_rtfstyle = FontStyle.Regular;
1499 rtf_cursor_x = cursor_x;
1500 rtf_cursor_y = cursor_y;
1502 rtf.DefaultFont(this.Font.Name);
1504 rtf_text_map = new RTF.TextMap();
1505 RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1507 document.NoRecalc = true;
1510 rtf.Read(); // That's it
1511 FlushText(rtf, false);
1514 catch (RTF.RTFException e) {
1515 // Seems to be plain text or broken RTF
1516 Console.WriteLine("RTF Parsing failure: {0}", e.Message);
1519 to_x = rtf_cursor_x;
1520 to_y = rtf_cursor_y;
1523 document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
1524 document.NoRecalc = false;
1526 document.Invalidate(document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1529 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1533 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1537 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1542 if (p.X >= document.ViewPortWidth) {
1543 p.X = document.ViewPortWidth - 1;
1544 } else if (p.X < 0) {
1548 if (p.Y >= document.ViewPortHeight) {
1549 p.Y = document.ViewPortHeight - 1;
1550 } else if (p.Y < 0) {
1554 tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1557 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1558 if (prev_index != font_index) {
1559 rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry
1562 if ((prev_font == null) || (prev_font.Size != font.Size)) {
1563 rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size
1566 if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1570 if (prev_font != null) {
1576 if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1580 if (prev_font != null) {
1586 if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1587 if (font.Strikeout) {
1588 rtf.Append("\\strike");
1590 if (prev_font != null) {
1591 rtf.Append("\\strike0");
1596 if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1597 if (font.Underline) {
1600 if (prev_font != null) {
1601 rtf.Append("\\ul0");
1607 [MonoTODO("Emit unicode and other special characters properly")]
1608 private void EmitRTFText(StringBuilder rtf, string text) {
1612 // start_pos and end_pos are 0-based
1613 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1627 sb = new StringBuilder();
1628 fonts = new ArrayList(10);
1629 colors = new ArrayList(10);
1631 // Two runs, first we parse to determine tables;
1632 // and unlike most of our processing here we work on tags
1635 line_no = start_line.line_no;
1638 // Add default font and color; to optimize document content we don't
1639 // use this.Font and this.ForeColor but the font/color from the first tag
1640 tag = LineTag.FindTag(start_line, pos);
1642 color = ((SolidBrush)tag.color).Color;
1643 fonts.Add(font.Name);
1646 while (line_no <= end_line.line_no) {
1647 line = document.GetLine(line_no);
1648 tag = LineTag.FindTag(line, pos);
1650 if (line_no != end_line.line_no) {
1651 line_len = line.text.Length;
1656 while (pos < line_len) {
1657 if (tag.font.Name != font.Name) {
1659 if (!fonts.Contains(font.Name)) {
1660 fonts.Add(font.Name);
1664 if (((SolidBrush)tag.color).Color != color) {
1665 color = ((SolidBrush)tag.color).Color;
1666 if (!colors.Contains(color)) {
1671 pos = tag.start + tag.length - 1;
1678 // We have the tables, emit the header
1679 sb.Append("{\\rtf1\\ansi");
1680 sb.Append("\\ansicpg1252"); // FIXME - is this correct?
1683 sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1686 sb.Append("\\deflang1033\n"); // FIXME - always 1033?
1688 // Emit the font table
1689 sb.Append("{\\fonttbl");
1690 for (i = 0; i < fonts.Count; i++) {
1691 sb.Append(String.Format("{{\\f{0}", i)); // {Font
1692 sb.Append("\\fnil"); // Family
1693 sb.Append("\\fcharset0 "); // Charset ANSI<space>
1694 sb.Append((string)fonts[i]); // Font name
1695 sb.Append(";}"); // }
1699 // Emit the color table (if needed)
1700 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))) {
1701 sb.Append("{\\colortbl "); // Header and NO! default color
1702 for (i = 0; i < colors.Count; i++) {
1703 sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1704 sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1705 sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1711 sb.Append("{\\*\\generator Mono RichTextBox;}");
1712 // Emit initial paragraph settings
1713 tag = LineTag.FindTag(start_line, start_pos);
1714 sb.Append("\\pard"); // Reset to default paragraph properties
1715 EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font); // Font properties
1716 sb.Append(" "); // Space separator
1719 color = (Color)colors[0];
1721 line_no = start_line.line_no;
1724 while (line_no <= end_line.line_no) {
1725 line = document.GetLine(line_no);
1726 tag = LineTag.FindTag(line, pos);
1728 if (line_no != end_line.line_no) {
1729 line_len = line.text.Length;
1734 while (pos < line_len) {
1737 if (tag.font != font) {
1738 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1742 if (((SolidBrush)tag.color).Color != color) {
1743 color = ((SolidBrush)tag.color).Color;
1744 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1746 if (length != sb.Length) {
1747 sb.Append(" "); // Emit space to separate keywords from text
1750 // Emit the string itself
1751 if (line_no != end_line.line_no) {
1752 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1754 if (end_pos < (tag.start + tag.length - 1)) {
1755 // Emit partial tag only, end_pos is inside this tag
1756 EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1758 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1762 pos = tag.start + tag.length - 1;
1765 if (pos >= line.text.Length) {
1766 if (!line.soft_break) {
1767 sb.Append("\\par\n");
1778 #endregion // Private Methods