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