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