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 #endregion // Local Variables
66 #region Public Constructors
67 public RichTextBox() {
68 accepts_return = true;
69 auto_word_select = false;
72 max_length = Int32.MaxValue;
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
107 public override bool AllowDrop {
109 return base.AllowDrop;
113 base.AllowDrop = value;
117 [DefaultValue(false)]
119 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
120 [RefreshProperties (RefreshProperties.Repaint)]
121 [EditorBrowsable (EditorBrowsableState.Never)]
126 public override bool AutoSize {
132 base.AutoSize = value;
136 [DefaultValue(false)]
137 public bool AutoWordSelection {
139 return auto_word_select;
143 auto_word_select = true;
148 [EditorBrowsable(EditorBrowsableState.Never)]
149 public override System.Drawing.Image BackgroundImage {
150 get { return base.BackgroundImage; }
151 set { base.BackgroundImage = value; }
156 public int BulletIndent {
158 return bullet_indent;
162 bullet_indent = value;
167 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
168 public bool CanRedo {
170 return document.undo.CanRedo;
175 public bool DetectUrls {
185 public override Font Font {
196 if (PreferredHeight != Height) {
197 Height = PreferredHeight;
203 // Font changes always set the whole doc to that font
204 start = document.GetLine(1);
205 end = document.GetLine(document.Lines);
206 document.FormatText(start, 1, end, end.text.Length + 1, base.Font, null, null, FormatSpecified.Font);
211 public override Color ForeColor {
213 return base.ForeColor;
217 base.ForeColor = value;
221 [DefaultValue(Int32.MaxValue)]
222 public override int MaxLength {
224 return base.max_length;
228 base.max_length = value;
233 public override bool Multiline {
239 base.Multiline = value;
244 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
246 public string RedoActionName {
248 return document.undo.RedoActionName;
254 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
255 public int RightMargin {
261 margin_right = value;
266 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
268 [RefreshProperties (RefreshProperties.All)]
277 start_line = document.GetLine(1);
278 end_line = document.GetLine(document.Lines);
279 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
286 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
288 InsertRTFFromStream(data, 0, 1);
296 [DefaultValue(RichTextBoxScrollBars.Both)]
298 public RichTextBoxScrollBars ScrollBars {
310 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
311 public string SelectedRtf {
313 return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
325 if (document.selection_visible) {
326 document.ReplaceSelection("", false);
329 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
331 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
332 InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y, out chars);
335 document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
336 document.SetSelection(line, sel_start);
337 document.PositionCaret(line, sel_start);
338 document.DisplayCaret();
340 OnTextChanged(EventArgs.Empty);
346 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
347 public override string SelectedText {
349 return base.SelectedText;
353 base.SelectedText = value;
358 [DefaultValue(HorizontalAlignment.Left)]
359 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
360 public HorizontalAlignment SelectionAlignment {
362 HorizontalAlignment align;
367 start = document.ParagraphStart(document.selection_start.line);
368 align = start.alignment;
370 end = document.ParagraphEnd(document.selection_end.line);
375 if (line.alignment != align) {
376 return HorizontalAlignment.Left;
382 line = document.GetLine(line.line_no + 1);
393 start = document.ParagraphStart(document.selection_start.line);
395 end = document.ParagraphEnd(document.selection_end.line);
400 line.alignment = value;
405 line = document.GetLine(line.line_no + 1);
407 this.CalculateDocument();
412 [DefaultValue(false)]
413 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
415 public bool SelectionBullet {
426 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
428 public int SelectionCharOffset {
438 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
439 public Color SelectionColor {
446 start = document.selection_start.tag;
447 end = document.selection_end.tag;
448 color = ((SolidBrush)document.selection_start.tag.color).Color;
452 if (!color.Equals(((SolidBrush)tag.color).Color)) {
460 tag = document.NextTag(tag);
471 FontDefinition attributes;
475 attributes = new FontDefinition();
476 attributes.color = value;
478 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
479 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
481 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
483 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
484 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
486 document.UpdateView(document.selection_start.line, 0);
487 document.AlignCaret();
492 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
493 public Font SelectionFont {
500 start = document.selection_start.tag;
501 end = document.selection_end.tag;
502 font = document.selection_start.tag.font;
506 if (!font.Equals(tag.font)) {
514 tag = document.NextTag(tag);
525 FontDefinition attributes;
529 attributes = new FontDefinition();
530 attributes.font_obj = value;
532 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
533 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
535 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
537 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
538 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
540 document.UpdateView(document.selection_start.line, 0);
541 document.AlignCaret();
548 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
550 public int SelectionHangingIndent {
561 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
563 public int SelectionIndent {
573 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
574 public override int SelectionLength {
576 return base.SelectionLength;
580 base.SelectionLength = value;
585 [DefaultValue(false)]
586 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
588 public bool SelectionProtected {
599 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
601 public int SelectionRightIndent {
611 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
613 public int[] SelectionTabs {
623 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
624 public RichTextBoxSelectionTypes SelectionType {
626 if (document.selection_start == document.selection_end) {
627 return RichTextBoxSelectionTypes.Empty;
631 if (SelectedText.Length > 1) {
632 return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
635 return RichTextBoxSelectionTypes.Text;
639 [DefaultValue(false)]
641 public bool ShowSelectionMargin {
652 [RefreshProperties (RefreshProperties.All)]
654 public override string Text {
665 public override int TextLength {
667 return base.TextLength;
672 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
673 public string UndoActionName {
675 return document.undo.UndoActionName;
681 public float ZoomFactor {
690 #endregion // Public Instance Properties
692 #region Protected Instance Properties
693 protected override CreateParams CreateParams {
695 return base.CreateParams;
699 protected override Size DefaultSize {
701 return new Size(100, 96);
704 #endregion // Protected Instance Properties
706 #region Public Instance Methods
707 public bool CanPaste(DataFormats.Format clipFormat) {
708 if ((clipFormat.Name == DataFormats.Rtf) ||
709 (clipFormat.Name == DataFormats.Text) ||
710 (clipFormat.Name == DataFormats.UnicodeText)) {
716 public int Find(char[] characterSet) {
717 return Find(characterSet, -1, -1);
720 public int Find(char[] characterSet, int start) {
721 return Find(characterSet, start, -1);
724 public int Find(char[] characterSet, int start, int end) {
725 Document.Marker start_mark;
726 Document.Marker end_mark;
727 Document.Marker result;
730 document.GetMarker(out start_mark, true);
736 start_mark = new Document.Marker();
738 document.CharIndexToLineTag(start, out line, out tag, out pos);
739 start_mark.line = line;
740 start_mark.tag = tag;
741 start_mark.pos = pos;
745 document.GetMarker(out end_mark, false);
751 end_mark = new Document.Marker();
753 document.CharIndexToLineTag(end, out line, out tag, out pos);
754 end_mark.line = line;
759 if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
760 return document.LineTagToCharIndex(result.line, result.pos);
766 public int Find(string str) {
767 return Find(str, -1, -1, RichTextBoxFinds.None);
770 public int Find(string str, int start, int end, RichTextBoxFinds options) {
771 Document.Marker start_mark;
772 Document.Marker end_mark;
773 Document.Marker result;
776 document.GetMarker(out start_mark, true);
782 start_mark = new Document.Marker();
784 document.CharIndexToLineTag(start, out line, out tag, out pos);
786 start_mark.line = line;
787 start_mark.tag = tag;
788 start_mark.pos = pos;
792 document.GetMarker(out end_mark, false);
798 end_mark = new Document.Marker();
800 document.CharIndexToLineTag(end, out line, out tag, out pos);
802 end_mark.line = line;
807 if (document.Find(str, start_mark, end_mark, out result, options)) {
808 return document.LineTagToCharIndex(result.line, result.pos);
814 public int Find(string str, int start, RichTextBoxFinds options) {
815 return Find(str, start, -1, options);
818 public int Find(string str, RichTextBoxFinds options) {
819 return Find(str, -1, -1, options);
822 public char GetCharFromPosition(Point pt) {
826 PointToTagPos(pt, out tag, out pos);
828 if (pos >= tag.line.text.Length) {
832 return tag.line.text[pos];
836 public int GetCharIndexFromPosition(Point pt) {
840 PointToTagPos(pt, out tag, out pos);
842 return document.LineTagToCharIndex(tag.line, pos);
845 public int GetLineFromCharIndex(int index) {
850 document.CharIndexToLineTag(index, out line, out tag, out pos);
852 return line.LineNo - 1;
855 public Point GetPositionFromCharIndex(int index) {
860 document.CharIndexToLineTag(index, out line, out tag, out pos);
862 return new Point((int)line.widths[pos] + 1, line.Y + 1);
865 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
868 // FIXME - ignoring unicode
869 if (fileType == RichTextBoxStreamType.PlainText) {
875 sb = new StringBuilder((int)data.Length);
876 buffer = new byte[1024];
878 throw new IOException("Not enough memory to load document");
882 while (count < data.Length) {
883 count += data.Read(buffer, count, 1024);
886 base.Text = sb.ToString();
890 InsertRTFFromStream(data, 0, 1);
892 document.PositionCaret (document.GetLine (1), 0);
893 document.SetSelectionToCaret (true);
897 [MonoTODO("Make smarter RTF detection?")]
898 public void LoadFile(string path) {
899 if (path.EndsWith(".rtf")) {
900 LoadFile(path, RichTextBoxStreamType.RichText);
902 LoadFile(path, RichTextBoxStreamType.PlainText);
906 public void LoadFile(string path, RichTextBoxStreamType fileType) {
913 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
915 LoadFile(data, fileType);
919 throw new IOException("Could not open file " + path);
929 public void Paste(DataFormats.Format clipFormat) {
930 base.Paste(Clipboard.GetDataObject(), clipFormat, false);
935 document.undo.Redo ();
938 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
944 if (fileType == RichTextBoxStreamType.UnicodePlainText) {
945 encoding = Encoding.Unicode;
947 encoding = Encoding.ASCII;
951 case RichTextBoxStreamType.PlainText:
952 case RichTextBoxStreamType.TextTextOleObjs:
953 case RichTextBoxStreamType.UnicodePlainText: {
955 bytes = encoding.GetBytes(document.Root.text.ToString());
956 data.Write(bytes, 0, bytes.Length);
960 for (i = 1; i < document.Lines; i++) {
961 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
962 data.Write(bytes, 0, bytes.Length);
964 bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
965 data.Write(bytes, 0, bytes.Length);
970 // If we're here we're saving RTF
977 start_line = document.GetLine(1);
978 end_line = document.GetLine(document.Lines);
979 rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
981 bytes = new Byte[4096];
983 // Let's chunk it so we don't use up all memory...
984 for (i = 0; i < total; i += 1024) {
985 if ((i + 1024) < total) {
986 current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
989 current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
991 data.Write(bytes, 0, current);
995 public void SaveFile(string path) {
996 if (path.EndsWith(".rtf")) {
997 SaveFile(path, RichTextBoxStreamType.RichText);
999 SaveFile(path, RichTextBoxStreamType.PlainText);
1003 public void SaveFile(string path, RichTextBoxStreamType fileType) {
1009 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
1010 SaveFile(data, fileType);
1014 // throw new IOException("Could not write document to file " + path);
1024 #endregion // Public Instance Methods
1026 #region Protected Instance Methods
1027 protected virtual object CreateRichEditOleCallback() {
1028 throw new NotImplementedException();
1031 protected override void OnBackColorChanged(EventArgs e) {
1032 base.OnBackColorChanged (e);
1035 protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
1036 ContentsResizedEventHandler eh = (ContentsResizedEventHandler)(Events [ContentsResizedEvent]);
1041 protected override void OnContextMenuChanged(EventArgs e) {
1042 base.OnContextMenuChanged (e);
1045 protected override void OnHandleCreated(EventArgs e) {
1046 base.OnHandleCreated (e);
1049 protected override void OnHandleDestroyed(EventArgs e) {
1050 base.OnHandleDestroyed (e);
1053 protected virtual void OnHScroll(EventArgs e) {
1054 EventHandler eh = (EventHandler)(Events [HScrollEvent]);
1059 [MonoTODO("Determine when to call this")]
1060 protected virtual void OnImeChange(EventArgs e) {
1061 EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
1066 protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
1067 LinkClickedEventHandler eh = (LinkClickedEventHandler)(Events [LinkClickedEvent]);
1072 protected virtual void OnProtected(EventArgs e) {
1073 EventHandler eh = (EventHandler)(Events [ProtectedEvent]);
1078 protected override void OnRightToLeftChanged(EventArgs e) {
1079 base.OnRightToLeftChanged (e);
1082 protected virtual void OnSelectionChanged(EventArgs e) {
1083 EventHandler eh = (EventHandler)(Events [SelectionChangedEvent]);
1088 protected override void OnSystemColorsChanged(EventArgs e) {
1089 base.OnSystemColorsChanged (e);
1092 protected override void OnTextChanged(EventArgs e) {
1093 base.OnTextChanged (e);
1096 protected virtual void OnVScroll(EventArgs e) {
1097 EventHandler eh = (EventHandler)(Events [VScrollEvent]);
1102 protected override void WndProc(ref Message m) {
1103 base.WndProc (ref m);
1105 #endregion // Protected Instance Methods
1108 static object ContentsResizedEvent = new object ();
1109 static object HScrollEvent = new object ();
1110 static object ImeChangeEvent = new object ();
1111 static object LinkClickedEvent = new object ();
1112 static object ProtectedEvent = new object ();
1113 static object SelectionChangedEvent = new object ();
1114 static object VScrollEvent = new object ();
1117 [EditorBrowsable(EditorBrowsableState.Never)]
1118 public new event EventHandler BackgroundImageChanged {
1119 add { base.BackgroundImageChanged += value; }
1120 remove { base.BackgroundImageChanged -= value; }
1123 public event ContentsResizedEventHandler ContentsResized {
1124 add { Events.AddHandler (ContentsResizedEvent, value); }
1125 remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1129 [EditorBrowsable(EditorBrowsableState.Never)]
1130 public new event EventHandler DoubleClick {
1131 add { base.DoubleClick += value; }
1132 remove { base.DoubleClick -= value; }
1137 [EditorBrowsable(EditorBrowsableState.Never)]
1139 public new event DragEventHandler DragDrop {
1140 add { base.DragDrop += value; }
1141 remove { base.DragDrop -= value; }
1146 [EditorBrowsable(EditorBrowsableState.Never)]
1148 public new event DragEventHandler DragEnter {
1149 add { base.DragEnter += value; }
1150 remove { base.DragEnter -= value; }
1154 [EditorBrowsable(EditorBrowsableState.Never)]
1155 public new event EventHandler DragLeave {
1156 add { base.DragLeave += value; }
1157 remove { base.DragLeave -= value; }
1162 [EditorBrowsable(EditorBrowsableState.Never)]
1163 public new event DragEventHandler DragOver {
1164 add { base.DragOver += value; }
1165 remove { base.DragOver -= value; }
1170 [EditorBrowsable(EditorBrowsableState.Never)]
1171 public new event GiveFeedbackEventHandler GiveFeedback {
1172 add { base.GiveFeedback += value; }
1173 remove { base.GiveFeedback -= value; }
1176 public event EventHandler HScroll {
1177 add { Events.AddHandler (HScrollEvent, value); }
1178 remove { Events.RemoveHandler (HScrollEvent, value); }
1181 public event EventHandler ImeChange {
1182 add { Events.AddHandler (ImeChangeEvent, value); }
1183 remove { Events.RemoveHandler (ImeChangeEvent, value); }
1186 public event LinkClickedEventHandler LinkClicked {
1187 add { Events.AddHandler (LinkClickedEvent, value); }
1188 remove { Events.RemoveHandler (LinkClickedEvent, value); }
1191 public event EventHandler Protected {
1192 add { Events.AddHandler (ProtectedEvent, value); }
1193 remove { Events.RemoveHandler (ProtectedEvent, value); }
1197 [EditorBrowsable(EditorBrowsableState.Never)]
1198 public new event QueryContinueDragEventHandler QueryContinueDrag {
1199 add { base.QueryContinueDrag += value; }
1200 remove { base.QueryContinueDrag -= value; }
1203 public event EventHandler SelectionChanged {
1204 add { Events.AddHandler (SelectionChangedEvent, value); }
1205 remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1208 public event EventHandler VScroll {
1209 add { Events.AddHandler (VScrollEvent, value); }
1210 remove { Events.RemoveHandler (VScrollEvent, value); }
1212 #endregion // Events
1214 #region Private Methods
1216 internal override void SelectWord ()
1218 document.ExpandSelection(CaretSelection.Word, false);
1221 private void HandleControl(RTF.RTF rtf) {
1222 // Console.WriteLine ("HANDLING MAJOR: {0} MINOR: {1}", rtf.Major, rtf.Minor);
1224 case RTF.Major.Unicode: {
1226 case Minor.UnicodeCharBytes: {
1227 rtf_skip_width = rtf.Param;
1231 case Minor.UnicodeChar: {
1232 rtf_skip_count += rtf_skip_width;
1233 rtf_line.Append((char)rtf.Param);
1240 case RTF.Major.Destination: {
1241 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1246 case RTF.Major.CharAttr: {
1248 case Minor.ForeColor: {
1249 System.Windows.Forms.RTF.Color color;
1251 color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
1253 if (color != null) {
1254 FlushText(rtf, false);
1255 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
1256 this.rtf_color = new SolidBrush(ForeColor);
1258 this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1260 FlushText (rtf, false);
1265 case Minor.FontSize: {
1266 FlushText(rtf, false);
1267 this.rtf_rtffont_size = rtf.Param / 2;
1271 case Minor.FontNum: {
1272 System.Windows.Forms.RTF.Font font;
1274 font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
1276 FlushText(rtf, false);
1277 this.rtf_rtffont = font;
1283 FlushText(rtf, false);
1284 rtf_rtfstyle = FontStyle.Regular;
1289 FlushText(rtf, false);
1290 if (rtf.Param == RTF.RTF.NoParam) {
1291 rtf_rtfstyle |= FontStyle.Bold;
1293 rtf_rtfstyle &= ~FontStyle.Bold;
1298 case Minor.Italic: {
1299 FlushText(rtf, false);
1300 if (rtf.Param == RTF.RTF.NoParam) {
1301 rtf_rtfstyle |= FontStyle.Italic;
1303 rtf_rtfstyle &= ~FontStyle.Italic;
1308 case Minor.StrikeThru: {
1309 FlushText(rtf, false);
1310 if (rtf.Param == RTF.RTF.NoParam) {
1311 rtf_rtfstyle |= FontStyle.Strikeout;
1313 rtf_rtfstyle &= ~FontStyle.Strikeout;
1318 case Minor.Underline: {
1319 FlushText(rtf, false);
1320 if (rtf.Param == RTF.RTF.NoParam) {
1321 rtf_rtfstyle |= FontStyle.Underline;
1323 rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline;
1328 case Minor.NoUnderline: {
1329 FlushText(rtf, false);
1330 rtf_rtfstyle &= ~FontStyle.Underline;
1337 case RTF.Major.SpecialChar: {
1338 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1345 private void SpecialChar(RTF.RTF rtf) {
1352 FlushText(rtf, true);
1361 case Minor.NoBrkSpace: {
1367 rtf_line.Append ("\t");
1368 // FlushText (rtf, false);
1372 case Minor.NoReqHyphen:
1373 case Minor.NoBrkHyphen: {
1374 rtf_line.Append ("-");
1375 // FlushText (rtf, false);
1379 case Minor.Bullet: {
1380 Console.WriteLine("*");
1384 case Minor.WidowCtrl:
1387 case Minor.EmDash: {
1388 rtf_line.Append ("\u2014");
1392 case Minor.EnDash: {
1393 rtf_line.Append ("\u2013");
1397 case Minor.LQuote: {
1398 Console.Write("\u2018");
1402 case Minor.RQuote: {
1403 Console.Write("\u2019");
1407 case Minor.LDblQuote: {
1408 Console.Write("\u201C");
1412 case Minor.RDblQuote: {
1413 Console.Write("\u201D");
1418 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1425 private void HandleText(RTF.RTF rtf) {
1426 if (rtf_skip_count > 0) {
1431 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1432 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1434 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1435 rtf_line.Append((char)rtf.Major);
1437 //rtf_line.Append((char)rtf.Major);
1438 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1443 private void FlushText(RTF.RTF rtf, bool newline) {
1447 length = rtf_line.Length;
1448 if (!newline && (length == 0)) {
1452 if (rtf_rtffont == null) {
1453 // First font in table is default
1454 rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0);
1457 font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1459 if (rtf_color == null) {
1460 System.Windows.Forms.RTF.Color color;
1462 // First color in table is default
1463 color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0);
1465 if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
1466 rtf_color = new SolidBrush(ForeColor);
1468 rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1473 rtf_chars += rtf_line.Length;
1475 if (rtf_cursor_x == 0) {
1476 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color);
1480 line = document.GetLine(rtf_cursor_y);
1481 if (rtf_line.Length > 0) {
1482 document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1483 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
1486 document.Split(line, rtf_cursor_x + length);
1494 rtf_cursor_x += length;
1496 rtf_line.Length = 0; // Empty line
1499 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1504 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
1507 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) {
1510 rtf = new RTF.RTF(data);
1513 rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1514 rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1518 rtf_line = new StringBuilder();
1520 rtf_rtffont_size = (int)this.Font.Size;
1521 rtf_rtfalign = HorizontalAlignment.Left;
1522 rtf_rtfstyle = FontStyle.Regular;
1524 rtf_cursor_x = cursor_x;
1525 rtf_cursor_y = cursor_y;
1527 rtf.DefaultFont(this.Font.Name);
1529 rtf_text_map = new RTF.TextMap();
1530 RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1532 document.SuspendRecalc ();
1535 rtf.Read(); // That's it
1536 FlushText(rtf, false);
1541 catch (RTF.RTFException e) {
1545 // Seems to be plain text or broken RTF
1546 Console.WriteLine("RTF Parsing failure: {0}", e.Message);
1549 to_x = rtf_cursor_x;
1550 to_y = rtf_cursor_y;
1553 document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
1554 document.ResumeRecalc (true);
1556 document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1559 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1563 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1567 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1572 if (p.X >= document.ViewPortWidth) {
1573 p.X = document.ViewPortWidth - 1;
1574 } else if (p.X < 0) {
1578 if (p.Y >= document.ViewPortHeight) {
1579 p.Y = document.ViewPortHeight - 1;
1580 } else if (p.Y < 0) {
1584 tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1587 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1588 if (prev_index != font_index) {
1589 rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry
1592 if ((prev_font == null) || (prev_font.Size != font.Size)) {
1593 rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size
1596 if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1600 if (prev_font != null) {
1606 if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1610 if (prev_font != null) {
1616 if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1617 if (font.Strikeout) {
1618 rtf.Append("\\strike");
1620 if (prev_font != null) {
1621 rtf.Append("\\strike0");
1626 if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1627 if (font.Underline) {
1630 if (prev_font != null) {
1631 rtf.Append("\\ul0");
1637 [MonoTODO("Emit unicode and other special characters properly")]
1638 private void EmitRTFText(StringBuilder rtf, string text) {
1642 // start_pos and end_pos are 0-based
1643 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1657 sb = new StringBuilder();
1658 fonts = new ArrayList(10);
1659 colors = new ArrayList(10);
1661 // Two runs, first we parse to determine tables;
1662 // and unlike most of our processing here we work on tags
1665 line_no = start_line.line_no;
1668 // Add default font and color; to optimize document content we don't
1669 // use this.Font and this.ForeColor but the font/color from the first tag
1670 tag = LineTag.FindTag(start_line, pos);
1672 color = ((SolidBrush)tag.color).Color;
1673 fonts.Add(font.Name);
1676 while (line_no <= end_line.line_no) {
1677 line = document.GetLine(line_no);
1678 tag = LineTag.FindTag(line, pos);
1680 if (line_no != end_line.line_no) {
1681 line_len = line.text.Length;
1686 while (pos < line_len) {
1687 if (tag.font.Name != font.Name) {
1689 if (!fonts.Contains(font.Name)) {
1690 fonts.Add(font.Name);
1694 if (((SolidBrush)tag.color).Color != color) {
1695 color = ((SolidBrush)tag.color).Color;
1696 if (!colors.Contains(color)) {
1701 pos = tag.start + tag.length - 1;
1708 // We have the tables, emit the header
1709 sb.Append("{\\rtf1\\ansi");
1710 sb.Append("\\ansicpg1252"); // FIXME - is this correct?
1713 sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1716 sb.Append("\\deflang1033\n"); // FIXME - always 1033?
1718 // Emit the font table
1719 sb.Append("{\\fonttbl");
1720 for (i = 0; i < fonts.Count; i++) {
1721 sb.Append(String.Format("{{\\f{0}", i)); // {Font
1722 sb.Append("\\fnil"); // Family
1723 sb.Append("\\fcharset0 "); // Charset ANSI<space>
1724 sb.Append((string)fonts[i]); // Font name
1725 sb.Append(";}"); // }
1729 // Emit the color table (if needed)
1730 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))) {
1731 sb.Append("{\\colortbl "); // Header and NO! default color
1732 for (i = 0; i < colors.Count; i++) {
1733 sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1734 sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1735 sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1741 sb.Append("{\\*\\generator Mono RichTextBox;}");
1742 // Emit initial paragraph settings
1743 tag = LineTag.FindTag(start_line, start_pos);
1744 sb.Append("\\pard"); // Reset to default paragraph properties
1745 EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font); // Font properties
1746 sb.Append(" "); // Space separator
1749 color = (Color)colors[0];
1751 line_no = start_line.line_no;
1754 while (line_no <= end_line.line_no) {
1755 line = document.GetLine(line_no);
1756 tag = LineTag.FindTag(line, pos);
1758 if (line_no != end_line.line_no) {
1759 line_len = line.text.Length;
1764 while (pos < line_len) {
1767 if (tag.font != font) {
1768 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1772 if (((SolidBrush)tag.color).Color != color) {
1773 color = ((SolidBrush)tag.color).Color;
1774 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1776 if (length != sb.Length) {
1777 sb.Append(" "); // Emit space to separate keywords from text
1780 // Emit the string itself
1781 if (line_no != end_line.line_no) {
1782 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1784 if (end_pos < (tag.start + tag.length - 1)) {
1785 // Emit partial tag only, end_pos is inside this tag
1786 EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1788 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1792 pos = tag.start + tag.length - 1;
1795 if (pos >= line.text.Length) {
1796 if (!line.soft_break) {
1797 sb.Append("\\par\n");
1808 #endregion // Private Methods