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