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