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