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