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