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