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 System.Runtime.InteropServices;
36 using RTF=System.Windows.Forms.RTF;
38 namespace System.Windows.Forms {
40 [ClassInterface (ClassInterfaceType.AutoDispatch)]
41 [Docking (DockingBehavior.Ask)]
44 public class RichTextBox : TextBoxBase {
45 #region Local Variables
46 internal bool auto_word_select;
47 internal int bullet_indent;
48 internal bool detect_urls;
49 internal int margin_right;
52 private RTF.TextMap rtf_text_map;
53 private int rtf_skip_width;
54 private int rtf_skip_count;
55 private StringBuilder rtf_line;
56 private SolidBrush rtf_color;
57 private RTF.Font rtf_rtffont;
58 private int rtf_rtffont_size;
59 private FontStyle rtf_rtfstyle;
60 private HorizontalAlignment rtf_rtfalign;
61 private int rtf_cursor_x;
62 private int rtf_cursor_y;
63 private int rtf_chars;
64 private int rtf_par_line_left_indent;
65 #endregion // Local Variables
67 #region Public Constructors
68 public RichTextBox() {
69 accepts_return = true;
70 auto_word_select = false;
73 max_length = Int32.MaxValue;
76 base.Multiline = true;
77 document.CRLFSize = 1;
79 scrollbars = RichTextBoxScrollBars.Both;
80 alignment = HorizontalAlignment.Left;
81 LostFocus += new EventHandler(RichTextBox_LostFocus);
82 GotFocus += new EventHandler(RichTextBox_GotFocus);
83 BackColor = ThemeEngine.Current.ColorWindow;
84 ForeColor = ThemeEngine.Current.ColorWindowText;
85 base.HScrolled += new EventHandler(RichTextBox_HScrolled);
86 base.VScrolled += new EventHandler(RichTextBox_VScrolled);
89 SetStyle (ControlStyles.StandardDoubleClick, false);
92 #endregion // Public Constructors
94 #region Private & Internal Methods
95 private void RichTextBox_LostFocus(object sender, EventArgs e) {
99 private void RichTextBox_GotFocus(object sender, EventArgs e) {
102 #endregion // Private & Internal Methods
104 #region Public Instance Properties
108 public override bool AllowDrop {
110 return base.AllowDrop;
114 base.AllowDrop = value;
118 [DefaultValue(false)]
120 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
121 [RefreshProperties (RefreshProperties.Repaint)]
122 [EditorBrowsable (EditorBrowsableState.Never)]
127 public override bool AutoSize {
133 base.AutoSize = value;
137 [DefaultValue(false)]
138 public bool AutoWordSelection {
140 return auto_word_select;
144 auto_word_select = true;
149 [EditorBrowsable(EditorBrowsableState.Never)]
150 public override System.Drawing.Image BackgroundImage {
151 get { return base.BackgroundImage; }
152 set { base.BackgroundImage = value; }
157 public int BulletIndent {
159 return bullet_indent;
163 bullet_indent = value;
168 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
169 public bool CanRedo {
171 return document.undo.CanRedo;
176 public bool DetectUrls {
186 public override Font Font {
197 if (PreferredHeight != Height) {
198 Height = PreferredHeight;
204 // Font changes always set the whole doc to that font
205 start = document.GetLine(1);
206 end = document.GetLine(document.Lines);
207 document.FormatText(start, 1, end, end.text.Length + 1, base.Font, null, null, FormatSpecified.Font);
212 public override Color ForeColor {
214 return base.ForeColor;
218 base.ForeColor = value;
222 [DefaultValue(Int32.MaxValue)]
223 public override int MaxLength {
225 return base.max_length;
229 base.max_length = value;
234 public override bool Multiline {
236 return base.Multiline;
240 base.Multiline = value;
245 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
247 public string RedoActionName {
249 return document.undo.RedoActionName;
255 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
256 public int RightMargin {
262 margin_right = value;
267 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
269 [RefreshProperties (RefreshProperties.All)]
278 start_line = document.GetLine(1);
279 end_line = document.GetLine(document.Lines);
280 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
287 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
289 InsertRTFFromStream(data, 0, 1);
297 [DefaultValue(RichTextBoxScrollBars.Both)]
299 public RichTextBoxScrollBars ScrollBars {
311 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
312 public string SelectedRtf {
314 return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
326 if (document.selection_visible) {
327 document.ReplaceSelection("", false);
330 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
332 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
333 InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y, out chars);
336 document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
337 document.SetSelection(line, sel_start);
338 document.PositionCaret(line, sel_start);
339 document.DisplayCaret();
341 OnTextChanged(EventArgs.Empty);
347 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
348 public override string SelectedText {
350 return base.SelectedText;
354 base.SelectedText = value;
359 [DefaultValue(HorizontalAlignment.Left)]
360 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
361 public HorizontalAlignment SelectionAlignment {
363 HorizontalAlignment align;
368 start = document.ParagraphStart(document.selection_start.line);
369 align = start.alignment;
371 end = document.ParagraphEnd(document.selection_end.line);
376 if (line.alignment != align) {
377 return HorizontalAlignment.Left;
383 line = document.GetLine(line.line_no + 1);
394 start = document.ParagraphStart(document.selection_start.line);
396 end = document.ParagraphEnd(document.selection_end.line);
401 line.alignment = value;
406 line = document.GetLine(line.line_no + 1);
408 this.CalculateDocument();
413 [DefaultValue(false)]
414 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
416 public bool SelectionBullet {
427 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
429 public int SelectionCharOffset {
439 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
440 public Color SelectionColor {
447 start = document.selection_start.tag;
448 end = document.selection_end.tag;
449 color = ((SolidBrush)document.selection_start.tag.color).Color;
453 if (!color.Equals(((SolidBrush)tag.color).Color)) {
461 tag = document.NextTag(tag);
472 FontDefinition attributes;
476 attributes = new FontDefinition();
477 attributes.color = value;
479 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
480 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
482 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
484 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
485 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
487 document.UpdateView(document.selection_start.line, 0);
488 document.AlignCaret();
493 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
494 public Font SelectionFont {
501 start = document.selection_start.tag;
502 end = document.selection_end.tag;
503 font = document.selection_start.tag.font;
507 if (!font.Equals(tag.font)) {
515 tag = document.NextTag(tag);
526 FontDefinition attributes;
530 attributes = new FontDefinition();
531 attributes.font_obj = value;
533 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
534 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
536 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
538 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
539 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
541 document.UpdateView(document.selection_start.line, 0);
542 document.AlignCaret();
549 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
551 public int SelectionHangingIndent {
562 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
564 public int SelectionIndent {
574 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
575 public override int SelectionLength {
577 return base.SelectionLength;
581 base.SelectionLength = value;
586 [DefaultValue(false)]
587 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
589 public bool SelectionProtected {
600 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
602 public int SelectionRightIndent {
612 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
614 public int[] SelectionTabs {
624 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
625 public RichTextBoxSelectionTypes SelectionType {
627 if (document.selection_start == document.selection_end) {
628 return RichTextBoxSelectionTypes.Empty;
632 if (SelectedText.Length > 1) {
633 return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
636 return RichTextBoxSelectionTypes.Text;
640 [DefaultValue(false)]
642 public bool ShowSelectionMargin {
653 [RefreshProperties (RefreshProperties.All)]
655 public override string Text {
666 public override int TextLength {
668 return base.TextLength;
673 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
674 public string UndoActionName {
676 return document.undo.UndoActionName;
682 public float ZoomFactor {
691 #endregion // Public Instance Properties
693 #region Protected Instance Properties
694 protected override CreateParams CreateParams {
696 return base.CreateParams;
700 protected override Size DefaultSize {
702 return new Size(100, 96);
705 #endregion // Protected Instance Properties
707 #region Public Instance Methods
708 public bool CanPaste(DataFormats.Format clipFormat) {
709 if ((clipFormat.Name == DataFormats.Rtf) ||
710 (clipFormat.Name == DataFormats.Text) ||
711 (clipFormat.Name == DataFormats.UnicodeText)) {
717 public int Find(char[] characterSet) {
718 return Find(characterSet, -1, -1);
721 public int Find(char[] characterSet, int start) {
722 return Find(characterSet, start, -1);
725 public int Find(char[] characterSet, int start, int end) {
726 Document.Marker start_mark;
727 Document.Marker end_mark;
728 Document.Marker result;
731 document.GetMarker(out start_mark, true);
737 start_mark = new Document.Marker();
739 document.CharIndexToLineTag(start, out line, out tag, out pos);
740 start_mark.line = line;
741 start_mark.tag = tag;
742 start_mark.pos = pos;
746 document.GetMarker(out end_mark, false);
752 end_mark = new Document.Marker();
754 document.CharIndexToLineTag(end, out line, out tag, out pos);
755 end_mark.line = line;
760 if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
761 return document.LineTagToCharIndex(result.line, result.pos);
767 public int Find(string str) {
768 return Find(str, -1, -1, RichTextBoxFinds.None);
771 public int Find(string str, int start, int end, RichTextBoxFinds options) {
772 Document.Marker start_mark;
773 Document.Marker end_mark;
774 Document.Marker result;
777 document.GetMarker(out start_mark, true);
783 start_mark = new Document.Marker();
785 document.CharIndexToLineTag(start, out line, out tag, out pos);
787 start_mark.line = line;
788 start_mark.tag = tag;
789 start_mark.pos = pos;
793 document.GetMarker(out end_mark, false);
799 end_mark = new Document.Marker();
801 document.CharIndexToLineTag(end, out line, out tag, out pos);
803 end_mark.line = line;
808 if (document.Find(str, start_mark, end_mark, out result, options)) {
809 return document.LineTagToCharIndex(result.line, result.pos);
815 public int Find(string str, int start, RichTextBoxFinds options) {
816 return Find(str, start, -1, options);
819 public int Find(string str, RichTextBoxFinds options) {
820 return Find(str, -1, -1, options);
823 public char GetCharFromPosition(Point pt) {
827 PointToTagPos(pt, out tag, out pos);
829 if (pos >= tag.line.text.Length) {
833 return tag.line.text[pos];
837 public int GetCharIndexFromPosition(Point pt) {
841 PointToTagPos(pt, out tag, out pos);
843 return document.LineTagToCharIndex(tag.line, pos);
846 public int GetLineFromCharIndex(int index) {
851 document.CharIndexToLineTag(index, out line, out tag, out pos);
853 return line.LineNo - 1;
856 public Point GetPositionFromCharIndex(int index) {
861 document.CharIndexToLineTag(index, out line, out tag, out pos);
863 return new Point((int)line.widths[pos] + 1, line.Y + 1);
866 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
870 // FIXME - ignoring unicode
871 if (fileType == RichTextBoxStreamType.PlainText) {
877 sb = new StringBuilder((int)data.Length);
878 buffer = new byte[1024];
880 throw new IOException("Not enough memory to load document");
884 while (count < data.Length) {
885 count += data.Read(buffer, count, 1024);
888 base.Text = sb.ToString();
892 InsertRTFFromStream(data, 0, 1);
894 document.PositionCaret (document.GetLine (1), 0);
895 document.SetSelectionToCaret (true);
899 [MonoTODO("Make smarter RTF detection?")]
900 public void LoadFile(string path) {
901 if (path.EndsWith(".rtf")) {
902 LoadFile(path, RichTextBoxStreamType.RichText);
904 LoadFile(path, RichTextBoxStreamType.PlainText);
908 public void LoadFile(string path, RichTextBoxStreamType fileType) {
915 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
917 LoadFile(data, fileType);
921 throw new IOException("Could not open file " + path);
931 public void Paste(DataFormats.Format clipFormat) {
932 base.Paste(Clipboard.GetDataObject(), clipFormat, false);
937 document.undo.Redo ();
940 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
946 if (fileType == RichTextBoxStreamType.UnicodePlainText) {
947 encoding = Encoding.Unicode;
949 encoding = Encoding.ASCII;
953 case RichTextBoxStreamType.PlainText:
954 case RichTextBoxStreamType.TextTextOleObjs:
955 case RichTextBoxStreamType.UnicodePlainText: {
957 bytes = encoding.GetBytes(document.Root.text.ToString());
958 data.Write(bytes, 0, bytes.Length);
962 for (i = 1; i < document.Lines; i++) {
963 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
964 data.Write(bytes, 0, bytes.Length);
966 bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
967 data.Write(bytes, 0, bytes.Length);
972 // If we're here we're saving RTF
979 start_line = document.GetLine(1);
980 end_line = document.GetLine(document.Lines);
981 rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
983 bytes = new Byte[4096];
985 // Let's chunk it so we don't use up all memory...
986 for (i = 0; i < total; i += 1024) {
987 if ((i + 1024) < total) {
988 current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
991 current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
993 data.Write(bytes, 0, current);
997 public void SaveFile(string path) {
998 if (path.EndsWith(".rtf")) {
999 SaveFile(path, RichTextBoxStreamType.RichText);
1001 SaveFile(path, RichTextBoxStreamType.PlainText);
1005 public void SaveFile(string path, RichTextBoxStreamType fileType) {
1011 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
1012 SaveFile(data, fileType);
1016 // throw new IOException("Could not write document to file " + path);
1026 #endregion // Public Instance Methods
1028 #region Protected Instance Methods
1029 protected virtual object CreateRichEditOleCallback() {
1030 throw new NotImplementedException();
1033 protected override void OnBackColorChanged(EventArgs e) {
1034 base.OnBackColorChanged (e);
1037 protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
1038 ContentsResizedEventHandler eh = (ContentsResizedEventHandler)(Events [ContentsResizedEvent]);
1043 protected override void OnContextMenuChanged(EventArgs e) {
1044 base.OnContextMenuChanged (e);
1047 protected override void OnHandleCreated(EventArgs e) {
1048 base.OnHandleCreated (e);
1051 protected override void OnHandleDestroyed(EventArgs e) {
1052 base.OnHandleDestroyed (e);
1055 protected virtual void OnHScroll(EventArgs e) {
1056 EventHandler eh = (EventHandler)(Events [HScrollEvent]);
1061 [MonoTODO("Determine when to call this")]
1062 protected virtual void OnImeChange(EventArgs e) {
1063 EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
1068 protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
1069 LinkClickedEventHandler eh = (LinkClickedEventHandler)(Events [LinkClickedEvent]);
1074 protected virtual void OnProtected(EventArgs e) {
1075 EventHandler eh = (EventHandler)(Events [ProtectedEvent]);
1080 protected override void OnRightToLeftChanged(EventArgs e) {
1081 base.OnRightToLeftChanged (e);
1084 protected virtual void OnSelectionChanged(EventArgs e) {
1085 EventHandler eh = (EventHandler)(Events [SelectionChangedEvent]);
1090 protected override void OnSystemColorsChanged(EventArgs e) {
1091 base.OnSystemColorsChanged (e);
1094 protected override void OnTextChanged(EventArgs e) {
1095 base.OnTextChanged (e);
1098 protected virtual void OnVScroll(EventArgs e) {
1099 EventHandler eh = (EventHandler)(Events [VScrollEvent]);
1104 protected override void WndProc(ref Message m) {
1105 base.WndProc (ref m);
1107 #endregion // Protected Instance Methods
1110 static object ContentsResizedEvent = new object ();
1111 static object HScrollEvent = new object ();
1112 static object ImeChangeEvent = new object ();
1113 static object LinkClickedEvent = new object ();
1114 static object ProtectedEvent = new object ();
1115 static object SelectionChangedEvent = new object ();
1116 static object VScrollEvent = new object ();
1119 [EditorBrowsable(EditorBrowsableState.Never)]
1120 public new event EventHandler BackgroundImageChanged {
1121 add { base.BackgroundImageChanged += value; }
1122 remove { base.BackgroundImageChanged -= value; }
1125 public event ContentsResizedEventHandler ContentsResized {
1126 add { Events.AddHandler (ContentsResizedEvent, value); }
1127 remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1131 [EditorBrowsable(EditorBrowsableState.Never)]
1132 public new event EventHandler DoubleClick {
1133 add { base.DoubleClick += value; }
1134 remove { base.DoubleClick -= value; }
1139 [EditorBrowsable(EditorBrowsableState.Never)]
1141 public new event DragEventHandler DragDrop {
1142 add { base.DragDrop += value; }
1143 remove { base.DragDrop -= value; }
1148 [EditorBrowsable(EditorBrowsableState.Never)]
1150 public new event DragEventHandler DragEnter {
1151 add { base.DragEnter += value; }
1152 remove { base.DragEnter -= value; }
1156 [EditorBrowsable(EditorBrowsableState.Never)]
1157 public new event EventHandler DragLeave {
1158 add { base.DragLeave += value; }
1159 remove { base.DragLeave -= value; }
1164 [EditorBrowsable(EditorBrowsableState.Never)]
1165 public new event DragEventHandler DragOver {
1166 add { base.DragOver += value; }
1167 remove { base.DragOver -= value; }
1172 [EditorBrowsable(EditorBrowsableState.Never)]
1173 public new event GiveFeedbackEventHandler GiveFeedback {
1174 add { base.GiveFeedback += value; }
1175 remove { base.GiveFeedback -= value; }
1178 public event EventHandler HScroll {
1179 add { Events.AddHandler (HScrollEvent, value); }
1180 remove { Events.RemoveHandler (HScrollEvent, value); }
1183 public event EventHandler ImeChange {
1184 add { Events.AddHandler (ImeChangeEvent, value); }
1185 remove { Events.RemoveHandler (ImeChangeEvent, value); }
1188 public event LinkClickedEventHandler LinkClicked {
1189 add { Events.AddHandler (LinkClickedEvent, value); }
1190 remove { Events.RemoveHandler (LinkClickedEvent, value); }
1193 public event EventHandler Protected {
1194 add { Events.AddHandler (ProtectedEvent, value); }
1195 remove { Events.RemoveHandler (ProtectedEvent, value); }
1199 [EditorBrowsable(EditorBrowsableState.Never)]
1200 public new event QueryContinueDragEventHandler QueryContinueDrag {
1201 add { base.QueryContinueDrag += value; }
1202 remove { base.QueryContinueDrag -= value; }
1205 public event EventHandler SelectionChanged {
1206 add { Events.AddHandler (SelectionChangedEvent, value); }
1207 remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1210 public event EventHandler VScroll {
1211 add { Events.AddHandler (VScrollEvent, value); }
1212 remove { Events.RemoveHandler (VScrollEvent, value); }
1214 #endregion // Events
1216 #region Private Methods
1218 internal override void SelectWord ()
1220 document.ExpandSelection(CaretSelection.Word, false);
1223 private void HandleControl(RTF.RTF rtf) {
1225 case RTF.Major.Unicode: {
1227 case Minor.UnicodeCharBytes: {
1228 rtf_skip_width = rtf.Param;
1232 case Minor.UnicodeChar: {
1233 rtf_skip_count += rtf_skip_width;
1234 rtf_line.Append((char)rtf.Param);
1241 case RTF.Major.Destination: {
1242 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1247 case RTF.Major.PictAttr:
1248 switch (rtf.Minor) {
1250 FlushText (rtf, false);
1252 Image img = new Bitmap (new MemoryStream (rtf.Image));
1254 Line line = document.GetLine (rtf_cursor_y);
1255 document.InsertImage (line, 0, img);
1258 FlushText (rtf, true);
1260 } catch (Exception e) {
1261 Console.Error.WriteLine ("EXCEPTION while loading image: {0}", e);
1267 case RTF.Major.CharAttr: {
1269 case Minor.ForeColor: {
1270 System.Windows.Forms.RTF.Color color;
1272 color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
1274 if (color != null) {
1275 FlushText(rtf, false);
1276 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
1277 this.rtf_color = new SolidBrush(ForeColor);
1279 this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1281 FlushText (rtf, false);
1286 case Minor.FontSize: {
1287 FlushText(rtf, false);
1288 this.rtf_rtffont_size = rtf.Param / 2;
1292 case Minor.FontNum: {
1293 System.Windows.Forms.RTF.Font font;
1295 font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
1297 FlushText(rtf, false);
1298 this.rtf_rtffont = font;
1304 FlushText(rtf, false);
1305 rtf_rtfstyle = FontStyle.Regular;
1310 FlushText(rtf, false);
1311 if (rtf.Param == RTF.RTF.NoParam) {
1312 rtf_rtfstyle |= FontStyle.Bold;
1314 rtf_rtfstyle &= ~FontStyle.Bold;
1319 case Minor.Italic: {
1320 FlushText(rtf, false);
1321 if (rtf.Param == RTF.RTF.NoParam) {
1322 rtf_rtfstyle |= FontStyle.Italic;
1324 rtf_rtfstyle &= ~FontStyle.Italic;
1329 case Minor.StrikeThru: {
1330 FlushText(rtf, false);
1331 if (rtf.Param == RTF.RTF.NoParam) {
1332 rtf_rtfstyle |= FontStyle.Strikeout;
1334 rtf_rtfstyle &= ~FontStyle.Strikeout;
1339 case Minor.Underline: {
1340 FlushText(rtf, false);
1341 if (rtf.Param == RTF.RTF.NoParam) {
1342 rtf_rtfstyle |= FontStyle.Underline;
1344 rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline;
1349 case Minor.NoUnderline: {
1350 FlushText(rtf, false);
1351 rtf_rtfstyle &= ~FontStyle.Underline;
1358 case RTF.Major.ParAttr: {
1359 switch (rtf.Minor) {
1360 case Minor.LeftIndent:
1361 rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * CreateGraphics ().DpiX + 0.5F);
1367 case RTF.Major.SpecialChar: {
1368 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1375 private void SpecialChar(RTF.RTF rtf) {
1382 FlushText(rtf, true);
1391 case Minor.NoBrkSpace: {
1397 rtf_line.Append ("\t");
1398 // FlushText (rtf, false);
1402 case Minor.NoReqHyphen:
1403 case Minor.NoBrkHyphen: {
1404 rtf_line.Append ("-");
1405 // FlushText (rtf, false);
1409 case Minor.Bullet: {
1410 Console.WriteLine("*");
1414 case Minor.WidowCtrl:
1417 case Minor.EmDash: {
1418 rtf_line.Append ("\u2014");
1422 case Minor.EnDash: {
1423 rtf_line.Append ("\u2013");
1427 case Minor.LQuote: {
1428 Console.Write("\u2018");
1432 case Minor.RQuote: {
1433 Console.Write("\u2019");
1437 case Minor.LDblQuote: {
1438 Console.Write("\u201C");
1442 case Minor.RDblQuote: {
1443 Console.Write("\u201D");
1448 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1455 private void HandleText(RTF.RTF rtf) {
1456 if (rtf_skip_count > 0) {
1461 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1462 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1464 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1465 rtf_line.Append((char)rtf.Major);
1467 //rtf_line.Append((char)rtf.Major);
1468 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1473 private void FlushText(RTF.RTF rtf, bool newline) {
1477 length = rtf_line.Length;
1478 if (!newline && (length == 0)) {
1482 if (rtf_rtffont == null) {
1483 // First font in table is default
1484 rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0);
1487 font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1489 if (rtf_color == null) {
1490 System.Windows.Forms.RTF.Color color;
1492 // First color in table is default
1493 color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0);
1495 if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
1496 rtf_color = new SolidBrush(ForeColor);
1498 rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1503 rtf_chars += rtf_line.Length;
1505 if (rtf_cursor_x == 0) {
1506 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color);
1507 if (rtf_par_line_left_indent != 0) {
1508 Line line = document.GetLine (rtf_cursor_y);
1509 line.indent = rtf_par_line_left_indent;
1514 line = document.GetLine(rtf_cursor_y);
1515 line.indent = rtf_par_line_left_indent;
1516 if (rtf_line.Length > 0) {
1517 document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1518 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
1521 document.Split(line, rtf_cursor_x + length);
1529 rtf_cursor_x += length;
1531 rtf_line.Length = 0; // Empty line
1534 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1539 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
1542 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) {
1545 rtf = new RTF.RTF(data);
1548 rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1549 rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1553 rtf_line = new StringBuilder();
1555 rtf_rtffont_size = (int)this.Font.Size;
1556 rtf_rtfalign = HorizontalAlignment.Left;
1557 rtf_rtfstyle = FontStyle.Regular;
1559 rtf_cursor_x = cursor_x;
1560 rtf_cursor_y = cursor_y;
1562 rtf.DefaultFont(this.Font.Name);
1564 rtf_text_map = new RTF.TextMap();
1565 RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1567 document.SuspendRecalc ();
1570 rtf.Read(); // That's it
1571 FlushText(rtf, false);
1576 catch (RTF.RTFException e) {
1580 // Seems to be plain text or broken RTF
1581 Console.WriteLine("RTF Parsing failure: {0}", e.Message);
1584 to_x = rtf_cursor_x;
1585 to_y = rtf_cursor_y;
1588 document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
1589 document.ResumeRecalc (true);
1591 document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1594 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1598 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1602 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1607 if (p.X >= document.ViewPortWidth) {
1608 p.X = document.ViewPortWidth - 1;
1609 } else if (p.X < 0) {
1613 if (p.Y >= document.ViewPortHeight) {
1614 p.Y = document.ViewPortHeight - 1;
1615 } else if (p.Y < 0) {
1619 tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1622 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1623 if (prev_index != font_index) {
1624 rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry
1627 if ((prev_font == null) || (prev_font.Size != font.Size)) {
1628 rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size
1631 if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1635 if (prev_font != null) {
1641 if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1645 if (prev_font != null) {
1651 if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1652 if (font.Strikeout) {
1653 rtf.Append("\\strike");
1655 if (prev_font != null) {
1656 rtf.Append("\\strike0");
1661 if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1662 if (font.Underline) {
1665 if (prev_font != null) {
1666 rtf.Append("\\ul0");
1672 [MonoTODO("Emit unicode and other special characters properly")]
1673 private void EmitRTFText(StringBuilder rtf, string text) {
1677 // start_pos and end_pos are 0-based
1678 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1692 sb = new StringBuilder();
1693 fonts = new ArrayList(10);
1694 colors = new ArrayList(10);
1696 // Two runs, first we parse to determine tables;
1697 // and unlike most of our processing here we work on tags
1700 line_no = start_line.line_no;
1703 // Add default font and color; to optimize document content we don't
1704 // use this.Font and this.ForeColor but the font/color from the first tag
1705 tag = LineTag.FindTag(start_line, pos);
1707 color = ((SolidBrush)tag.color).Color;
1708 fonts.Add(font.Name);
1711 while (line_no <= end_line.line_no) {
1712 line = document.GetLine(line_no);
1713 tag = LineTag.FindTag(line, pos);
1715 if (line_no != end_line.line_no) {
1716 line_len = line.text.Length;
1721 while (pos < line_len) {
1722 if (tag.font.Name != font.Name) {
1724 if (!fonts.Contains(font.Name)) {
1725 fonts.Add(font.Name);
1729 if (((SolidBrush)tag.color).Color != color) {
1730 color = ((SolidBrush)tag.color).Color;
1731 if (!colors.Contains(color)) {
1736 pos = tag.start + tag.length - 1;
1743 // We have the tables, emit the header
1744 sb.Append("{\\rtf1\\ansi");
1745 sb.Append("\\ansicpg1252"); // FIXME - is this correct?
1748 sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1751 sb.Append("\\deflang1033\n"); // FIXME - always 1033?
1753 // Emit the font table
1754 sb.Append("{\\fonttbl");
1755 for (i = 0; i < fonts.Count; i++) {
1756 sb.Append(String.Format("{{\\f{0}", i)); // {Font
1757 sb.Append("\\fnil"); // Family
1758 sb.Append("\\fcharset0 "); // Charset ANSI<space>
1759 sb.Append((string)fonts[i]); // Font name
1760 sb.Append(";}"); // }
1764 // Emit the color table (if needed)
1765 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))) {
1766 sb.Append("{\\colortbl "); // Header and NO! default color
1767 for (i = 0; i < colors.Count; i++) {
1768 sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1769 sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1770 sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1776 sb.Append("{\\*\\generator Mono RichTextBox;}");
1777 // Emit initial paragraph settings
1778 tag = LineTag.FindTag(start_line, start_pos);
1779 sb.Append("\\pard"); // Reset to default paragraph properties
1780 EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font); // Font properties
1781 sb.Append(" "); // Space separator
1784 color = (Color)colors[0];
1786 line_no = start_line.line_no;
1789 while (line_no <= end_line.line_no) {
1790 line = document.GetLine(line_no);
1791 tag = LineTag.FindTag(line, pos);
1793 if (line_no != end_line.line_no) {
1794 line_len = line.text.Length;
1799 while (pos < line_len) {
1802 if (tag.font != font) {
1803 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1807 if (((SolidBrush)tag.color).Color != color) {
1808 color = ((SolidBrush)tag.color).Color;
1809 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1811 if (length != sb.Length) {
1812 sb.Append(" "); // Emit space to separate keywords from text
1815 // Emit the string itself
1816 if (line_no != end_line.line_no) {
1817 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1819 if (end_pos < (tag.start + tag.length - 1)) {
1820 // Emit partial tag only, end_pos is inside this tag
1821 EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1823 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1827 pos = tag.start + tag.length - 1;
1830 if (pos >= line.text.Length) {
1831 if (!line.soft_break) {
1832 sb.Append("\\par\n");
1843 #endregion // Private Methods