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