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