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)]
45 public class RichTextBox : TextBoxBase {
46 #region Local Variables
47 internal bool auto_word_select;
48 internal int bullet_indent;
49 internal bool detect_urls;
50 internal int margin_right;
53 private RTF.TextMap rtf_text_map;
54 private int rtf_skip_width;
55 private int rtf_skip_count;
56 private StringBuilder rtf_line;
57 private SolidBrush rtf_color;
58 private RTF.Font rtf_rtffont;
59 private int rtf_rtffont_size;
60 private FontStyle rtf_rtfstyle;
61 private HorizontalAlignment rtf_rtfalign;
62 private int rtf_cursor_x;
63 private int rtf_cursor_y;
64 private int rtf_chars;
65 private int rtf_par_line_left_indent;
66 #endregion // Local Variables
68 #region Public Constructors
69 public RichTextBox() {
70 accepts_return = true;
71 auto_word_select = false;
74 max_length = Int32.MaxValue;
77 base.Multiline = true;
78 document.CRLFSize = 1;
79 shortcuts_enabled = true;
81 scrollbars = RichTextBoxScrollBars.Both;
82 alignment = HorizontalAlignment.Left;
83 LostFocus += new EventHandler(RichTextBox_LostFocus);
84 GotFocus += new EventHandler(RichTextBox_GotFocus);
85 BackColor = ThemeEngine.Current.ColorWindow;
86 backcolor_set = false;
87 ForeColor = ThemeEngine.Current.ColorWindowText;
89 base.HScrolled += new EventHandler(RichTextBox_HScrolled);
90 base.VScrolled += new EventHandler(RichTextBox_VScrolled);
93 SetStyle (ControlStyles.StandardDoubleClick, false);
96 #endregion // Public Constructors
98 #region Private & Internal Methods
99 private void RichTextBox_LostFocus(object sender, EventArgs e) {
103 private void RichTextBox_GotFocus(object sender, EventArgs e) {
106 #endregion // Private & Internal Methods
108 #region Public Instance Properties
112 public override bool AllowDrop {
114 return base.AllowDrop;
118 base.AllowDrop = value;
122 [DefaultValue(false)]
124 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
125 [RefreshProperties (RefreshProperties.Repaint)]
126 [EditorBrowsable (EditorBrowsableState.Never)]
131 public override bool AutoSize {
137 base.AutoSize = value;
141 [DefaultValue(false)]
142 public bool AutoWordSelection {
144 return auto_word_select;
148 auto_word_select = true;
153 [EditorBrowsable(EditorBrowsableState.Never)]
154 public override System.Drawing.Image BackgroundImage {
155 get { return base.BackgroundImage; }
156 set { base.BackgroundImage = value; }
161 public int BulletIndent {
163 return bullet_indent;
167 bullet_indent = value;
172 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
173 public bool CanRedo {
175 return document.undo.CanRedo;
180 public bool DetectUrls {
190 public override Font Font {
201 if (PreferredHeight != Height) {
202 Height = PreferredHeight;
208 // Font changes always set the whole doc to that font
209 start = document.GetLine(1);
210 end = document.GetLine(document.Lines);
211 document.FormatText(start, 1, end, end.text.Length + 1, base.Font, null, null, FormatSpecified.Font);
216 public override Color ForeColor {
218 return base.ForeColor;
222 base.ForeColor = value;
226 [DefaultValue(Int32.MaxValue)]
227 public override int MaxLength {
229 return base.max_length;
233 base.max_length = value;
238 public override bool Multiline {
240 return base.Multiline;
244 base.Multiline = value;
249 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
251 public string RedoActionName {
253 return document.undo.RedoActionName;
259 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
260 public int RightMargin {
266 margin_right = value;
271 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
273 [RefreshProperties (RefreshProperties.All)]
282 start_line = document.GetLine(1);
283 end_line = document.GetLine(document.Lines);
284 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
291 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
293 InsertRTFFromStream(data, 0, 1);
301 [DefaultValue(RichTextBoxScrollBars.Both)]
303 public RichTextBoxScrollBars ScrollBars {
315 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
316 public string SelectedRtf {
318 return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
330 if (document.selection_visible) {
331 document.ReplaceSelection("", false);
334 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
336 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
337 InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y, out chars);
340 document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
341 document.SetSelection(line, sel_start);
342 document.PositionCaret(line, sel_start);
343 document.DisplayCaret();
345 OnTextChanged(EventArgs.Empty);
351 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
352 public override string SelectedText {
354 return base.SelectedText;
358 base.SelectedText = value;
363 [DefaultValue(HorizontalAlignment.Left)]
364 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
365 public HorizontalAlignment SelectionAlignment {
367 HorizontalAlignment align;
372 start = document.ParagraphStart(document.selection_start.line);
373 align = start.alignment;
375 end = document.ParagraphEnd(document.selection_end.line);
380 if (line.alignment != align) {
381 return HorizontalAlignment.Left;
387 line = document.GetLine(line.line_no + 1);
398 start = document.ParagraphStart(document.selection_start.line);
400 end = document.ParagraphEnd(document.selection_end.line);
405 line.alignment = value;
410 line = document.GetLine(line.line_no + 1);
412 this.CalculateDocument();
417 [DefaultValue(false)]
418 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
420 public bool SelectionBullet {
431 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
433 public int SelectionCharOffset {
443 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
444 public Color SelectionColor {
451 start = document.selection_start.tag;
452 end = document.selection_end.tag;
453 color = ((SolidBrush)document.selection_start.tag.color).Color;
457 if (!color.Equals(((SolidBrush)tag.color).Color)) {
465 tag = document.NextTag(tag);
476 FontDefinition attributes;
480 attributes = new FontDefinition();
481 attributes.color = value;
483 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
484 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
486 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
488 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
489 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
491 document.UpdateView(document.selection_start.line, 0);
492 document.AlignCaret();
497 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
498 public Font SelectionFont {
505 start = document.selection_start.tag;
506 end = document.selection_end.tag;
507 font = document.selection_start.tag.font;
509 if (selection_length > 1) {
513 if (!font.Equals(tag.font)) {
521 tag = document.NextTag(tag);
533 FontDefinition attributes;
537 attributes = new FontDefinition();
538 attributes.font_obj = value;
540 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
541 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
543 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
545 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
546 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
548 document.UpdateView(document.selection_start.line, 0);
549 document.AlignCaret();
556 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
558 public int SelectionHangingIndent {
569 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
571 public int SelectionIndent {
581 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
582 public override int SelectionLength {
584 return base.SelectionLength;
588 base.SelectionLength = value;
593 [DefaultValue(false)]
594 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
596 public bool SelectionProtected {
607 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
609 public int SelectionRightIndent {
619 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
621 public int[] SelectionTabs {
631 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
632 public RichTextBoxSelectionTypes SelectionType {
634 if (document.selection_start == document.selection_end) {
635 return RichTextBoxSelectionTypes.Empty;
639 if (SelectedText.Length > 1) {
640 return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
643 return RichTextBoxSelectionTypes.Text;
647 [DefaultValue(false)]
649 public bool ShowSelectionMargin {
660 [RefreshProperties (RefreshProperties.All)]
662 public override string Text {
673 public override int TextLength {
675 return base.TextLength;
680 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
681 public string UndoActionName {
683 return document.undo.UndoActionName;
689 public float ZoomFactor {
698 #endregion // Public Instance Properties
700 #region Protected Instance Properties
701 protected override CreateParams CreateParams {
703 return base.CreateParams;
707 protected override Size DefaultSize {
709 return new Size(100, 96);
712 #endregion // Protected Instance Properties
714 #region Public Instance Methods
715 public bool CanPaste(DataFormats.Format clipFormat) {
716 if ((clipFormat.Name == DataFormats.Rtf) ||
717 (clipFormat.Name == DataFormats.Text) ||
718 (clipFormat.Name == DataFormats.UnicodeText)) {
724 public int Find(char[] characterSet) {
725 return Find(characterSet, -1, -1);
728 public int Find(char[] characterSet, int start) {
729 return Find(characterSet, start, -1);
732 public int Find(char[] characterSet, int start, int end) {
733 Document.Marker start_mark;
734 Document.Marker end_mark;
735 Document.Marker result;
738 document.GetMarker(out start_mark, true);
744 start_mark = new Document.Marker();
746 document.CharIndexToLineTag(start, out line, out tag, out pos);
747 start_mark.line = line;
748 start_mark.tag = tag;
749 start_mark.pos = pos;
753 document.GetMarker(out end_mark, false);
759 end_mark = new Document.Marker();
761 document.CharIndexToLineTag(end, out line, out tag, out pos);
762 end_mark.line = line;
767 if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
768 return document.LineTagToCharIndex(result.line, result.pos);
774 public int Find(string str) {
775 return Find(str, -1, -1, RichTextBoxFinds.None);
778 public int Find(string str, int start, int end, RichTextBoxFinds options) {
779 Document.Marker start_mark;
780 Document.Marker end_mark;
781 Document.Marker result;
784 document.GetMarker(out start_mark, true);
790 start_mark = new Document.Marker();
792 document.CharIndexToLineTag(start, out line, out tag, out pos);
794 start_mark.line = line;
795 start_mark.tag = tag;
796 start_mark.pos = pos;
800 document.GetMarker(out end_mark, false);
806 end_mark = new Document.Marker();
808 document.CharIndexToLineTag(end, out line, out tag, out pos);
810 end_mark.line = line;
815 if (document.Find(str, start_mark, end_mark, out result, options)) {
816 return document.LineTagToCharIndex(result.line, result.pos);
822 public int Find(string str, int start, RichTextBoxFinds options) {
823 return Find(str, start, -1, options);
826 public int Find(string str, RichTextBoxFinds options) {
827 return Find(str, -1, -1, options);
830 public char GetCharFromPosition(Point pt) {
834 PointToTagPos(pt, out tag, out pos);
836 if (pos >= tag.line.text.Length) {
840 return tag.line.text[pos];
844 public int GetCharIndexFromPosition(Point pt) {
848 PointToTagPos(pt, out tag, out pos);
850 return document.LineTagToCharIndex(tag.line, pos);
853 public int GetLineFromCharIndex(int index) {
858 document.CharIndexToLineTag(index, out line, out tag, out pos);
860 return line.LineNo - 1;
863 public Point GetPositionFromCharIndex(int index) {
868 document.CharIndexToLineTag(index, out line, out tag, out pos);
870 return new Point((int)line.widths[pos] + 1, line.Y + 1);
873 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
877 // FIXME - ignoring unicode
878 if (fileType == RichTextBoxStreamType.PlainText) {
884 sb = new StringBuilder((int)data.Length);
885 buffer = new byte[1024];
887 throw new IOException("Not enough memory to load document");
891 while (count < data.Length) {
892 count += data.Read(buffer, count, 1024);
895 base.Text = sb.ToString();
899 InsertRTFFromStream(data, 0, 1);
901 document.PositionCaret (document.GetLine (1), 0);
902 document.SetSelectionToCaret (true);
906 [MonoTODO("Make smarter RTF detection?")]
907 public void LoadFile(string path) {
908 if (path.EndsWith(".rtf")) {
909 LoadFile(path, RichTextBoxStreamType.RichText);
911 LoadFile(path, RichTextBoxStreamType.PlainText);
915 public void LoadFile(string path, RichTextBoxStreamType fileType) {
922 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
924 LoadFile(data, fileType);
928 throw new IOException("Could not open file " + path);
938 public void Paste(DataFormats.Format clipFormat) {
939 base.Paste(Clipboard.GetDataObject(), clipFormat, false);
944 document.undo.Redo ();
947 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
953 if (fileType == RichTextBoxStreamType.UnicodePlainText) {
954 encoding = Encoding.Unicode;
956 encoding = Encoding.ASCII;
960 case RichTextBoxStreamType.PlainText:
961 case RichTextBoxStreamType.TextTextOleObjs:
962 case RichTextBoxStreamType.UnicodePlainText: {
964 bytes = encoding.GetBytes(document.Root.text.ToString());
965 data.Write(bytes, 0, bytes.Length);
969 for (i = 1; i < document.Lines; i++) {
970 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
971 data.Write(bytes, 0, bytes.Length);
973 bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
974 data.Write(bytes, 0, bytes.Length);
979 // If we're here we're saving RTF
986 start_line = document.GetLine(1);
987 end_line = document.GetLine(document.Lines);
988 rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
990 bytes = new Byte[4096];
992 // Let's chunk it so we don't use up all memory...
993 for (i = 0; i < total; i += 1024) {
994 if ((i + 1024) < total) {
995 current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
998 current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
1000 data.Write(bytes, 0, current);
1004 public void SaveFile(string path) {
1005 if (path.EndsWith(".rtf")) {
1006 SaveFile(path, RichTextBoxStreamType.RichText);
1008 SaveFile(path, RichTextBoxStreamType.PlainText);
1012 public void SaveFile(string path, RichTextBoxStreamType fileType) {
1018 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
1019 SaveFile(data, fileType);
1023 // throw new IOException("Could not write document to file " + path);
1033 #endregion // Public Instance Methods
1035 #region Protected Instance Methods
1036 protected virtual object CreateRichEditOleCallback() {
1037 throw new NotImplementedException();
1040 protected override void OnBackColorChanged(EventArgs e) {
1041 base.OnBackColorChanged (e);
1044 protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
1045 ContentsResizedEventHandler eh = (ContentsResizedEventHandler)(Events [ContentsResizedEvent]);
1050 protected override void OnContextMenuChanged(EventArgs e) {
1051 base.OnContextMenuChanged (e);
1054 protected override void OnHandleCreated(EventArgs e) {
1055 base.OnHandleCreated (e);
1058 protected override void OnHandleDestroyed(EventArgs e) {
1059 base.OnHandleDestroyed (e);
1062 protected virtual void OnHScroll(EventArgs e) {
1063 EventHandler eh = (EventHandler)(Events [HScrollEvent]);
1068 [MonoTODO("Determine when to call this")]
1069 protected virtual void OnImeChange(EventArgs e) {
1070 EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
1075 protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
1076 LinkClickedEventHandler eh = (LinkClickedEventHandler)(Events [LinkClickedEvent]);
1081 protected virtual void OnProtected(EventArgs e) {
1082 EventHandler eh = (EventHandler)(Events [ProtectedEvent]);
1087 protected override void OnRightToLeftChanged(EventArgs e) {
1088 base.OnRightToLeftChanged (e);
1091 protected virtual void OnSelectionChanged(EventArgs e) {
1092 EventHandler eh = (EventHandler)(Events [SelectionChangedEvent]);
1097 protected override void OnSystemColorsChanged(EventArgs e) {
1098 base.OnSystemColorsChanged (e);
1101 protected override void OnTextChanged(EventArgs e) {
1102 base.OnTextChanged (e);
1105 protected virtual void OnVScroll(EventArgs e) {
1106 EventHandler eh = (EventHandler)(Events [VScrollEvent]);
1111 protected override void WndProc(ref Message m) {
1112 base.WndProc (ref m);
1114 #endregion // Protected Instance Methods
1117 static object ContentsResizedEvent = new object ();
1118 static object HScrollEvent = new object ();
1119 static object ImeChangeEvent = new object ();
1120 static object LinkClickedEvent = new object ();
1121 static object ProtectedEvent = new object ();
1122 static object SelectionChangedEvent = new object ();
1123 static object VScrollEvent = new object ();
1126 [EditorBrowsable(EditorBrowsableState.Never)]
1127 public new event EventHandler BackgroundImageChanged {
1128 add { base.BackgroundImageChanged += value; }
1129 remove { base.BackgroundImageChanged -= value; }
1132 public event ContentsResizedEventHandler ContentsResized {
1133 add { Events.AddHandler (ContentsResizedEvent, value); }
1134 remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1138 [EditorBrowsable(EditorBrowsableState.Never)]
1139 public new event EventHandler DoubleClick {
1140 add { base.DoubleClick += value; }
1141 remove { base.DoubleClick -= value; }
1146 [EditorBrowsable(EditorBrowsableState.Never)]
1148 public new event DragEventHandler DragDrop {
1149 add { base.DragDrop += value; }
1150 remove { base.DragDrop -= value; }
1155 [EditorBrowsable(EditorBrowsableState.Never)]
1157 public new event DragEventHandler DragEnter {
1158 add { base.DragEnter += value; }
1159 remove { base.DragEnter -= value; }
1163 [EditorBrowsable(EditorBrowsableState.Never)]
1164 public new event EventHandler DragLeave {
1165 add { base.DragLeave += value; }
1166 remove { base.DragLeave -= value; }
1171 [EditorBrowsable(EditorBrowsableState.Never)]
1172 public new event DragEventHandler DragOver {
1173 add { base.DragOver += value; }
1174 remove { base.DragOver -= value; }
1179 [EditorBrowsable(EditorBrowsableState.Never)]
1180 public new event GiveFeedbackEventHandler GiveFeedback {
1181 add { base.GiveFeedback += value; }
1182 remove { base.GiveFeedback -= value; }
1185 public event EventHandler HScroll {
1186 add { Events.AddHandler (HScrollEvent, value); }
1187 remove { Events.RemoveHandler (HScrollEvent, value); }
1190 public event EventHandler ImeChange {
1191 add { Events.AddHandler (ImeChangeEvent, value); }
1192 remove { Events.RemoveHandler (ImeChangeEvent, value); }
1195 public event LinkClickedEventHandler LinkClicked {
1196 add { Events.AddHandler (LinkClickedEvent, value); }
1197 remove { Events.RemoveHandler (LinkClickedEvent, value); }
1200 public event EventHandler Protected {
1201 add { Events.AddHandler (ProtectedEvent, value); }
1202 remove { Events.RemoveHandler (ProtectedEvent, value); }
1206 [EditorBrowsable(EditorBrowsableState.Never)]
1207 public new event QueryContinueDragEventHandler QueryContinueDrag {
1208 add { base.QueryContinueDrag += value; }
1209 remove { base.QueryContinueDrag -= value; }
1212 public event EventHandler SelectionChanged {
1213 add { Events.AddHandler (SelectionChangedEvent, value); }
1214 remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1217 public event EventHandler VScroll {
1218 add { Events.AddHandler (VScrollEvent, value); }
1219 remove { Events.RemoveHandler (VScrollEvent, value); }
1221 #endregion // Events
1223 #region Private Methods
1225 internal override void SelectWord ()
1227 document.ExpandSelection(CaretSelection.Word, false);
1230 private void HandleControl(RTF.RTF rtf) {
1232 case RTF.Major.Unicode: {
1234 case Minor.UnicodeCharBytes: {
1235 rtf_skip_width = rtf.Param;
1239 case Minor.UnicodeChar: {
1240 rtf_skip_count += rtf_skip_width;
1241 rtf_line.Append((char)rtf.Param);
1248 case RTF.Major.Destination: {
1249 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1254 case RTF.Major.PictAttr:
1255 if (rtf.Picture != null && rtf.Picture.IsValid ()) {
1256 Line line = document.GetLine (rtf_cursor_y);
1257 document.InsertPicture (line, 0, rtf.Picture);
1260 FlushText (rtf, true);
1265 case RTF.Major.CharAttr: {
1267 case Minor.ForeColor: {
1268 System.Windows.Forms.RTF.Color color;
1270 color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
1272 if (color != null) {
1273 FlushText(rtf, false);
1274 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
1275 this.rtf_color = new SolidBrush(ForeColor);
1277 this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1279 FlushText (rtf, false);
1284 case Minor.FontSize: {
1285 FlushText(rtf, false);
1286 this.rtf_rtffont_size = rtf.Param / 2;
1290 case Minor.FontNum: {
1291 System.Windows.Forms.RTF.Font font;
1293 font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
1295 FlushText(rtf, false);
1296 this.rtf_rtffont = font;
1302 FlushText(rtf, false);
1303 rtf_rtfstyle = FontStyle.Regular;
1308 FlushText(rtf, false);
1309 if (rtf.Param == RTF.RTF.NoParam) {
1310 rtf_rtfstyle |= FontStyle.Bold;
1312 rtf_rtfstyle &= ~FontStyle.Bold;
1317 case Minor.Italic: {
1318 FlushText(rtf, false);
1319 if (rtf.Param == RTF.RTF.NoParam) {
1320 rtf_rtfstyle |= FontStyle.Italic;
1322 rtf_rtfstyle &= ~FontStyle.Italic;
1327 case Minor.StrikeThru: {
1328 FlushText(rtf, false);
1329 if (rtf.Param == RTF.RTF.NoParam) {
1330 rtf_rtfstyle |= FontStyle.Strikeout;
1332 rtf_rtfstyle &= ~FontStyle.Strikeout;
1337 case Minor.Underline: {
1338 FlushText(rtf, false);
1339 if (rtf.Param == RTF.RTF.NoParam) {
1340 rtf_rtfstyle |= FontStyle.Underline;
1342 rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline;
1347 case Minor.NoUnderline: {
1348 FlushText(rtf, false);
1349 rtf_rtfstyle &= ~FontStyle.Underline;
1356 case RTF.Major.ParAttr: {
1357 switch (rtf.Minor) {
1358 case Minor.LeftIndent:
1359 rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * CreateGraphics ().DpiX + 0.5F);
1365 case RTF.Major.SpecialChar: {
1366 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1373 private void SpecialChar(RTF.RTF rtf) {
1380 FlushText(rtf, true);
1389 case Minor.NoBrkSpace: {
1395 rtf_line.Append ("\t");
1396 // FlushText (rtf, false);
1400 case Minor.NoReqHyphen:
1401 case Minor.NoBrkHyphen: {
1402 rtf_line.Append ("-");
1403 // FlushText (rtf, false);
1407 case Minor.Bullet: {
1408 Console.WriteLine("*");
1412 case Minor.WidowCtrl:
1415 case Minor.EmDash: {
1416 rtf_line.Append ("\u2014");
1420 case Minor.EnDash: {
1421 rtf_line.Append ("\u2013");
1425 case Minor.LQuote: {
1426 Console.Write("\u2018");
1430 case Minor.RQuote: {
1431 Console.Write("\u2019");
1435 case Minor.LDblQuote: {
1436 Console.Write("\u201C");
1440 case Minor.RDblQuote: {
1441 Console.Write("\u201D");
1446 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1453 private void HandleText(RTF.RTF rtf) {
1454 if (rtf_skip_count > 0) {
1459 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1460 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1462 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1463 rtf_line.Append((char)rtf.Major);
1465 //rtf_line.Append((char)rtf.Major);
1466 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1471 private void FlushText(RTF.RTF rtf, bool newline) {
1475 length = rtf_line.Length;
1476 if (!newline && (length == 0)) {
1480 if (rtf_rtffont == null) {
1481 // First font in table is default
1482 rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0);
1485 font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1487 if (rtf_color == null) {
1488 System.Windows.Forms.RTF.Color color;
1490 // First color in table is default
1491 color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0);
1493 if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
1494 rtf_color = new SolidBrush(ForeColor);
1496 rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1501 rtf_chars += rtf_line.Length;
1503 if (rtf_cursor_x == 0) {
1504 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color, LineEnding.Wrap);
1505 if (rtf_par_line_left_indent != 0) {
1506 Line line = document.GetLine (rtf_cursor_y);
1507 line.indent = rtf_par_line_left_indent;
1512 line = document.GetLine(rtf_cursor_y);
1513 line.indent = rtf_par_line_left_indent;
1514 if (rtf_line.Length > 0) {
1515 document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1516 document.FormatText(line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, font, rtf_color, null, FormatSpecified.Font | FormatSpecified.Color); // FormatText is 1-based
1519 document.Split(line, rtf_cursor_x + length);
1527 rtf_cursor_x += length;
1529 rtf_line.Length = 0; // Empty line
1532 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1537 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
1540 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) {
1543 rtf = new RTF.RTF(data);
1546 rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1547 rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1551 rtf_line = new StringBuilder();
1553 rtf_rtffont_size = (int)this.Font.Size;
1554 rtf_rtfalign = HorizontalAlignment.Left;
1555 rtf_rtfstyle = FontStyle.Regular;
1557 rtf_cursor_x = cursor_x;
1558 rtf_cursor_y = cursor_y;
1560 rtf.DefaultFont(this.Font.Name);
1562 rtf_text_map = new RTF.TextMap();
1563 RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1565 document.SuspendRecalc ();
1568 rtf.Read(); // That's it
1569 FlushText(rtf, false);
1574 catch (RTF.RTFException e) {
1578 // Seems to be plain text or broken RTF
1579 Console.WriteLine("RTF Parsing failure: {0}", e.Message);
1582 to_x = rtf_cursor_x;
1583 to_y = rtf_cursor_y;
1586 document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
1587 document.ResumeRecalc (true);
1589 document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1592 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1596 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1600 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1605 if (p.X >= document.ViewPortWidth) {
1606 p.X = document.ViewPortWidth - 1;
1607 } else if (p.X < 0) {
1611 if (p.Y >= document.ViewPortHeight) {
1612 p.Y = document.ViewPortHeight - 1;
1613 } else if (p.Y < 0) {
1617 tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1620 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1621 if (prev_index != font_index) {
1622 rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry
1625 if ((prev_font == null) || (prev_font.Size != font.Size)) {
1626 rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size
1629 if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1633 if (prev_font != null) {
1639 if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1643 if (prev_font != null) {
1649 if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1650 if (font.Strikeout) {
1651 rtf.Append("\\strike");
1653 if (prev_font != null) {
1654 rtf.Append("\\strike0");
1659 if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1660 if (font.Underline) {
1663 if (prev_font != null) {
1664 rtf.Append("\\ul0");
1670 [MonoTODO("Emit unicode and other special characters properly")]
1671 private void EmitRTFText(StringBuilder rtf, string text) {
1675 // start_pos and end_pos are 0-based
1676 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1690 sb = new StringBuilder();
1691 fonts = new ArrayList(10);
1692 colors = new ArrayList(10);
1694 // Two runs, first we parse to determine tables;
1695 // and unlike most of our processing here we work on tags
1698 line_no = start_line.line_no;
1701 // Add default font and color; to optimize document content we don't
1702 // use this.Font and this.ForeColor but the font/color from the first tag
1703 tag = LineTag.FindTag(start_line, pos);
1705 color = ((SolidBrush)tag.color).Color;
1706 fonts.Add(font.Name);
1709 while (line_no <= end_line.line_no) {
1710 line = document.GetLine(line_no);
1711 tag = LineTag.FindTag(line, pos);
1713 if (line_no != end_line.line_no) {
1714 line_len = line.text.Length;
1719 while (pos < line_len) {
1720 if (tag.font.Name != font.Name) {
1722 if (!fonts.Contains(font.Name)) {
1723 fonts.Add(font.Name);
1727 if (((SolidBrush)tag.color).Color != color) {
1728 color = ((SolidBrush)tag.color).Color;
1729 if (!colors.Contains(color)) {
1734 pos = tag.start + tag.length - 1;
1741 // We have the tables, emit the header
1742 sb.Append("{\\rtf1\\ansi");
1743 sb.Append("\\ansicpg1252"); // FIXME - is this correct?
1746 sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1749 sb.Append("\\deflang1033\n"); // FIXME - always 1033?
1751 // Emit the font table
1752 sb.Append("{\\fonttbl");
1753 for (i = 0; i < fonts.Count; i++) {
1754 sb.Append(String.Format("{{\\f{0}", i)); // {Font
1755 sb.Append("\\fnil"); // Family
1756 sb.Append("\\fcharset0 "); // Charset ANSI<space>
1757 sb.Append((string)fonts[i]); // Font name
1758 sb.Append(";}"); // }
1762 // Emit the color table (if needed)
1763 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))) {
1764 sb.Append("{\\colortbl "); // Header and NO! default color
1765 for (i = 0; i < colors.Count; i++) {
1766 sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1767 sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1768 sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1774 sb.Append("{\\*\\generator Mono RichTextBox;}");
1775 // Emit initial paragraph settings
1776 tag = LineTag.FindTag(start_line, start_pos);
1777 sb.Append("\\pard"); // Reset to default paragraph properties
1778 EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font); // Font properties
1779 sb.Append(" "); // Space separator
1782 color = (Color)colors[0];
1784 line_no = start_line.line_no;
1787 while (line_no <= end_line.line_no) {
1788 line = document.GetLine(line_no);
1789 tag = LineTag.FindTag(line, pos);
1791 if (line_no != end_line.line_no) {
1792 line_len = line.text.Length;
1797 while (pos < line_len) {
1800 if (tag.font != font) {
1801 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1805 if (((SolidBrush)tag.color).Color != color) {
1806 color = ((SolidBrush)tag.color).Color;
1807 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1809 if (length != sb.Length) {
1810 sb.Append(" "); // Emit space to separate keywords from text
1813 // Emit the string itself
1814 if (line_no != end_line.line_no) {
1815 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1817 if (end_pos < (tag.start + tag.length - 1)) {
1818 // Emit partial tag only, end_pos is inside this tag
1819 EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1821 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1825 pos = tag.start + tag.length - 1;
1828 if (pos >= line.text.Length) {
1829 if (line.ending != LineEnding.Wrap) {
1830 sb.Append("\\par\n");
1841 #endregion // Private Methods