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