* RTF.cs: Use the documents encoding code page to decode unicode
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / RichTextBox.cs
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:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
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.
19 //
20 // Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    <pbartok@novell.com>
24 //
25 //
26
27 // #define DEBUG
28
29 using System;
30 using System.Collections;
31 using System.ComponentModel;
32 using System.Drawing;
33 using System.Drawing.Imaging;
34 using System.IO;
35 using System.Text;
36 using System.Runtime.InteropServices;
37 using RTF=System.Windows.Forms.RTF;
38
39 namespace System.Windows.Forms {
40 #if NET_2_0
41         [ClassInterface (ClassInterfaceType.AutoDispatch)]
42         [Docking (DockingBehavior.Ask)]
43         [ComVisible (true)]
44 #endif
45         public class RichTextBox : TextBoxBase {
46                 #region Local Variables
47                 internal bool           auto_word_select;
48                 internal int            bullet_indent;
49                 internal bool           detect_urls;
50                 internal int            margin_right;
51                 internal float          zoom;
52
53                 private RTF.TextMap     rtf_text_map;
54                 private int             rtf_skip_width;
55                 private int             rtf_skip_count;
56                 private StringBuilder   rtf_line;
57                 private SolidBrush      rtf_color;
58                 private RTF.Font        rtf_rtffont;
59                 private int             rtf_rtffont_size;
60                 private FontStyle       rtf_rtfstyle;
61                 private HorizontalAlignment rtf_rtfalign;
62                 private int             rtf_cursor_x;
63                 private int             rtf_cursor_y;
64                 private int             rtf_chars;
65                 private int rtf_par_line_left_indent;
66                 #endregion      // Local Variables
67
68                 #region Public Constructors
69                 public RichTextBox() {
70                         accepts_return = true;
71                         auto_word_select = false;
72                         bullet_indent = 0;
73                         detect_urls = true;
74                         max_length = Int32.MaxValue;
75                         margin_right = 0;
76                         zoom = 1;
77                         base.Multiline = true;
78                         document.CRLFSize = 1;
79                         shortcuts_enabled = true;
80
81                         scrollbars = RichTextBoxScrollBars.Both;
82                         alignment = HorizontalAlignment.Left;
83                         LostFocus += new EventHandler(RichTextBox_LostFocus);
84                         GotFocus += new EventHandler(RichTextBox_GotFocus);
85                         BackColor = ThemeEngine.Current.ColorWindow;
86                         backcolor_set = false;
87                         ForeColor = ThemeEngine.Current.ColorWindowText;
88
89                         base.HScrolled += new EventHandler(RichTextBox_HScrolled);
90                         base.VScrolled += new EventHandler(RichTextBox_VScrolled);
91
92 #if NET_2_0
93                         SetStyle (ControlStyles.StandardDoubleClick, false);
94 #endif
95                 }
96                 #endregion      // Public Constructors
97
98                 #region Private & Internal Methods
99                 private void RichTextBox_LostFocus(object sender, EventArgs e) {
100                         Invalidate();
101                 }
102
103                 private void RichTextBox_GotFocus(object sender, EventArgs e) {
104                         Invalidate();
105                 }
106                 #endregion      // Private & Internal Methods
107
108                 #region Public Instance Properties
109 #if NET_2_0
110                 [Browsable (false)]
111 #endif
112                 public override bool AllowDrop {
113                         get {
114                                 return base.AllowDrop;
115                         }
116
117                         set {
118                                 base.AllowDrop = value;
119                         }
120                 }
121
122                 [DefaultValue(false)]
123 #if NET_2_0
124                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
125                 [RefreshProperties (RefreshProperties.Repaint)]
126                 [EditorBrowsable (EditorBrowsableState.Never)]
127                 [Browsable (false)]
128 #else
129                 [Localizable(true)]
130 #endif
131                 public override bool AutoSize {
132                         get {
133                                 return auto_size;
134                         }
135
136                         set {
137                                 base.AutoSize = value;
138                         }
139                 }
140
141                 [DefaultValue(false)]
142                 public bool AutoWordSelection {
143                         get {
144                                 return auto_word_select;
145                         }
146
147                         set {
148                                 auto_word_select = true;
149                         }
150                 }
151
152                 [Browsable(false)]
153                 [EditorBrowsable(EditorBrowsableState.Never)]
154                 public override System.Drawing.Image BackgroundImage {
155                         get { return base.BackgroundImage; }
156                         set { base.BackgroundImage = value; }
157                 }
158
159                 [DefaultValue(0)]
160                 [Localizable(true)]
161                 public int BulletIndent {
162                         get {
163                                 return bullet_indent;
164                         }
165
166                         set {
167                                 bullet_indent = value;
168                         }
169                 }
170
171                 [Browsable(false)]
172                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
173                 public bool CanRedo {
174                         get {
175                                 return document.undo.CanRedo;
176                         }
177                 }
178
179                 [DefaultValue(true)]
180                 public bool DetectUrls {
181                         get {
182                                 return detect_urls;
183                         }
184
185                         set {
186                                 detect_urls = true;
187                         }
188                 }
189
190                 public override Font Font {
191                         get {
192                                 return base.Font;
193                         }
194
195                         set {
196                                 if (font != value) {
197                                         Line    start;
198                                         Line    end;
199
200                                         if (auto_size) {
201                                                 if (PreferredHeight != Height) {
202                                                         Height = PreferredHeight;
203                                                 }
204                                         }
205
206                                         base.Font = value;
207
208                                         // Font changes always set the whole doc to that font
209                                         start = document.GetLine(1);
210                                         end = document.GetLine(document.Lines);
211                                         document.FormatText(start, 1, end, end.text.Length + 1, base.Font, null, null, FormatSpecified.Font);
212                                 }
213                         }
214                 }
215
216                 public override Color ForeColor {
217                         get {
218                                 return base.ForeColor;
219                         }
220
221                         set {
222                                 base.ForeColor = value;
223                         }
224                 }
225
226                 [DefaultValue(Int32.MaxValue)]
227                 public override int MaxLength {
228                         get {
229                                 return base.max_length;
230                         }
231
232                         set {
233                                 base.max_length = value;
234                         }
235                 }
236
237                 [DefaultValue(true)]
238                 public override bool Multiline {
239                         get {
240                                 return base.Multiline;
241                         }
242
243                         set {
244                                 base.Multiline = value;
245                         }
246                 }
247
248                 [Browsable(false)]
249                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
250                 [MonoTODO]
251                 public string RedoActionName {
252                         get {
253                                 return document.undo.RedoActionName;
254                         }
255                 }
256
257                 [DefaultValue(0)]
258                 [Localizable(true)]
259                 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
260                 public int RightMargin {
261                         get {
262                                 return margin_right;
263                         }
264
265                         set {
266                                 margin_right = value;
267                         }
268                 }
269
270                 [Browsable(false)]
271                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
272 #if NET_2_0
273                 [RefreshProperties (RefreshProperties.All)]
274 #else
275                 [DefaultValue("")]
276 #endif
277                 public string Rtf {
278                         get {
279                                 Line            start_line;
280                                 Line            end_line;
281
282                                 start_line = document.GetLine(1);
283                                 end_line = document.GetLine(document.Lines);
284                                 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
285                         }
286
287                         set {
288                                 MemoryStream    data;
289
290                                 document.Empty();
291                                 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
292
293                                 InsertRTFFromStream(data, 0, 1);
294
295                                 data.Close();
296
297                                 Invalidate();
298                         }
299                 }
300
301                 [DefaultValue(RichTextBoxScrollBars.Both)]
302                 [Localizable(true)]
303                 public RichTextBoxScrollBars ScrollBars {
304                         get {
305                                 return scrollbars;
306                         }
307
308                         set {
309                                 scrollbars = value;
310                         }
311                 }
312
313                 [Browsable(false)]
314                 [DefaultValue("")]
315                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
316                 public string SelectedRtf {
317                         get {
318                                 return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
319                         }
320
321                         set {                           
322                                 MemoryStream    data;
323                                 int             x;
324                                 int             y;
325                                 int             sel_start;
326                                 int             chars;
327                                 Line            line;
328                                 LineTag         tag;
329
330                                 if (document.selection_visible) {
331                                         document.ReplaceSelection("", false);
332                                 }
333
334                                 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
335
336                                 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
337                                 InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y, out chars);
338                                 data.Close();
339
340                                 document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
341                                 document.SetSelection(line, sel_start);
342                                 document.PositionCaret(line, sel_start);
343                                 document.DisplayCaret();
344                                 ScrollToCaret();
345                                 OnTextChanged(EventArgs.Empty);
346                         }
347                 }
348
349                 [Browsable(false)]
350                 [DefaultValue("")]
351                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
352                 public override string SelectedText {
353                         get {
354                                 return base.SelectedText;
355                         }
356
357                         set {
358                                 base.SelectedText = value;
359                         }
360                 }
361
362                 [Browsable(false)]
363                 [DefaultValue(HorizontalAlignment.Left)]
364                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
365                 public HorizontalAlignment SelectionAlignment {
366                         get {
367                                 HorizontalAlignment     align;
368                                 Line                    start;
369                                 Line                    end;
370                                 Line                    line;
371
372                                 start = document.ParagraphStart(document.selection_start.line);
373                                 align = start.alignment;
374
375                                 end = document.ParagraphEnd(document.selection_end.line);
376
377                                 line = start;
378
379                                 while (true) {
380                                         if (line.alignment != align) {
381                                                 return HorizontalAlignment.Left;
382                                         }
383
384                                         if (line == end) {
385                                                 break;
386                                         }
387                                         line = document.GetLine(line.line_no + 1);
388                                 }
389
390                                 return align;
391                         }
392
393                         set {
394                                 Line                    start;
395                                 Line                    end;
396                                 Line                    line;
397
398                                 start = document.ParagraphStart(document.selection_start.line);
399
400                                 end = document.ParagraphEnd(document.selection_end.line);
401
402                                 line = start;
403
404                                 while (true) {
405                                         line.alignment = value;
406
407                                         if (line == end) {
408                                                 break;
409                                         }
410                                         line = document.GetLine(line.line_no + 1);
411                                 }
412                                 this.CalculateDocument();
413                         }
414                 }
415
416                 [Browsable(false)]
417                 [DefaultValue(false)]
418                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
419                 [MonoTODO]
420                 public bool SelectionBullet {
421                         get {
422                                 return false;
423                         }
424
425                         set {
426                         }
427                 }
428
429                 [Browsable(false)]
430                 [DefaultValue(0)]
431                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
432                 [MonoTODO]
433                 public int SelectionCharOffset {
434                         get {
435                                 return 0;
436                         }
437
438                         set {
439                         }
440                 }
441
442                 [Browsable(false)]
443                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
444                 public Color SelectionColor {
445                         get {
446                                 Color   color;
447                                 LineTag start;
448                                 LineTag end;
449                                 LineTag tag;
450
451                                 start = document.selection_start.line.FindTag (document.selection_start.pos);
452                                 end = document.selection_start.line.FindTag (document.selection_end.pos);
453                                 color = start.color.Color;
454
455                                 tag = start;
456                                 while (tag != null && tag != end) {
457
458                                         if (!color.Equals (tag.color.Color))
459                                                 return Color.Empty;
460
461                                         tag = document.NextTag (tag);
462                                 }
463
464                                 return color;
465                         }
466
467                         set {
468                                 FontDefinition  attributes;
469                                 int             sel_start;
470                                 int             sel_end;
471
472                                 attributes = new FontDefinition();
473                                 attributes.color = value;
474
475                                 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
476                                 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
477
478                                 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
479
480                                 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
481                                 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
482
483                                 document.UpdateView(document.selection_start.line, 0);
484                                 document.AlignCaret();
485                         }
486                 }
487
488                 [Browsable(false)]
489                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
490                 public Font SelectionFont {
491                         get {
492                                 Font    font;
493                                 LineTag start;
494                                 LineTag end;
495                                 LineTag tag;
496
497                                 start = document.selection_start.line.FindTag (document.selection_start.pos);
498                                 end = document.selection_start.line.FindTag (document.selection_end.pos);
499                                 font = start.font;
500
501                                 if (selection_length > 1) {
502                                         tag = start;
503                                         while (tag != null && tag != end) {
504
505                                                 if (!font.Equals(tag.font))
506                                                         return null;
507
508                                                 tag = document.NextTag (tag);
509                                         }
510                                 }
511
512                                 return font;
513                         }
514
515                         set {
516                                 FontDefinition  attributes;
517                                 int             sel_start;
518                                 int             sel_end;
519
520                                 attributes = new FontDefinition();
521                                 attributes.font_obj = value;
522
523                                 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
524                                 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
525
526                                 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
527
528                                 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
529                                 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
530
531                                 document.UpdateView(document.selection_start.line, 0);
532                                 document.AlignCaret();
533
534                         }
535                 }
536
537                 [Browsable(false)]
538                 [DefaultValue(0)]
539                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
540                 [MonoTODO]
541                 public int SelectionHangingIndent {
542                         get {
543                                 return 0;
544                         }
545
546                         set {
547                         }
548                 }
549
550                 [Browsable(false)]
551                 [DefaultValue(0)]
552                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
553                 [MonoTODO]
554                 public int SelectionIndent {
555                         get {
556                                 return 0;
557                         }
558
559                         set {
560                         }
561                 }
562
563                 [Browsable(false)]
564                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
565                 public override int SelectionLength {
566                         get {
567                                 return base.SelectionLength;
568                         }
569
570                         set {
571                                 base.SelectionLength = value;
572                         }
573                 }
574
575                 [Browsable(false)]
576                 [DefaultValue(false)]
577                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
578                 [MonoTODO]
579                 public bool SelectionProtected {
580                         get {
581                                 return false;
582                         }
583
584                         set {
585                         }
586                 }
587
588                 [Browsable(false)]
589                 [DefaultValue(0)]
590                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
591                 [MonoTODO]
592                 public int SelectionRightIndent {
593                         get {
594                                 return 0;
595                         }
596
597                         set {
598                         }
599                 }
600
601                 [Browsable(false)]
602                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
603                 [MonoTODO]
604                 public int[] SelectionTabs {
605                         get {
606                                 return new int[0];
607                         }
608
609                         set {
610                         }
611                 }
612
613                 [Browsable(false)]
614                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
615                 public RichTextBoxSelectionTypes SelectionType {
616                         get {
617                                 if (document.selection_start == document.selection_end) {
618                                         return RichTextBoxSelectionTypes.Empty;
619                                 }
620
621                                 // Lazy, but works
622                                 if (SelectedText.Length > 1) {
623                                         return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
624                                 }
625
626                                 return RichTextBoxSelectionTypes.Text;
627                         }
628                 }
629
630                 [DefaultValue(false)]
631                 [MonoTODO]
632                 public bool ShowSelectionMargin {
633                         get {
634                                 return false;
635                         }
636
637                         set {
638                         }
639                 }
640
641                 [Localizable(true)]
642 #if NET_2_0
643                 [RefreshProperties (RefreshProperties.All)]
644 #endif
645                 public override string Text {
646                         get {
647                                 return base.Text;
648                         }
649
650                         set {
651                                 base.Text = value;
652                         }
653                 }
654
655                 [Browsable(false)]
656                 public override int TextLength {
657                         get {
658                                 return base.TextLength;
659                         }
660                 }
661
662                 [Browsable(false)]
663                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
664                 public string UndoActionName {
665                         get {
666                                 return document.undo.UndoActionName;
667                         }
668                 }
669
670                 [Localizable(true)]
671                 [DefaultValue(1)]
672                 public float ZoomFactor {
673                         get {
674                                 return zoom;
675                         }
676
677                         set {
678                                 zoom = value;
679                         }
680                 }
681                 #endregion      // Public Instance Properties
682
683                 #region Protected Instance Properties
684                 protected override CreateParams CreateParams {
685                         get {
686                                 return base.CreateParams;
687                         }
688                 }
689
690                 protected override Size DefaultSize {
691                         get {
692                                 return new Size(100, 96);
693                         }
694                 }
695                 #endregion      // Protected Instance Properties
696
697                 #region Public Instance Methods
698                 public bool CanPaste(DataFormats.Format clipFormat) {
699                         if ((clipFormat.Name == DataFormats.Rtf) ||
700                                 (clipFormat.Name == DataFormats.Text) ||
701                                 (clipFormat.Name == DataFormats.UnicodeText)) {
702                                         return true;
703                         }
704                         return false;
705                 }
706
707                 public int Find(char[] characterSet) {
708                         return Find(characterSet, -1, -1);
709                 }
710
711                 public int Find(char[] characterSet, int start) {
712                         return Find(characterSet, start, -1);
713                 }
714
715                 public int Find(char[] characterSet, int start, int end) {
716                         Document.Marker start_mark;
717                         Document.Marker end_mark;
718                         Document.Marker result;
719
720                         if (start == -1) {
721                                 document.GetMarker(out start_mark, true);
722                         } else {
723                                 Line line;
724                                 LineTag tag;
725                                 int pos;
726
727                                 start_mark = new Document.Marker();
728
729                                 document.CharIndexToLineTag(start, out line, out tag, out pos);
730                                 start_mark.line = line;
731                                 start_mark.tag = tag;
732                                 start_mark.pos = pos;
733                         }
734
735                         if (end == -1) {
736                                 document.GetMarker(out end_mark, false);
737                         } else {
738                                 Line line;
739                                 LineTag tag;
740                                 int pos;
741
742                                 end_mark = new Document.Marker();
743
744                                 document.CharIndexToLineTag(end, out line, out tag, out pos);
745                                 end_mark.line = line;
746                                 end_mark.tag = tag;
747                                 end_mark.pos = pos;
748                         }
749
750                         if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
751                                 return document.LineTagToCharIndex(result.line, result.pos);
752                         }
753
754                         return -1;
755                 }
756
757                 public int Find(string str) {
758                         return Find(str, -1, -1, RichTextBoxFinds.None);
759                 }
760
761                 public int Find(string str, int start, int end, RichTextBoxFinds options) {
762                         Document.Marker start_mark;
763                         Document.Marker end_mark;
764                         Document.Marker result;
765
766                         if (start == -1) {
767                                 document.GetMarker(out start_mark, true);
768                         } else {
769                                 Line line;
770                                 LineTag tag;
771                                 int pos;
772
773                                 start_mark = new Document.Marker();
774
775                                 document.CharIndexToLineTag(start, out line, out tag, out pos);
776
777                                 start_mark.line = line;
778                                 start_mark.tag = tag;
779                                 start_mark.pos = pos;
780                         }
781
782                         if (end == -1) {
783                                 document.GetMarker(out end_mark, false);
784                         } else {
785                                 Line line;
786                                 LineTag tag;
787                                 int pos;
788
789                                 end_mark = new Document.Marker();
790
791                                 document.CharIndexToLineTag(end, out line, out tag, out pos);
792
793                                 end_mark.line = line;
794                                 end_mark.tag = tag;
795                                 end_mark.pos = pos;
796                         }
797
798                         if (document.Find(str, start_mark, end_mark, out result, options)) {
799                                 return document.LineTagToCharIndex(result.line, result.pos);
800                         }
801
802                         return -1;
803                 }
804
805                 public int Find(string str, int start, RichTextBoxFinds options) {
806                         return Find(str, start, -1, options);
807                 }
808
809                 public int Find(string str, RichTextBoxFinds options) {
810                         return Find(str, -1, -1, options);
811                 }
812
813                 public char GetCharFromPosition(Point pt) {
814                         LineTag tag;
815                         int     pos;
816
817                         PointToTagPos(pt, out tag, out pos);
818
819                         if (pos >= tag.line.text.Length) {
820                                 return '\n';
821                         }
822
823                         return tag.line.text[pos];
824                         
825                 }
826
827                 public int GetCharIndexFromPosition(Point pt) {
828                         LineTag tag;
829                         int     pos;
830
831                         PointToTagPos(pt, out tag, out pos);
832
833                         return document.LineTagToCharIndex(tag.line, pos);
834                 }
835
836                 public int GetLineFromCharIndex(int index) {
837                         Line    line;
838                         LineTag tag;
839                         int     pos;
840
841                         document.CharIndexToLineTag(index, out line, out tag, out pos);
842
843                         return line.LineNo - 1;
844                 }
845
846                 public Point GetPositionFromCharIndex(int index) {
847                         Line    line;
848                         LineTag tag;
849                         int     pos;
850
851                         document.CharIndexToLineTag(index, out line, out tag, out pos);
852
853                         return new Point((int)line.widths[pos] + 1, line.Y + 1);
854                 }
855
856                 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
857                         document.Empty();
858
859                         
860                         // FIXME - ignoring unicode
861                         if (fileType == RichTextBoxStreamType.PlainText) {
862                                 StringBuilder   sb;
863                                 int             count;
864                                 byte[]          buffer;
865
866                                 try {
867                                         sb = new StringBuilder((int)data.Length);
868                                         buffer = new byte[1024];
869                                 } catch {
870                                         throw new IOException("Not enough memory to load document");
871                                 }
872
873                                 count = 0;
874                                 while (count < data.Length) {
875                                         count += data.Read(buffer, count, 1024);
876                                         sb.Append(buffer);
877                                 }
878                                 base.Text = sb.ToString();
879                                 return;
880                         }
881
882                         InsertRTFFromStream(data, 0, 1);
883
884                         document.PositionCaret (document.GetLine (1), 0);
885                         document.SetSelectionToCaret (true);
886                         ScrollToCaret ();
887                 }
888
889                 [MonoTODO("Make smarter RTF detection?")]
890                 public void LoadFile(string path) {
891                         if (path.EndsWith(".rtf")) {
892                                 LoadFile(path, RichTextBoxStreamType.RichText);
893                         } else {
894                                 LoadFile(path, RichTextBoxStreamType.PlainText);
895                         }
896                 }
897
898                 public void LoadFile(string path, RichTextBoxStreamType fileType) {
899                         FileStream      data;
900
901                         data = null;
902
903
904                         try {
905                                 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
906
907                                 LoadFile(data, fileType);
908                         }
909 #if !DEBUG
910                         catch {
911                                 throw new IOException("Could not open file " + path);
912                         }
913 #endif
914                         finally {
915                                 if (data != null) {
916                                         data.Close();
917                                 }
918                         }
919                 }
920
921                 public void Paste(DataFormats.Format clipFormat) {
922                         base.Paste(Clipboard.GetDataObject(), clipFormat, false);
923                 }
924
925                 public void Redo()
926                 {
927                         document.undo.Redo ();
928                 }
929
930                 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
931                         Encoding        encoding;
932                         int             i;
933                         Byte[]          bytes;
934
935
936                         if (fileType == RichTextBoxStreamType.UnicodePlainText) {
937                                 encoding = Encoding.Unicode;
938                         } else {
939                                 encoding = Encoding.ASCII;
940                         }
941
942                         switch(fileType) {
943                                 case RichTextBoxStreamType.PlainText: 
944                                 case RichTextBoxStreamType.TextTextOleObjs: 
945                                 case RichTextBoxStreamType.UnicodePlainText: {
946                                         if (!Multiline) {
947                                                 bytes = encoding.GetBytes(document.Root.text.ToString());
948                                                 data.Write(bytes, 0, bytes.Length);
949                                                 return;
950                                         }
951
952                                         for (i = 1; i < document.Lines; i++) {
953                                                 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
954                                                 data.Write(bytes, 0, bytes.Length);
955                                         }
956                                         bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
957                                         data.Write(bytes, 0, bytes.Length);
958                                         return;
959                                 }
960                         }
961
962                         // If we're here we're saving RTF
963                         Line            start_line;
964                         Line            end_line;
965                         StringBuilder   rtf;
966                         int             current;
967                         int             total;
968
969                         start_line = document.GetLine(1);
970                         end_line = document.GetLine(document.Lines);
971                         rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
972                         total = rtf.Length;
973                         bytes = new Byte[4096];
974
975                         // Let's chunk it so we don't use up all memory...
976                         for (i = 0; i < total; i += 1024) {
977                                 if ((i + 1024) < total) {
978                                         current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
979                                 } else {
980                                         current = total - i;
981                                         current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
982                                 }
983                                 data.Write(bytes, 0, current);
984                         }
985                 }
986
987                 public void SaveFile(string path) {
988                         if (path.EndsWith(".rtf")) {
989                                 SaveFile(path, RichTextBoxStreamType.RichText);
990                         } else {
991                                 SaveFile(path, RichTextBoxStreamType.PlainText);
992                         }
993                 }
994
995                 public void SaveFile(string path, RichTextBoxStreamType fileType) {
996                         FileStream      data;
997
998                         data = null;
999
1000 //                      try {
1001                                 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
1002                                 SaveFile(data, fileType);
1003 //                      }
1004
1005 //                      catch {
1006 //                              throw new IOException("Could not write document to file " + path);
1007 //                      }
1008
1009 //                      finally {
1010                                 if (data != null) {
1011                                         data.Close();
1012                                 }
1013 //                      }
1014                 }
1015
1016                 #endregion      // Public Instance Methods
1017
1018                 #region Protected Instance Methods
1019                 protected virtual object CreateRichEditOleCallback() {
1020                         throw new NotImplementedException();
1021                 }
1022
1023                 protected override void OnBackColorChanged(EventArgs e) {
1024                         base.OnBackColorChanged (e);
1025                 }
1026
1027                 protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
1028                         ContentsResizedEventHandler eh = (ContentsResizedEventHandler)(Events [ContentsResizedEvent]);
1029                         if (eh != null)
1030                                 eh (this, e);
1031                 }
1032
1033                 protected override void OnContextMenuChanged(EventArgs e) {
1034                         base.OnContextMenuChanged (e);
1035                 }
1036
1037                 protected override void OnHandleCreated(EventArgs e) {
1038                         base.OnHandleCreated (e);
1039                 }
1040
1041                 protected override void OnHandleDestroyed(EventArgs e) {
1042                         base.OnHandleDestroyed (e);
1043                 }
1044
1045                 protected virtual void OnHScroll(EventArgs e) {
1046                         EventHandler eh = (EventHandler)(Events [HScrollEvent]);
1047                         if (eh != null)
1048                                 eh (this, e);
1049                 }
1050
1051                 [MonoTODO("Determine when to call this")]
1052                 protected virtual void OnImeChange(EventArgs e) {
1053                         EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
1054                         if (eh != null)
1055                                 eh (this, e);
1056                 }
1057
1058                 protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
1059                         LinkClickedEventHandler eh = (LinkClickedEventHandler)(Events [LinkClickedEvent]);
1060                         if (eh != null)
1061                                 eh (this, e);
1062                 }
1063
1064                 protected virtual void OnProtected(EventArgs e) {
1065                         EventHandler eh = (EventHandler)(Events [ProtectedEvent]);
1066                         if (eh != null)
1067                                 eh (this, e);
1068                 }
1069
1070                 protected override void OnRightToLeftChanged(EventArgs e) {
1071                         base.OnRightToLeftChanged (e);
1072                 }
1073
1074                 protected virtual void OnSelectionChanged(EventArgs e) {
1075                         EventHandler eh = (EventHandler)(Events [SelectionChangedEvent]);
1076                         if (eh != null)
1077                                 eh (this, e);
1078                 }
1079
1080                 protected override void OnSystemColorsChanged(EventArgs e) {
1081                         base.OnSystemColorsChanged (e);
1082                 }
1083
1084                 protected override void OnTextChanged(EventArgs e) {
1085                         base.OnTextChanged (e);
1086                 }
1087
1088                 protected virtual void OnVScroll(EventArgs e) {
1089                         EventHandler eh = (EventHandler)(Events [VScrollEvent]);
1090                         if (eh != null)
1091                                 eh (this, e);
1092                 }
1093
1094                 protected override void WndProc(ref Message m) {
1095                         base.WndProc (ref m);
1096                 }
1097                 #endregion      // Protected Instance Methods
1098
1099                 #region Events
1100                 static object ContentsResizedEvent = new object ();
1101                 static object HScrollEvent = new object ();
1102                 static object ImeChangeEvent = new object ();
1103                 static object LinkClickedEvent = new object ();
1104                 static object ProtectedEvent = new object ();
1105                 static object SelectionChangedEvent = new object ();
1106                 static object VScrollEvent = new object ();
1107
1108                 [Browsable(false)]
1109                 [EditorBrowsable(EditorBrowsableState.Never)]
1110                 public new event EventHandler BackgroundImageChanged {
1111                         add { base.BackgroundImageChanged += value; }
1112                         remove { base.BackgroundImageChanged -= value; }
1113                 }
1114
1115                 public event ContentsResizedEventHandler ContentsResized {
1116                         add { Events.AddHandler (ContentsResizedEvent, value); }
1117                         remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1118                 }
1119
1120                 [Browsable(false)]
1121                 [EditorBrowsable(EditorBrowsableState.Never)]
1122                 public new event EventHandler DoubleClick {
1123                         add { base.DoubleClick += value; }
1124                         remove { base.DoubleClick -= value; }
1125                 }
1126
1127                 [Browsable(false)]
1128 #if !NET_2_0
1129                 [EditorBrowsable(EditorBrowsableState.Never)]
1130 #endif
1131                 public new event DragEventHandler DragDrop {
1132                         add { base.DragDrop += value; }
1133                         remove { base.DragDrop -= value; }
1134                 }
1135
1136                 [Browsable(false)]
1137 #if !NET_2_0
1138                 [EditorBrowsable(EditorBrowsableState.Never)]
1139 #endif
1140                 public new event DragEventHandler DragEnter {
1141                         add { base.DragEnter += value; }
1142                         remove { base.DragEnter -= value; }
1143                 }
1144
1145                 [Browsable(false)]
1146                 [EditorBrowsable(EditorBrowsableState.Never)]
1147                 public new event EventHandler DragLeave {
1148                         add { base.DragLeave += value; }
1149                         remove { base.DragLeave -= value; }
1150                 }
1151
1152
1153                 [Browsable(false)]
1154                 [EditorBrowsable(EditorBrowsableState.Never)]
1155                 public new event DragEventHandler DragOver {
1156                         add { base.DragOver += value; }
1157                         remove { base.DragOver -= value; }
1158                 }
1159
1160
1161                 [Browsable(false)]
1162                 [EditorBrowsable(EditorBrowsableState.Never)]
1163                 public new event GiveFeedbackEventHandler GiveFeedback {
1164                         add { base.GiveFeedback += value; }
1165                         remove { base.GiveFeedback -= value; }
1166                 }
1167
1168                 public event EventHandler HScroll {
1169                         add { Events.AddHandler (HScrollEvent, value); }
1170                         remove { Events.RemoveHandler (HScrollEvent, value); }
1171                 }
1172
1173                 public event EventHandler ImeChange {
1174                         add { Events.AddHandler (ImeChangeEvent, value); }
1175                         remove { Events.RemoveHandler (ImeChangeEvent, value); }
1176                 }
1177
1178                 public event LinkClickedEventHandler LinkClicked {
1179                         add { Events.AddHandler (LinkClickedEvent, value); }
1180                         remove { Events.RemoveHandler (LinkClickedEvent, value); }
1181                 }
1182
1183                 public event EventHandler Protected {
1184                         add { Events.AddHandler (ProtectedEvent, value); }
1185                         remove { Events.RemoveHandler (ProtectedEvent, value); }
1186                 }
1187
1188                 [Browsable(false)]
1189                 [EditorBrowsable(EditorBrowsableState.Never)]
1190                 public new event QueryContinueDragEventHandler QueryContinueDrag {
1191                         add { base.QueryContinueDrag += value; }
1192                         remove { base.QueryContinueDrag -= value; }
1193                 }
1194
1195                 public event EventHandler SelectionChanged {
1196                         add { Events.AddHandler (SelectionChangedEvent, value); }
1197                         remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1198                 }
1199
1200                 public event EventHandler VScroll {
1201                         add { Events.AddHandler (VScrollEvent, value); }
1202                         remove { Events.RemoveHandler (VScrollEvent, value); }
1203                 }
1204                 #endregion      // Events
1205
1206                 #region Private Methods
1207
1208                 internal override void SelectWord ()
1209                 {
1210                         document.ExpandSelection(CaretSelection.Word, false);
1211                 }
1212
1213                 private void HandleControl(RTF.RTF rtf) {
1214                         switch(rtf.Major) {
1215                                 case RTF.Major.Unicode: {
1216                                         switch(rtf.Minor) {
1217                                                 case Minor.UnicodeCharBytes: {
1218                                                         rtf_skip_width = rtf.Param;
1219                                                         break;
1220                                                 }
1221
1222                                                 case Minor.UnicodeChar: {
1223                                                         rtf_skip_count += rtf_skip_width;
1224                                                         rtf_line.Append((char)rtf.Param);
1225                                                         break;
1226                                                 }
1227                                         }
1228                                         break;
1229                                 }
1230
1231                                 case RTF.Major.Destination: {
1232 //                                      Console.Write("[Got Destination control {0}]", rtf.Minor);
1233                                         rtf.SkipGroup();
1234                                         break;
1235                                 }
1236
1237                                 case RTF.Major.PictAttr:
1238                                         if (rtf.Picture != null && rtf.Picture.IsValid ()) {
1239                                                 Line line = document.GetLine (rtf_cursor_y);
1240                                                 document.InsertPicture (line, 0, rtf.Picture);
1241                                                 rtf_cursor_x++;
1242
1243                                                 FlushText (rtf, true);
1244                                                 rtf.Picture = null;
1245                                         }
1246                                         break;
1247
1248                                 case RTF.Major.CharAttr: {
1249                                         switch(rtf.Minor) {
1250                                                 case Minor.ForeColor: {
1251                                                         System.Windows.Forms.RTF.Color  color;
1252
1253                                                         color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
1254                                                         
1255                                                         if (color != null) {
1256                                                                 FlushText(rtf, false);
1257                                                                 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
1258                                                                         this.rtf_color = new SolidBrush(ForeColor);
1259                                                                 } else {
1260                                                                         this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1261                                                                 }
1262                                                                 FlushText (rtf, false);
1263                                                         }
1264                                                         break;
1265                                                 }
1266
1267                                                 case Minor.FontSize: {
1268                                                         FlushText(rtf, false);
1269                                                         this.rtf_rtffont_size = rtf.Param / 2;
1270                                                         break;
1271                                                 }
1272
1273                                                 case Minor.FontNum: {
1274                                                         System.Windows.Forms.RTF.Font   font;
1275
1276                                                         font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
1277                                                         if (font != null) {
1278                                                                 FlushText(rtf, false);
1279                                                                 this.rtf_rtffont = font;
1280                                                         }
1281                                                         break;
1282                                                 }
1283
1284                                                 case Minor.Plain: {
1285                                                         FlushText(rtf, false);
1286                                                         rtf_rtfstyle = FontStyle.Regular;
1287                                                         break;
1288                                                 }
1289
1290                                                 case Minor.Bold: {
1291                                                         FlushText(rtf, false);
1292                                                         if (rtf.Param == RTF.RTF.NoParam) {
1293                                                                 rtf_rtfstyle |= FontStyle.Bold;
1294                                                         } else {
1295                                                                 rtf_rtfstyle &= ~FontStyle.Bold;
1296                                                         }
1297                                                         break;
1298                                                 }
1299
1300                                                 case Minor.Italic: {
1301                                                         FlushText(rtf, false);
1302                                                         if (rtf.Param == RTF.RTF.NoParam) {
1303                                                                 rtf_rtfstyle |= FontStyle.Italic;
1304                                                         } else {
1305                                                                 rtf_rtfstyle &= ~FontStyle.Italic;
1306                                                         }
1307                                                         break;
1308                                                 }
1309
1310                                                 case Minor.StrikeThru: {
1311                                                         FlushText(rtf, false);
1312                                                         if (rtf.Param == RTF.RTF.NoParam) {
1313                                                                 rtf_rtfstyle |= FontStyle.Strikeout;
1314                                                         } else {
1315                                                                 rtf_rtfstyle &= ~FontStyle.Strikeout;
1316                                                         }
1317                                                         break;
1318                                                 }
1319
1320                                                 case Minor.Underline: {
1321                                                         FlushText(rtf, false);
1322                                                         if (rtf.Param == RTF.RTF.NoParam) {
1323                                                                 rtf_rtfstyle |= FontStyle.Underline;
1324                                                         } else {
1325                                                                 rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline;
1326                                                         }
1327                                                         break;
1328                                                 }
1329
1330                                                 case Minor.NoUnderline: {
1331                                                         FlushText(rtf, false);
1332                                                         rtf_rtfstyle &= ~FontStyle.Underline;
1333                                                         break;
1334                                                 }
1335                                         }
1336                                         break;
1337                                 }
1338
1339                         case RTF.Major.ParAttr: {
1340                                 switch (rtf.Minor) {
1341                                 case Minor.LeftIndent:
1342                                         rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * CreateGraphics ().DpiX + 0.5F);
1343                                         break;
1344                                 }
1345                                 break;
1346                         }
1347                                 
1348                                 case RTF.Major.SpecialChar: {
1349                                         //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1350                                         SpecialChar(rtf);
1351                                         break;
1352                                 }
1353                         }
1354                 }
1355
1356                 private void SpecialChar(RTF.RTF rtf) {
1357                         switch(rtf.Minor) {
1358                                 case Minor.Page:
1359                                 case Minor.Sect:
1360                                 case Minor.Row:
1361                                 case Minor.Line:
1362                                 case Minor.Par: {
1363                                         FlushText(rtf, true);
1364                                         break;
1365                                 }
1366
1367                                 case Minor.Cell: {
1368                                         Console.Write(" ");
1369                                         break;
1370                                 }
1371
1372                                 case Minor.NoBrkSpace: {
1373                                         Console.Write(" ");
1374                                         break;
1375                                 }
1376
1377                                 case Minor.Tab: {
1378                                         rtf_line.Append ("\t");
1379 //                                      FlushText (rtf, false);
1380                                         break;
1381                                 }
1382
1383                                 case Minor.NoReqHyphen:
1384                                 case Minor.NoBrkHyphen: {
1385                                         rtf_line.Append ("-");
1386 //                                      FlushText (rtf, false);
1387                                         break;
1388                                 }
1389
1390                                 case Minor.Bullet: {
1391                                         Console.WriteLine("*");
1392                                         break;
1393                                 }
1394
1395                         case Minor.WidowCtrl:
1396                                 break;
1397
1398                                 case Minor.EmDash: {
1399                                 rtf_line.Append ("\u2014");
1400                                         break;
1401                                 }
1402
1403                                 case Minor.EnDash: {
1404                                         rtf_line.Append ("\u2013");
1405                                         break;
1406                                 }
1407 /*
1408                                 case Minor.LQuote: {
1409                                         Console.Write("\u2018");
1410                                         break;
1411                                 }
1412
1413                                 case Minor.RQuote: {
1414                                         Console.Write("\u2019");
1415                                         break;
1416                                 }
1417
1418                                 case Minor.LDblQuote: {
1419                                         Console.Write("\u201C");
1420                                         break;
1421                                 }
1422
1423                                 case Minor.RDblQuote: {
1424                                         Console.Write("\u201D");
1425                                         break;
1426                                 }
1427 */
1428                                 default: {
1429 //                                      Console.WriteLine ("skipped special char:   {0}", rtf.Minor);
1430 //                                      rtf.SkipGroup();
1431                                         break;
1432                                 }
1433                         }
1434                 }
1435
1436                 private void HandleText(RTF.RTF rtf) {
1437                         if (rtf_skip_count > 0) {
1438                                 rtf_skip_count--;
1439                                 return;
1440                         }
1441
1442                         /*
1443                         if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1444                                 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1445                         } else {
1446                                 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1447                                         rtf_line.Append((char)rtf.Major);
1448                                 } else {
1449                                         //rtf_line.Append((char)rtf.Major);
1450                                         Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1451                                 }
1452                         }
1453                         */
1454                         rtf_line.Append (rtf.EncodedText);
1455                 }
1456
1457                 private void FlushText(RTF.RTF rtf, bool newline) {
1458                         int             length;
1459                         Font            font;
1460
1461                         length = rtf_line.Length;
1462                         if (!newline && (length == 0)) {
1463                                 return;
1464                         }
1465
1466                         if (rtf_rtffont == null) {
1467                                 // First font in table is default
1468                                 rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0);
1469                         }
1470
1471                         font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1472
1473                         if (rtf_color == null) {
1474                                 System.Windows.Forms.RTF.Color color;
1475
1476                                 // First color in table is default
1477                                 color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0);
1478
1479                                 if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
1480                                         rtf_color = new SolidBrush(ForeColor);
1481                                 } else {
1482                                         rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
1483                                 }
1484                                 
1485                         }
1486
1487                         rtf_chars += rtf_line.Length;
1488
1489                         if (rtf_cursor_x == 0) {
1490                                 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color, LineEnding.Wrap);
1491                                 if (rtf_par_line_left_indent != 0) {
1492                                         Line line = document.GetLine (rtf_cursor_y);
1493                                         line.indent = rtf_par_line_left_indent;
1494                                 }
1495                         } else {
1496                                 Line    line;
1497
1498                                 line = document.GetLine(rtf_cursor_y);
1499                                 line.indent = rtf_par_line_left_indent;
1500                                 if (rtf_line.Length > 0) {
1501                                         document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1502                                         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
1503                                 }
1504                                 if (newline) {
1505                                         document.Split(line, rtf_cursor_x + length);
1506                                 }
1507                         }
1508
1509                         if (newline) {
1510                                 rtf_cursor_x = 0;
1511                                 rtf_cursor_y++;
1512                         } else {
1513                                 rtf_cursor_x += length;
1514                         }
1515                         rtf_line.Length = 0;    // Empty line
1516                 }
1517
1518                 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1519                         int     x;
1520                         int     y;
1521                         int     chars;
1522
1523                         InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
1524                 }
1525
1526                 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) {
1527                         RTF.RTF         rtf;
1528
1529                         rtf = new RTF.RTF(data);
1530
1531                         // Prepare
1532                         rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1533                         rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1534
1535                         rtf_skip_width = 0;
1536                         rtf_skip_count = 0;
1537                         rtf_line = new StringBuilder();
1538                         rtf_color = null;
1539                         rtf_rtffont_size = (int)this.Font.Size;
1540                         rtf_rtfalign = HorizontalAlignment.Left;
1541                         rtf_rtfstyle = FontStyle.Regular;
1542                         rtf_rtffont = null;
1543                         rtf_cursor_x = cursor_x;
1544                         rtf_cursor_y = cursor_y;
1545                         rtf_chars = 0;
1546                         rtf.DefaultFont(this.Font.Name);
1547
1548                         rtf_text_map = new RTF.TextMap();
1549                         RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1550
1551                         document.SuspendRecalc ();
1552
1553                         try {
1554                                 rtf.Read();     // That's it
1555                                 FlushText(rtf, false);
1556
1557                         }
1558
1559
1560                         catch (RTF.RTFException e) {
1561 #if DEBUG
1562                                 throw e;
1563 #endif
1564                                 // Seems to be plain text or broken RTF
1565                                 Console.WriteLine("RTF Parsing failure: {0}", e.Message);
1566                         }                     
1567
1568                         to_x = rtf_cursor_x;
1569                         to_y = rtf_cursor_y;
1570                         chars = rtf_chars;
1571
1572                         document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
1573                         document.ResumeRecalc (true);
1574
1575                         document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1576                 }
1577
1578                 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1579                         OnHScroll(e);
1580                 }
1581
1582                 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1583                         OnVScroll(e);
1584                 }
1585
1586                 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1587                         Point p;
1588
1589                         p = pt;
1590
1591                         if (p.X >= document.ViewPortWidth) {
1592                                 p.X = document.ViewPortWidth - 1;
1593                         } else if (p.X < 0) {
1594                                 p.X = 0;
1595                         }
1596
1597                         if (p.Y >= document.ViewPortHeight) {
1598                                 p.Y = document.ViewPortHeight - 1;
1599                         } else if (p.Y < 0) {
1600                                 p.Y = 0;
1601                         }
1602
1603                         tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1604                 }
1605
1606                 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1607                         if (prev_index != font_index) {
1608                                 rtf.Append(String.Format("\\f{0}", font_index));        // Font table entry
1609                         }
1610
1611                         if ((prev_font == null) || (prev_font.Size != font.Size)) {
1612                                 rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2)));             // Font size
1613                         }
1614
1615                         if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1616                                 if (font.Bold) {
1617                                         rtf.Append("\\b");
1618                                 } else {
1619                                         if (prev_font != null) {
1620                                                 rtf.Append("\\b0");
1621                                         }
1622                                 }
1623                         }
1624
1625                         if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1626                                 if (font.Italic) {
1627                                         rtf.Append("\\i");
1628                                 } else {
1629                                         if (prev_font != null) {
1630                                                 rtf.Append("\\i0");
1631                                         }
1632                                 }
1633                         }
1634
1635                         if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1636                                 if (font.Strikeout) {
1637                                         rtf.Append("\\strike");
1638                                 } else {
1639                                         if (prev_font != null) {
1640                                                 rtf.Append("\\strike0");
1641                                         }
1642                                 }
1643                         }
1644
1645                         if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1646                                 if (font.Underline) {
1647                                         rtf.Append("\\ul");
1648                                 } else {
1649                                         if (prev_font != null) {
1650                                                 rtf.Append("\\ul0");
1651                                         }
1652                                 }
1653                         }
1654                 }
1655
1656                 [MonoTODO("Emit unicode and other special characters properly")]
1657                 private void EmitRTFText(StringBuilder rtf, string text) {
1658                         rtf.Append(text);
1659                 }
1660
1661                 // start_pos and end_pos are 0-based
1662                 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1663                         StringBuilder   sb;
1664                         ArrayList       fonts;
1665                         ArrayList       colors;
1666                         Color           color;
1667                         Font            font;
1668                         Line            line;
1669                         LineTag         tag;
1670                         int             pos;
1671                         int             line_no;
1672                         int             line_len;
1673                         int             i;
1674                         int             length;
1675
1676                         sb = new StringBuilder();
1677                         fonts = new ArrayList(10);
1678                         colors = new ArrayList(10);
1679
1680                         // Two runs, first we parse to determine tables;
1681                         // and unlike most of our processing here we work on tags
1682
1683                         line = start_line;
1684                         line_no = start_line.line_no;
1685                         pos = start_pos;
1686
1687                         // Add default font and color; to optimize document content we don't
1688                         // use this.Font and this.ForeColor but the font/color from the first tag
1689                         tag = LineTag.FindTag(start_line, pos);
1690                         font = tag.font;
1691                         color = ((SolidBrush)tag.color).Color;
1692                         fonts.Add(font.Name);
1693                         colors.Add(color);
1694
1695                         while (line_no <= end_line.line_no) {
1696                                 line = document.GetLine(line_no);
1697                                 tag = LineTag.FindTag(line, pos);
1698
1699                                 if (line_no != end_line.line_no) {
1700                                         line_len = line.text.Length;
1701                                 } else {
1702                                         line_len = end_pos;
1703                                 }
1704
1705                                 while (pos < line_len) {
1706                                         if (tag.font.Name != font.Name) {
1707                                                 font = tag.font;
1708                                                 if (!fonts.Contains(font.Name)) {
1709                                                         fonts.Add(font.Name);
1710                                                 }
1711                                         }
1712
1713                                         if (((SolidBrush)tag.color).Color != color) {
1714                                                 color = ((SolidBrush)tag.color).Color;
1715                                                 if (!colors.Contains(color)) {
1716                                                         colors.Add(color);
1717                                                 }
1718                                         }
1719
1720                                         pos = tag.start + tag.length - 1;
1721                                         tag = tag.next;
1722                                 }
1723                                 pos = 0;
1724                                 line_no++;
1725                         }
1726
1727                         // We have the tables, emit the header
1728                         sb.Append("{\\rtf1\\ansi");
1729                         sb.Append("\\ansicpg1252");     // FIXME - is this correct?
1730
1731                         // Default Font
1732                         sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1733
1734                         // Default Language 
1735                         sb.Append("\\deflang1033\n");   // FIXME - always 1033?
1736
1737                         // Emit the font table
1738                         sb.Append("{\\fonttbl");
1739                         for (i = 0; i < fonts.Count; i++) {
1740                                 sb.Append(String.Format("{{\\f{0}", i));        // {Font 
1741                                 sb.Append("\\fnil");                    // Family
1742                                 sb.Append("\\fcharset0 ");              // Charset ANSI<space>
1743                                 sb.Append((string)fonts[i]);            // Font name
1744                                 sb.Append(";}");                        // }
1745                         }
1746                         sb.Append("}\n");
1747
1748                         // Emit the color table (if needed)
1749                         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))) {
1750                                 sb.Append("{\\colortbl ");                      // Header and NO! default color
1751                                 for (i = 0; i < colors.Count; i++) {
1752                                         sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1753                                         sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1754                                         sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1755                                         sb.Append(";");
1756                                 }
1757                                 sb.Append("}\n");
1758                         }
1759
1760                         sb.Append("{\\*\\generator Mono RichTextBox;}");
1761                         // Emit initial paragraph settings
1762                         tag = LineTag.FindTag(start_line, start_pos);
1763                         sb.Append("\\pard");    // Reset to default paragraph properties
1764                         EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font);    // Font properties
1765                         sb.Append(" ");         // Space separator
1766
1767                         font = tag.font;
1768                         color = (Color)colors[0];
1769                         line = start_line;
1770                         line_no = start_line.line_no;
1771                         pos = start_pos;
1772
1773                         while (line_no <= end_line.line_no) {
1774                                 line = document.GetLine(line_no);
1775                                 tag = LineTag.FindTag(line, pos);
1776
1777                                 if (line_no != end_line.line_no) {
1778                                         line_len = line.text.Length;
1779                                 } else {
1780                                         line_len = end_pos;
1781                                 }
1782
1783                                 while (pos < line_len) {
1784                                         length = sb.Length;
1785
1786                                         if (tag.font != font) {
1787                                                 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1788                                                 font = tag.font;
1789                                         }
1790
1791                                         if (((SolidBrush)tag.color).Color != color) {
1792                                                 color = ((SolidBrush)tag.color).Color;
1793                                                 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1794                                         }
1795                                         if (length != sb.Length) {
1796                                                 sb.Append(" "); // Emit space to separate keywords from text
1797                                         }
1798
1799                                         // Emit the string itself
1800                                         if (line_no != end_line.line_no) {
1801                                                 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1802                                         } else {
1803                                                 if (end_pos < (tag.start + tag.length - 1)) {
1804                                                         // Emit partial tag only, end_pos is inside this tag
1805                                                         EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1806                                                 } else {
1807                                                         EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1808                                                 }
1809                                         }
1810
1811                                         pos = tag.start + tag.length - 1;
1812                                         tag = tag.next;
1813                                 }
1814                                 if (pos >= line.text.Length) {
1815                                         if (line.ending != LineEnding.Wrap) {
1816                                                 sb.Append("\\par\n");
1817                                         }
1818                                 }
1819                                 pos = 0;
1820                                 line_no++;
1821                         }
1822
1823                         sb.Append("}\n");
1824
1825                         return sb;
1826                 }
1827                 #endregion      // Private Methods
1828         }
1829 }