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