1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
23 // Peter Bartok <pbartok@novell.com>
30 using System.Collections;
31 using System.ComponentModel;
35 using RTF=System.Windows.Forms.RTF;
37 namespace System.Windows.Forms {
38 public class RichTextBox : TextBoxBase {
39 #region Local Variables
40 internal bool auto_word_select;
41 internal int bullet_indent;
42 internal bool can_redo;
43 internal bool detect_urls;
44 internal string redo_action_name;
45 internal int margin_right;
46 internal string undo_action_name;
49 private RTF.TextMap rtf_text_map;
50 private int rtf_skip_width;
51 private int rtf_skip_count;
52 private StringBuilder rtf_line;
53 private SolidBrush rtf_color;
54 private RTF.Font rtf_rtffont;
55 private int rtf_rtffont_size;
56 private FontStyle rtf_rtfstyle;
57 private HorizontalAlignment rtf_rtfalign;
58 private int rtf_cursor_x;
59 private int rtf_cursor_y;
60 private int rtf_chars;
61 #endregion // Local Variables
63 #region Public Constructors
64 public RichTextBox() {
65 accepts_return = true;
66 auto_word_select = false;
70 max_length = Int32.MaxValue;
71 redo_action_name = string.Empty;
73 undo_action_name = string.Empty;
75 base.Multiline = true;
76 document.CRLFSize = 1;
78 scrollbars = RichTextBoxScrollBars.Both;
79 alignment = HorizontalAlignment.Left;
80 LostFocus += new EventHandler(RichTextBox_LostFocus);
81 GotFocus += new EventHandler(RichTextBox_GotFocus);
82 BackColor = ThemeEngine.Current.ColorWindow;
83 ForeColor = ThemeEngine.Current.ColorWindowText;
84 base.HScrolled += new EventHandler(RichTextBox_HScrolled);
85 base.VScrolled += new EventHandler(RichTextBox_VScrolled);
88 SetStyle (ControlStyles.StandardDoubleClick, false);
91 #endregion // Public Constructors
93 #region Private & Internal Methods
94 private void RichTextBox_LostFocus(object sender, EventArgs e) {
99 private void RichTextBox_GotFocus(object sender, EventArgs e) {
103 #endregion // Private & Internal Methods
105 #region Public Instance Properties
106 public override bool AllowDrop {
108 return base.AllowDrop;
112 base.AllowDrop = value;
116 [DefaultValue(false)]
118 public override bool AutoSize {
124 base.AutoSize = value;
128 [DefaultValue(false)]
129 public bool AutoWordSelection {
131 return auto_word_select;
135 auto_word_select = true;
140 [EditorBrowsable(EditorBrowsableState.Never)]
141 public override System.Drawing.Image BackgroundImage {
143 return background_image;
147 base.BackgroundImage = value;
153 public int BulletIndent {
155 return bullet_indent;
159 bullet_indent = value;
164 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
165 public bool CanRedo {
172 public bool DetectUrls {
182 public override Font Font {
193 if (PreferredHeight != Height) {
194 Height = PreferredHeight;
200 // Font changes always set the whole doc to that font
201 start = document.GetLine(1);
202 end = document.GetLine(document.Lines);
203 document.FormatText(start, 1, end, end.text.Length + 1, base.Font, new SolidBrush(this.ForeColor));
208 public override Color ForeColor {
210 return base.ForeColor;
214 base.ForeColor = value;
218 [DefaultValue(Int32.MaxValue)]
219 public override int MaxLength {
221 return base.max_length;
225 base.max_length = value;
230 public override bool Multiline {
236 base.Multiline = value;
241 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
243 public string RedoActionName {
245 return redo_action_name;
251 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
252 public int RightMargin {
258 margin_right = value;
264 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
270 start_line = document.GetLine(1);
271 end_line = document.GetLine(document.Lines);
272 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
279 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
281 InsertRTFFromStream(data, 0, 1);
289 [DefaultValue(RichTextBoxScrollBars.Both)]
291 public RichTextBoxScrollBars ScrollBars {
303 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
304 public string SelectedRtf {
306 return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
318 if (document.selection_visible) {
319 document.ReplaceSelection("", false);
322 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
324 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
325 InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y, out chars);
328 document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
329 document.SetSelection(line, sel_start);
330 document.PositionCaret(line, sel_start);
331 document.DisplayCaret();
333 OnTextChanged(EventArgs.Empty);
339 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
340 public override string SelectedText {
342 return base.SelectedText;
346 base.SelectedText = value;
351 [DefaultValue(HorizontalAlignment.Left)]
352 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
353 public HorizontalAlignment SelectionAlignment {
355 HorizontalAlignment align;
360 start = document.ParagraphStart(document.selection_start.line);
361 align = start.alignment;
363 end = document.ParagraphEnd(document.selection_end.line);
368 if (line.alignment != align) {
369 return HorizontalAlignment.Left;
375 line = document.GetLine(line.line_no + 1);
386 start = document.ParagraphStart(document.selection_start.line);
388 end = document.ParagraphEnd(document.selection_end.line);
393 line.alignment = value;
398 line = document.GetLine(line.line_no + 1);
400 this.CalculateDocument();
405 [DefaultValue(false)]
406 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
408 public bool SelectionBullet {
419 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
421 public int SelectionCharOffset {
431 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
432 public Color SelectionColor {
439 start = document.selection_start.tag;
440 end = document.selection_end.tag;
441 color = ((SolidBrush)document.selection_start.tag.color).Color;
445 if (!color.Equals(((SolidBrush)tag.color).Color)) {
453 tag = document.NextTag(tag);
464 FontDefinition attributes;
468 attributes = new FontDefinition();
469 attributes.color = value;
471 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
472 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
474 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
476 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
477 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
479 document.UpdateView(document.selection_start.line, 0);
480 document.AlignCaret();
485 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
486 public Font SelectionFont {
493 start = document.selection_start.tag;
494 end = document.selection_end.tag;
495 font = document.selection_start.tag.font;
499 if (!font.Equals(tag.font)) {
507 tag = document.NextTag(tag);
518 FontDefinition attributes;
522 attributes = new FontDefinition();
523 attributes.font_obj = value;
525 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
526 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
528 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
530 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
531 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
533 document.UpdateView(document.selection_start.line, 0);
534 document.AlignCaret();
541 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
543 public int SelectionHangingIndent {
554 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
556 public int SelectionIndent {
566 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
567 public override int SelectionLength {
569 return base.SelectionLength;
573 base.SelectionLength = value;
578 [DefaultValue(false)]
579 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
581 public bool SelectionProtected {
592 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
594 public int SelectionRightIndent {
604 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
606 public int[] SelectionTabs {
616 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
617 public RichTextBoxSelectionTypes SelectionType {
619 if (document.selection_start == document.selection_end) {
620 return RichTextBoxSelectionTypes.Empty;
624 if (SelectedText.Length > 1) {
625 return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
628 return RichTextBoxSelectionTypes.Text;
632 [DefaultValue(false)]
634 public bool ShowSelectionMargin {
644 public override string Text {
655 public override int TextLength {
657 return base.TextLength;
662 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
663 public string UndoActionName {
665 return document.undo.UndoName;
671 public float ZoomFactor {
680 #endregion // Public Instance Properties
682 #region Protected Instance Properties
683 protected override CreateParams CreateParams {
685 return base.CreateParams;
689 protected override Size DefaultSize {
691 return new Size(100, 96);
694 #endregion // Protected Instance Properties
696 #region Public Instance Methods
697 public bool CanPaste(DataFormats.Format clipFormat) {
698 if ((clipFormat.Name == DataFormats.Rtf) ||
699 (clipFormat.Name == DataFormats.Text) ||
700 (clipFormat.Name == DataFormats.UnicodeText)) {
706 public int Find(char[] characterSet) {
707 return Find(characterSet, -1, -1);
710 public int Find(char[] characterSet, int start) {
711 return Find(characterSet, start, -1);
714 public int Find(char[] characterSet, int start, int end) {
715 Document.Marker start_mark;
716 Document.Marker end_mark;
717 Document.Marker result;
720 document.GetMarker(out start_mark, true);
726 start_mark = new Document.Marker();
728 document.CharIndexToLineTag(start, out line, out tag, out pos);
729 start_mark.line = line;
730 start_mark.tag = tag;
731 start_mark.pos = pos;
735 document.GetMarker(out end_mark, false);
741 end_mark = new Document.Marker();
743 document.CharIndexToLineTag(end, out line, out tag, out pos);
744 end_mark.line = line;
749 if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
750 return document.LineTagToCharIndex(result.line, result.pos);
756 public int Find(string str) {
757 return Find(str, -1, -1, RichTextBoxFinds.None);
760 public int Find(string str, int start, int end, RichTextBoxFinds options) {
761 Document.Marker start_mark;
762 Document.Marker end_mark;
763 Document.Marker result;
766 document.GetMarker(out start_mark, true);
772 start_mark = new Document.Marker();
774 document.CharIndexToLineTag(start, out line, out tag, out pos);
776 start_mark.line = line;
777 start_mark.tag = tag;
778 start_mark.pos = pos;
782 document.GetMarker(out end_mark, false);
788 end_mark = new Document.Marker();
790 document.CharIndexToLineTag(end, out line, out tag, out pos);
792 end_mark.line = line;
797 if (document.Find(str, start_mark, end_mark, out result, options)) {
798 return document.LineTagToCharIndex(result.line, result.pos);
804 public int Find(string str, int start, RichTextBoxFinds options) {
805 return Find(str, start, -1, options);
808 public int Find(string str, RichTextBoxFinds options) {
809 return Find(str, -1, -1, options);
812 public char GetCharFromPosition(Point pt) {
816 PointToTagPos(pt, out tag, out pos);
818 if (pos >= tag.line.text.Length) {
822 return tag.line.text[pos];
826 public int GetCharIndexFromPosition(Point pt) {
830 PointToTagPos(pt, out tag, out pos);
832 return document.LineTagToCharIndex(tag.line, pos);
835 public int GetLineFromCharIndex(int index) {
840 document.CharIndexToLineTag(index, out line, out tag, out pos);
842 return line.LineNo - 1;
845 public Point GetPositionFromCharIndex(int index) {
850 document.CharIndexToLineTag(index, out line, out tag, out pos);
852 return new Point((int)line.widths[pos] + 1, line.Y + 1);
855 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
858 // FIXME - ignoring unicode
859 if (fileType == RichTextBoxStreamType.PlainText) {
865 sb = new StringBuilder((int)data.Length);
866 buffer = new byte[1024];
870 throw new IOException("Not enough memory to load document");
874 while (count < data.Length) {
875 count += data.Read(buffer, count, 1024);
878 base.Text = sb.ToString();
882 InsertRTFFromStream(data, 0, 1);
885 [MonoTODO("Make smarter RTF detection?")]
886 public void LoadFile(string path) {
887 if (path.EndsWith(".rtf")) {
888 LoadFile(path, RichTextBoxStreamType.RichText);
890 LoadFile(path, RichTextBoxStreamType.PlainText);
894 public void LoadFile(string path, RichTextBoxStreamType fileType) {
900 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
901 LoadFile(data, fileType);
905 throw new IOException("Could not open file " + path);
915 public void Paste(DataFormats.Format clipFormat) {
916 base.Paste(Clipboard.GetDataObject(), clipFormat, false);
923 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
929 if (fileType == RichTextBoxStreamType.UnicodePlainText) {
930 encoding = Encoding.Unicode;
932 encoding = Encoding.ASCII;
936 case RichTextBoxStreamType.PlainText:
937 case RichTextBoxStreamType.TextTextOleObjs:
938 case RichTextBoxStreamType.UnicodePlainText: {
940 bytes = encoding.GetBytes(document.Root.text.ToString());
941 data.Write(bytes, 0, bytes.Length);
945 for (i = 1; i < document.Lines; i++) {
946 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
947 data.Write(bytes, 0, bytes.Length);
949 bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
950 data.Write(bytes, 0, bytes.Length);
955 // If we're here we're saving RTF
962 start_line = document.GetLine(1);
963 end_line = document.GetLine(document.Lines);
964 rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
966 bytes = new Byte[4096];
968 // Let's chunk it so we don't use up all memory...
969 for (i = 0; i < total; i += 1024) {
970 if ((i + 1024) < total) {
971 current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
974 current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
976 data.Write(bytes, 0, current);
980 public void SaveFile(string path) {
981 if (path.EndsWith(".rtf")) {
982 SaveFile(path, RichTextBoxStreamType.RichText);
984 SaveFile(path, RichTextBoxStreamType.PlainText);
988 public void SaveFile(string path, RichTextBoxStreamType fileType) {
994 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
995 SaveFile(data, fileType);
999 // throw new IOException("Could not write document to file " + path);
1009 #endregion // Public Instance Methods
1011 #region Protected Instance Methods
1012 protected virtual object CreateRichEditOleCallback() {
1013 throw new NotImplementedException();
1016 protected override void OnBackColorChanged(EventArgs e) {
1017 base.OnBackColorChanged (e);
1020 protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
1021 if (ContentsResized != null) {
1022 ContentsResized(this, e);
1026 protected override void OnContextMenuChanged(EventArgs e) {
1027 base.OnContextMenuChanged (e);
1030 protected override void OnHandleCreated(EventArgs e) {
1031 base.OnHandleCreated (e);
1034 protected override void OnHandleDestroyed(EventArgs e) {
1035 base.OnHandleDestroyed (e);
1038 protected virtual void OnHScroll(EventArgs e) {
1039 if (HScroll != null) {
1044 [MonoTODO("Determine when to call this")]
1045 protected virtual void OnImeChange(EventArgs e) {
1046 if (ImeChange != null) {
1051 protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
1052 if (LinkClicked != null) {
1053 LinkClicked(this, e);
1057 protected virtual void OnProtected(EventArgs e) {
1058 if (Protected != null) {
1063 protected override void OnRightToLeftChanged(EventArgs e) {
1064 base.OnRightToLeftChanged (e);
1067 protected virtual void OnSelectionChanged(EventArgs e) {
1068 if (SelectionChanged != null) {
1069 SelectionChanged(this, e);
1073 protected override void OnSystemColorsChanged(EventArgs e) {
1074 base.OnSystemColorsChanged (e);
1077 protected override void OnTextChanged(EventArgs e) {
1078 base.OnTextChanged (e);
1081 protected virtual void OnVScroll(EventArgs e) {
1082 if (VScroll != null) {
1087 protected override void WndProc(ref Message m) {
1088 base.WndProc (ref m);
1090 #endregion // Protected Instance Methods
1094 [EditorBrowsable(EditorBrowsableState.Never)]
1095 public event EventHandler BackgroundImageChanged;
1097 public event ContentsResizedEventHandler ContentsResized;
1100 [EditorBrowsable(EditorBrowsableState.Never)]
1101 public event EventHandler DoubleClick;
1104 [EditorBrowsable(EditorBrowsableState.Never)]
1105 public event DragEventHandler DragDrop {
1107 base.DragDrop += value;
1111 base.DragDrop -= value;
1116 [EditorBrowsable(EditorBrowsableState.Never)]
1117 public event DragEventHandler DragEnter {
1119 base.DragEnter += value;
1123 base.DragEnter -= value;
1128 [EditorBrowsable(EditorBrowsableState.Never)]
1129 public event EventHandler DragLeave {
1131 base.DragLeave += value;
1135 base.DragLeave -= value;
1141 [EditorBrowsable(EditorBrowsableState.Never)]
1142 public event DragEventHandler DragOver {
1144 base.DragOver += value;
1148 base.DragOver -= value;
1154 [EditorBrowsable(EditorBrowsableState.Never)]
1155 public event GiveFeedbackEventHandler GiveFeedback;
1157 public event EventHandler HScroll;
1158 public event EventHandler ImeChange;
1159 public event LinkClickedEventHandler LinkClicked;
1160 public event EventHandler Protected;
1163 [EditorBrowsable(EditorBrowsableState.Never)]
1164 public event QueryContinueDragEventHandler QueryContinueDrag;
1165 public event EventHandler SelectionChanged;
1166 public event EventHandler VScroll;
1167 #endregion // Events
1169 #region Private Methods
1171 internal override void SelectWord ()
1173 document.ExpandSelection(CaretSelection.Word, false);
1176 private void HandleControl(RTF.RTF rtf) {
1177 // Console.WriteLine ("HANDLING MAJOR: {0} MINOR: {1}", rtf.Major, rtf.Minor);
1179 case RTF.Major.Unicode: {
1181 case Minor.UnicodeCharBytes: {
1182 rtf_skip_width = rtf.Param;
1186 case Minor.UnicodeChar: {
1187 rtf_skip_count += rtf_skip_width;
1188 rtf_line.Append((char)rtf.Param);
1195 case RTF.Major.Destination: {
1196 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1201 case RTF.Major.CharAttr: {
1203 case Minor.ForeColor: {
1204 System.Windows.Forms.RTF.Color color;
1206 color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
1207 if (color != null) {
1208 FlushText(rtf, false);
1209 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
1210 this.rtf_color = new SolidBrush(ForeColor);
1212 this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1218 case Minor.FontSize: {
1219 FlushText(rtf, false);
1220 this.rtf_rtffont_size = rtf.Param / 2;
1224 case Minor.FontNum: {
1225 System.Windows.Forms.RTF.Font font;
1227 font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
1229 FlushText(rtf, false);
1230 this.rtf_rtffont = font;
1236 FlushText(rtf, false);
1237 rtf_rtfstyle = FontStyle.Regular;
1242 FlushText(rtf, false);
1243 if (rtf.Param == RTF.RTF.NoParam) {
1244 rtf_rtfstyle |= FontStyle.Bold;
1246 rtf_rtfstyle &= ~FontStyle.Bold;
1251 case Minor.Italic: {
1252 FlushText(rtf, false);
1253 if (rtf.Param == RTF.RTF.NoParam) {
1254 rtf_rtfstyle |= FontStyle.Italic;
1256 rtf_rtfstyle &= ~FontStyle.Italic;
1261 case Minor.StrikeThru: {
1262 FlushText(rtf, false);
1263 if (rtf.Param == RTF.RTF.NoParam) {
1264 rtf_rtfstyle |= FontStyle.Strikeout;
1266 rtf_rtfstyle &= ~FontStyle.Strikeout;
1271 case Minor.Underline: {
1272 FlushText(rtf, false);
1273 if (rtf.Param == RTF.RTF.NoParam) {
1274 rtf_rtfstyle |= FontStyle.Underline;
1276 rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline;
1281 case Minor.NoUnderline: {
1282 FlushText(rtf, false);
1283 rtf_rtfstyle &= ~FontStyle.Underline;
1290 case RTF.Major.SpecialChar: {
1291 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1298 private void SpecialChar(RTF.RTF rtf) {
1305 FlushText(rtf, true);
1314 case Minor.NoBrkSpace: {
1320 rtf_line.Append ("\t");
1321 // FlushText (rtf, false);
1325 case Minor.NoReqHyphen:
1326 case Minor.NoBrkHyphen: {
1327 rtf_line.Append ("-");
1328 // FlushText (rtf, false);
1332 case Minor.Bullet: {
1333 Console.WriteLine("*");
1337 case Minor.WidowCtrl:
1340 case Minor.EmDash: {
1341 rtf_line.Append ("\u2014");
1345 case Minor.EnDash: {
1346 rtf_line.Append ("\u2013");
1350 case Minor.LQuote: {
1351 Console.Write("\u2018");
1355 case Minor.RQuote: {
1356 Console.Write("\u2019");
1360 case Minor.LDblQuote: {
1361 Console.Write("\u201C");
1365 case Minor.RDblQuote: {
1366 Console.Write("\u201D");
1371 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1378 private void HandleText(RTF.RTF rtf) {
1379 if (rtf_skip_count > 0) {
1384 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1385 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1387 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1388 rtf_line.Append((char)rtf.Major);
1390 //rtf_line.Append((char)rtf.Major);
1391 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1396 private void FlushText(RTF.RTF rtf, bool newline) {
1400 length = rtf_line.Length;
1401 if (!newline && (length == 0)) {
1405 if (rtf_rtffont == null) {
1406 // First font in table is default
1407 rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0);
1410 font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1412 if (rtf_color == null) {
1413 System.Windows.Forms.RTF.Color color;
1415 // First color in table is default
1416 color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0);
1418 if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
1419 rtf_color = new SolidBrush(ForeColor);
1421 rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1425 rtf_chars += rtf_line.Length;
1427 if (rtf_cursor_x == 0) {
1428 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color);
1432 line = document.GetLine(rtf_cursor_y);
1433 if (rtf_line.Length > 0) {
1434 document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1435 document.FormatText(line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, font, rtf_color); // FormatText is 1-based
1438 document.Split(line, rtf_cursor_x + length);
1446 rtf_cursor_x += length;
1448 rtf_line.Length = 0; // Empty line
1451 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1456 InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
1459 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) {
1462 rtf = new RTF.RTF(data);
1465 rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1466 rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1470 rtf_line = new StringBuilder();
1472 rtf_rtffont_size = (int)this.Font.Size;
1473 rtf_rtfalign = HorizontalAlignment.Left;
1474 rtf_rtfstyle = FontStyle.Regular;
1476 rtf_cursor_x = cursor_x;
1477 rtf_cursor_y = cursor_y;
1479 rtf.DefaultFont(this.Font.Name);
1481 rtf_text_map = new RTF.TextMap();
1482 RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1484 document.NoRecalc = true;
1487 rtf.Read(); // That's it
1488 FlushText(rtf, false);
1491 catch (RTF.RTFException e) {
1492 // Seems to be plain text or broken RTF
1493 Console.WriteLine("RTF Parsing failure: {0}", e.Message);
1496 to_x = rtf_cursor_x;
1497 to_y = rtf_cursor_y;
1500 document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
1501 document.NoRecalc = false;
1503 document.Invalidate(document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1506 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1510 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1514 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1519 if (p.X >= document.ViewPortWidth) {
1520 p.X = document.ViewPortWidth - 1;
1521 } else if (p.X < 0) {
1525 if (p.Y >= document.ViewPortHeight) {
1526 p.Y = document.ViewPortHeight - 1;
1527 } else if (p.Y < 0) {
1531 tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1534 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1535 if (prev_index != font_index) {
1536 rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry
1539 if ((prev_font == null) || (prev_font.Size != font.Size)) {
1540 rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size
1543 if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1547 if (prev_font != null) {
1553 if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1557 if (prev_font != null) {
1563 if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1564 if (font.Strikeout) {
1565 rtf.Append("\\strike");
1567 if (prev_font != null) {
1568 rtf.Append("\\strike0");
1573 if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1574 if (font.Underline) {
1577 if (prev_font != null) {
1578 rtf.Append("\\ul0");
1584 [MonoTODO("Emit unicode and other special characters properly")]
1585 private void EmitRTFText(StringBuilder rtf, string text) {
1589 // start_pos and end_pos are 0-based
1590 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1604 sb = new StringBuilder();
1605 fonts = new ArrayList(10);
1606 colors = new ArrayList(10);
1608 // Two runs, first we parse to determine tables;
1609 // and unlike most of our processing here we work on tags
1612 line_no = start_line.line_no;
1615 // Add default font and color; to optimize document content we don't
1616 // use this.Font and this.ForeColor but the font/color from the first tag
1617 tag = LineTag.FindTag(start_line, pos);
1619 color = ((SolidBrush)tag.color).Color;
1620 fonts.Add(font.Name);
1623 while (line_no <= end_line.line_no) {
1624 line = document.GetLine(line_no);
1625 tag = LineTag.FindTag(line, pos);
1627 if (line_no != end_line.line_no) {
1628 line_len = line.text.Length;
1633 while (pos < line_len) {
1634 if (tag.font.Name != font.Name) {
1636 if (!fonts.Contains(font.Name)) {
1637 fonts.Add(font.Name);
1641 if (((SolidBrush)tag.color).Color != color) {
1642 color = ((SolidBrush)tag.color).Color;
1643 if (!colors.Contains(color)) {
1648 pos = tag.start + tag.length - 1;
1655 // We have the tables, emit the header
1656 sb.Append("{\\rtf1\\ansi");
1657 sb.Append("\\ansicpg1252"); // FIXME - is this correct?
1660 sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1663 sb.Append("\\deflang1033\n"); // FIXME - always 1033?
1665 // Emit the font table
1666 sb.Append("{\\fonttbl");
1667 for (i = 0; i < fonts.Count; i++) {
1668 sb.Append(String.Format("{{\\f{0}", i)); // {Font
1669 sb.Append("\\fnil"); // Family
1670 sb.Append("\\fcharset0 "); // Charset ANSI<space>
1671 sb.Append((string)fonts[i]); // Font name
1672 sb.Append(";}"); // }
1676 // Emit the color table (if needed)
1677 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))) {
1678 sb.Append("{\\colortbl "); // Header and NO! default color
1679 for (i = 0; i < colors.Count; i++) {
1680 sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1681 sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1682 sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1688 sb.Append("{\\*\\generator Mono RichTextBox;}");
1689 // Emit initial paragraph settings
1690 tag = LineTag.FindTag(start_line, start_pos);
1691 sb.Append("\\pard"); // Reset to default paragraph properties
1692 EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font); // Font properties
1693 sb.Append(" "); // Space separator
1696 color = (Color)colors[0];
1698 line_no = start_line.line_no;
1701 while (line_no <= end_line.line_no) {
1702 line = document.GetLine(line_no);
1703 tag = LineTag.FindTag(line, pos);
1705 if (line_no != end_line.line_no) {
1706 line_len = line.text.Length;
1711 while (pos < line_len) {
1714 if (tag.font != font) {
1715 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1719 if (((SolidBrush)tag.color).Color != color) {
1720 color = ((SolidBrush)tag.color).Color;
1721 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1723 if (length != sb.Length) {
1724 sb.Append(" "); // Emit space to separate keywords from text
1727 // Emit the string itself
1728 if (line_no != end_line.line_no) {
1729 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1731 if (end_pos < (tag.start + tag.length - 1)) {
1732 // Emit partial tag only, end_pos is inside this tag
1733 EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1735 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1739 pos = tag.start + tag.length - 1;
1742 if (pos >= line.text.Length) {
1743 if (!line.soft_break) {
1744 sb.Append("\\par\n");
1755 #endregion // Private Methods