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