merge -r 58060:58217
[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 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    <pbartok@novell.com>
24 //
25 //
26
27 // NOT COMPLETE
28
29 using System;
30 using System.Collections;
31 using System.ComponentModel;
32 using System.Drawing;
33 using System.IO;
34 using System.Text;
35 using RTF=System.Windows.Forms.RTF;
36
37 namespace System.Windows.Forms {
38         public class RichTextBox : TextBoxBase {
39                 #region Local Variables
40                 internal bool           auto_word_select;
41                 internal int            bullet_indent;
42                 internal bool           can_redo;
43                 internal bool           detect_urls;
44                 internal string         redo_action_name;
45                 internal int            margin_right;
46                 internal string         undo_action_name;
47                 internal float          zoom;
48
49                 private RTF.TextMap     rtf_text_map;
50                 private int             rtf_skip_width;
51                 private int             rtf_skip_count;
52                 private StringBuilder   rtf_line;
53                 private Font            rtf_font;
54                 private SolidBrush      rtf_color;
55                 private RTF.Font        rtf_rtffont;
56                 private int             rtf_rtffont_size;
57                 private FontStyle       rtf_rtfstyle;
58                 private HorizontalAlignment rtf_rtfalign;
59                 private int             rtf_cursor_x;
60                 private int             rtf_cursor_y;
61                 #endregion      // Local Variables
62
63                 #region Public Constructors
64                 public RichTextBox() {
65                         accepts_return = true;
66                         auto_word_select = false;
67                         bullet_indent = 0;
68                         can_redo = false;
69                         detect_urls = true;
70                         max_length = Int32.MaxValue;
71                         redo_action_name = string.Empty;
72                         margin_right = 0;
73                         undo_action_name = string.Empty;
74                         zoom = 1;
75                         base.Multiline = true;
76                         document.CRLFSize = 1;
77
78                         scrollbars = RichTextBoxScrollBars.Both;
79                         alignment = HorizontalAlignment.Left;
80                         LostFocus += new EventHandler(RichTextBox_LostFocus);
81                         GotFocus += new EventHandler(RichTextBox_GotFocus);
82                         BackColor = ThemeEngine.Current.ColorWindow;
83                         ForeColor = ThemeEngine.Current.ColorWindowText;
84                         base.HScrolled += new EventHandler(RichTextBox_HScrolled);
85                         base.VScrolled += new EventHandler(RichTextBox_VScrolled);
86                 }
87                 #endregion      // Public Constructors
88
89                 #region Private & Internal Methods
90                 private void RichTextBox_LostFocus(object sender, EventArgs e) {
91                         has_focus = false;
92                         Invalidate();
93                 }
94
95                 private void RichTextBox_GotFocus(object sender, EventArgs e) {
96                         has_focus = true;
97                         Invalidate();
98                 }
99                 #endregion      // Private & Internal Methods
100
101                 #region Public Instance Properties
102                 public override bool AllowDrop {
103                         get {
104                                 return base.AllowDrop;
105                         }
106
107                         set {
108                                 base.AllowDrop = value;
109                         }
110                 }
111
112                 [DefaultValue(false)]
113                 [Localizable(true)]
114                 public override bool AutoSize {
115                         get {
116                                 return auto_size;
117                         }
118
119                         set {
120                                 base.AutoSize = value;
121                         }
122                 }
123
124                 [DefaultValue(false)]
125                 public bool AutoWordSelection {
126                         get {
127                                 return auto_word_select;
128                         }
129
130                         set {
131                                 auto_word_select = true;
132                         }
133                 }
134
135                 [Browsable(false)]
136                 [EditorBrowsable(EditorBrowsableState.Never)]
137                 public override System.Drawing.Image BackgroundImage {
138                         get {
139                                 return background_image;
140                         }
141
142                         set {
143                                 base.BackgroundImage = value;
144                         }
145                 }
146
147                 [DefaultValue(0)]
148                 [Localizable(true)]
149                 public int BulletIndent {
150                         get {
151                                 return bullet_indent;
152                         }
153
154                         set {
155                                 bullet_indent = value;
156                         }
157                 }
158
159                 [Browsable(false)]
160                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
161                 public bool CanRedo {
162                         get {
163                                 return can_redo;
164                         }
165                 }
166
167                 [DefaultValue(true)]
168                 public bool DetectUrls {
169                         get {
170                                 return detect_urls;
171                         }
172
173                         set {
174                                 detect_urls = true;
175                         }
176                 }
177
178                 public override Font Font {
179                         get {
180                                 return base.Font;
181                         }
182
183                         set {
184                                 if (font != value) {
185                                         Line    start;
186                                         Line    end;
187
188                                         if (auto_size) {
189                                                 if (PreferredHeight != Height) {
190                                                         Height = PreferredHeight;
191                                                 }
192                                         }
193
194                                         base.Font = value;
195
196                                         // Font changes always set the whole doc to that font
197                                         start = document.GetLine(1);
198                                         end = document.GetLine(document.Lines);
199                                         document.FormatText(start, 1, end, end.text.Length, base.Font, new SolidBrush(this.ForeColor));
200                                 }
201                         }
202                 }
203
204                 public override Color ForeColor {
205                         get {
206                                 return base.ForeColor;
207                         }
208
209                         set {
210                                 base.ForeColor = value;
211                         }
212                 }
213
214                 [DefaultValue(Int32.MaxValue)]
215                 public override int MaxLength {
216                         get {
217                                 return base.max_length;
218                         }
219
220                         set {
221                                 base.max_length = value;
222                         }
223                 }
224
225                 [DefaultValue(true)]
226                 public override bool Multiline {
227                         get {
228                                 return multiline;
229                         }
230
231                         set {
232                                 base.Multiline = value;
233                         }
234                 }
235
236                 [Browsable(false)]
237                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
238                 [MonoTODO]
239                 public string RedoActionName {
240                         get {
241                                 return redo_action_name;
242                         }
243                 }
244
245                 [DefaultValue(0)]
246                 [Localizable(true)]
247                 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
248                 public int RightMargin {
249                         get {
250                                 return margin_right;
251                         }
252
253                         set {
254                                 margin_right = value;
255                         }
256                 }
257
258                 [Browsable(false)]
259                 [DefaultValue("")]
260                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
261                 [MonoTODO("Implement setter")]
262                 public string Rtf {
263                         get {
264                                 Line            start_line;
265                                 Line            end_line;
266                                 int             current;
267                                 int             total;
268
269                                 start_line = document.GetLine(1);
270                                 end_line = document.GetLine(document.Lines);
271                                 return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString();
272                         }
273
274                         set {
275                                 MemoryStream    data;
276
277                                 document.Empty();
278                                 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
279
280                                 InsertRTFFromStream(data, 0, 1);
281
282                                 data.Close();
283                         }
284                 }
285
286                 [DefaultValue(RichTextBoxScrollBars.Both)]
287                 [Localizable(true)]
288                 public RichTextBoxScrollBars ScrollBars {
289                         get {
290                                 return scrollbars;
291                         }
292
293                         set {
294                                 scrollbars = value;
295                         }
296                 }
297
298                 [Browsable(false)]
299                 [DefaultValue("")]
300                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
301                 [MonoTODO("Implement setter")]
302                 public string SelectedRtf {
303                         get {
304                                 return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
305                         }
306
307                         set {
308                                 MemoryStream    data;
309                                 int             x;
310                                 int             y;
311                                 Line            line;
312
313                                 if (document.selection_visible) {
314                                         document.ReplaceSelection("");
315                                 }
316
317                                 data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
318                                 InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y);
319                                 data.Close();
320
321                                 line = document.GetLine(y);
322                                 document.SetSelection(document.GetLine(y), x);
323                                 document.PositionCaret(line, x);
324
325                                 OnTextChanged(EventArgs.Empty);
326                         }
327                 }
328
329                 [Browsable(false)]
330                 [DefaultValue("")]
331                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
332                 public override string SelectedText {
333                         get {
334                                 return base.SelectedText;
335                         }
336
337                         set {
338                                 base.SelectedText = value;
339                         }
340                 }
341
342                 [Browsable(false)]
343                 [DefaultValue(HorizontalAlignment.Left)]
344                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
345                 public HorizontalAlignment SelectionAlignment {
346                         get {
347                                 HorizontalAlignment     align;
348                                 Line                    start;
349                                 Line                    end;
350                                 Line                    line;
351
352                                 start = document.ParagraphStart(document.selection_start.line);
353                                 align = start.alignment;
354
355                                 end = document.ParagraphEnd(document.selection_end.line);
356
357                                 line = start;
358
359                                 while (true) {
360                                         if (line.alignment != align) {
361                                                 return HorizontalAlignment.Left;
362                                         }
363
364                                         if (line == end) {
365                                                 break;
366                                         }
367                                         line = document.GetLine(line.line_no + 1);
368                                 }
369
370                                 return align;
371                         }
372
373                         set {
374                                 Line                    start;
375                                 Line                    end;
376                                 Line                    line;
377
378                                 start = document.ParagraphStart(document.selection_start.line);
379
380                                 end = document.ParagraphEnd(document.selection_end.line);
381
382                                 line = start;
383
384                                 while (true) {
385                                         line.alignment = value;
386
387                                         if (line == end) {
388                                                 break;
389                                         }
390                                         line = document.GetLine(line.line_no + 1);
391                                 }
392                                 this.CalculateDocument();
393                         }
394                 }
395
396                 [MonoTODO]
397                 public Color SelectionColor {
398                         get {
399                                 throw new NotImplementedException();
400                         }
401
402                         set {
403                                 int     sel_start;
404                                 int     sel_end;
405
406                                 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
407                                 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
408 Console.WriteLine("FIXME - SelectionColor should not alter font");
409                                 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos, document.selection_start.tag.font, new SolidBrush(value));
410
411                                 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
412                                 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
413
414                                 document.UpdateView(document.selection_start.line, 0);
415                                 document.AlignCaret();
416                         }
417                 }
418
419                 [Browsable(false)]
420                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
421                 public Font SelectionFont {
422                         get {
423                                 Font    font;
424                                 LineTag start;
425                                 LineTag end;
426                                 LineTag tag;
427
428                                 start = document.selection_start.tag;
429                                 end = document.selection_end.tag;
430                                 font = document.selection_start.tag.font;
431
432                                 tag = start;
433                                 while (true) {
434                                         if (!font.Equals(tag.font)) {
435                                                 return null;
436                                         }
437
438                                         if (tag == end) {
439                                                 break;
440                                         }
441
442                                         tag = document.NextTag(tag);
443
444                                         if (tag == null) {
445                                                 break;
446                                         }
447                                 }
448
449                                 return font;
450                         }
451
452                         set {
453                                 int     sel_start;
454                                 int     sel_end;
455
456                                 sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
457                                 sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
458
459                                 document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos, value, document.selection_start.tag.color);
460
461                                 document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
462                                 document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
463
464                                 document.UpdateView(document.selection_start.line, 0);
465                                 document.AlignCaret();
466                                 
467                         }
468                 }
469
470                 [Browsable(false)]
471                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
472                 public RichTextBoxSelectionTypes SelectionType {
473                         get {
474                                 if (document.selection_start == document.selection_end) {
475                                         return RichTextBoxSelectionTypes.Empty;
476                                 }
477
478                                 // Lazy, but works
479                                 if (SelectedText.Length > 1) {
480                                         return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text;
481                                 }
482
483                                 return RichTextBoxSelectionTypes.Text;
484                         }
485                 }
486
487                 [Localizable(true)]
488                 public override string Text {
489                         get {
490                                 return base.Text;
491                         }
492
493                         set {
494                                 base.Text = value;
495                         }
496                 }
497
498                 [Browsable(false)]
499                 public override int TextLength {
500                         get {
501                                 return base.TextLength;
502                         }
503                 }
504
505                 [Browsable(false)]
506                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
507                 public string UndoActionName {
508                         get {
509                                 return undo_action_name;
510                         }
511                 }
512
513                 [Localizable(true)]
514                 [DefaultValue(1)]
515                 public float ZoomFactor {
516                         get {
517                                 return zoom;
518                         }
519
520                         set {
521                                 zoom = value;
522                         }
523                 }
524                 #endregion      // Public Instance Properties
525
526                 #region Protected Instance Properties
527                 protected override CreateParams CreateParams {
528                         get {
529                                 return base.CreateParams;
530                         }
531                 }
532
533                 protected override Size DefaultSize {
534                         get {
535                                 return new Size(100, 96);
536                         }
537                 }
538                 #endregion      // Protected Instance Properties
539
540                 #region Public Instance Methods
541                 public int Find(char[] characterSet) {
542                         return Find(characterSet, -1, -1);
543                 }
544
545                 public int Find(char[] characterSet, int start) {
546                         return Find(characterSet, start, -1);
547                 }
548
549                 public int Find(char[] characterSet, int start, int end) {
550                         Document.Marker start_mark;
551                         Document.Marker end_mark;
552                         Document.Marker result;
553
554                         if (start == -1) {
555                                 document.GetMarker(out start_mark, true);
556                         } else {
557                                 Line line;
558                                 LineTag tag;
559                                 int pos;
560
561                                 start_mark = new Document.Marker();
562
563                                 document.CharIndexToLineTag(start, out line, out tag, out pos);
564                                 start_mark.line = line;
565                                 start_mark.tag = tag;
566                                 start_mark.pos = pos;
567                         }
568
569                         if (end == -1) {
570                                 document.GetMarker(out end_mark, false);
571                         } else {
572                                 Line line;
573                                 LineTag tag;
574                                 int pos;
575
576                                 end_mark = new Document.Marker();
577
578                                 document.CharIndexToLineTag(end, out line, out tag, out pos);
579                                 end_mark.line = line;
580                                 end_mark.tag = tag;
581                                 end_mark.pos = pos;
582                         }
583
584                         if (document.FindChars(characterSet, start_mark, end_mark, out result)) {
585                                 return document.LineTagToCharIndex(result.line, result.pos);
586                         }
587
588                         return -1;
589                 }
590
591                 public int Find(string str) {
592                         return Find(str, -1, -1, RichTextBoxFinds.None);
593                 }
594
595                 public int Find(string str, int start, int end, RichTextBoxFinds options) {
596                         Document.Marker start_mark;
597                         Document.Marker end_mark;
598                         Document.Marker result;
599
600                         if (start == -1) {
601                                 document.GetMarker(out start_mark, true);
602                         } else {
603                                 Line line;
604                                 LineTag tag;
605                                 int pos;
606
607                                 start_mark = new Document.Marker();
608
609                                 document.CharIndexToLineTag(start, out line, out tag, out pos);
610
611                                 start_mark.line = line;
612                                 start_mark.tag = tag;
613                                 start_mark.pos = pos;
614                         }
615
616                         if (end == -1) {
617                                 document.GetMarker(out end_mark, false);
618                         } else {
619                                 Line line;
620                                 LineTag tag;
621                                 int pos;
622
623                                 end_mark = new Document.Marker();
624
625                                 document.CharIndexToLineTag(end, out line, out tag, out pos);
626
627                                 end_mark.line = line;
628                                 end_mark.tag = tag;
629                                 end_mark.pos = pos;
630                         }
631
632                         if (document.Find(str, start_mark, end_mark, out result, options)) {
633                                 return document.LineTagToCharIndex(result.line, result.pos);
634                         }
635
636                         return -1;
637                 }
638
639                 public int Find(string str, int start, RichTextBoxFinds options) {
640                         return Find(str, start, -1, options);
641                 }
642
643                 public int Find(string str, RichTextBoxFinds options) {
644                         return Find(str, -1, -1, options);
645                 }
646
647                 public char GetCharFromPosition(Point pt) {
648                         LineTag tag;
649                         int     pos;
650
651                         PointToTagPos(pt, out tag, out pos);
652
653                         if (pos >= tag.line.text.Length) {
654                                 return '\n';
655                         }
656
657                         return tag.line.text[pos];
658                         
659                 }
660
661                 public int GetCharIndexFromPosition(Point pt) {
662                         LineTag tag;
663                         int     pos;
664
665                         PointToTagPos(pt, out tag, out pos);
666
667                         return document.LineTagToCharIndex(tag.line, pos);
668                 }
669
670                 public int GetLineFromCharIndex(int index) {
671                         Line    line;
672                         LineTag tag;
673                         int     pos;
674
675                         document.CharIndexToLineTag(index, out line, out tag, out pos);
676
677                         return line.LineNo - 1;
678                 }
679
680                 public Point GetPositionFromCharIndex(int index) {
681                         Line    line;
682                         LineTag tag;
683                         int     pos;
684
685                         document.CharIndexToLineTag(index, out line, out tag, out pos);
686
687                         return new Point((int)line.widths[pos] + 1, line.Y + 1);
688                 }
689
690                 public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
691                         RTF.RTF rtf;    // Not 'using SWF.RTF' to avoid ambiguities with font and color
692
693                         document.Empty();
694
695                         // FIXME - ignoring unicode
696                         if (fileType == RichTextBoxStreamType.PlainText) {
697                                 StringBuilder   sb;
698                                 int             count;
699                                 byte[]          buffer;
700
701                                 try {
702                                         sb = new StringBuilder((int)data.Length);
703                                         buffer = new byte[1024];
704                                 }
705
706                                 catch {
707                                         throw new IOException("Not enough memory to load document");
708                                 }
709
710                                 count = 0;
711                                 while (count < data.Length) {
712                                         count += data.Read(buffer, count, 1024);
713                                         sb.Append(buffer);
714                                 }
715                                 base.Text = sb.ToString();
716                                 return;
717                         }
718
719                         InsertRTFFromStream(data, 0, 1);
720                 }
721
722                 [MonoTODO("Make smarter RTF detection")]
723                 public void LoadFile(string path) {
724                         if (path.EndsWith(".rtf")) {
725                                 LoadFile(path, RichTextBoxStreamType.RichText);
726                         } else {
727                                 LoadFile(path, RichTextBoxStreamType.PlainText);
728                         }
729                 }
730
731                 public void LoadFile(string path, RichTextBoxStreamType fileType) {
732                         FileStream      data;
733
734                         data = null;
735
736                         try {
737                                 data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024);
738                                 LoadFile(data, fileType);
739                         }
740
741                         catch {
742                                 throw new IOException("Could not open file " + path);
743                         }
744
745                         finally {
746                                 if (data != null) {
747                                         data.Close();
748                                 }
749                         }
750                 }
751
752                 public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
753                         Encoding        encoding;
754                         int             i;
755                         Byte[]          bytes;
756
757
758                         if (fileType == RichTextBoxStreamType.UnicodePlainText) {
759                                 encoding = Encoding.Unicode;
760                         } else {
761                                 encoding = Encoding.ASCII;
762                         }
763
764                         switch(fileType) {
765                                 case RichTextBoxStreamType.PlainText: 
766                                 case RichTextBoxStreamType.TextTextOleObjs: 
767                                 case RichTextBoxStreamType.UnicodePlainText: {
768                                         if (!multiline) {
769                                                 bytes = encoding.GetBytes(document.Root.text.ToString());
770                                                 data.Write(bytes, 0, bytes.Length);
771                                                 return;
772                                         }
773
774                                         for (i = 1; i < document.Lines; i++) {
775                                                 bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
776                                                 data.Write(bytes, 0, bytes.Length);
777                                         }
778                                         bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
779                                         data.Write(bytes, 0, bytes.Length);
780                                         return;
781                                 }
782                         }
783
784                         // If we're here we're saving RTF
785                         Line            start_line;
786                         Line            end_line;
787                         StringBuilder   rtf;
788                         int             current;
789                         int             total;
790
791                         start_line = document.GetLine(1);
792                         end_line = document.GetLine(document.Lines);
793                         rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length);
794                         total = rtf.Length;
795                         bytes = new Byte[4096];
796
797                         // Let's chunk it so we don't use up all memory...
798                         for (i = 0; i < total; i += 1024) {
799                                 if ((i + 1024) < total) {
800                                         current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0);
801                                 } else {
802                                         current = total - i;
803                                         current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0);
804                                 }
805                                 data.Write(bytes, 0, current);
806                         }
807                 }
808
809                 public void SaveFile(string path) {
810                         if (path.EndsWith(".rtf")) {
811                                 SaveFile(path, RichTextBoxStreamType.RichText);
812                         } else {
813                                 SaveFile(path, RichTextBoxStreamType.PlainText);
814                         }
815                 }
816
817                 public void SaveFile(string path, RichTextBoxStreamType fileType) {
818                         FileStream      data;
819
820                         data = null;
821
822 //                      try {
823                                 data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false);
824                                 SaveFile(data, fileType);
825 //                      }
826
827 //                      catch {
828 //                              throw new IOException("Could not write document to file " + path);
829 //                      }
830
831 //                      finally {
832                                 if (data != null) {
833                                         data.Close();
834                                 }
835 //                      }
836                 }
837
838                 #endregion      // Public Instance Methods
839
840                 #region Protected Instance Methods
841                 protected override void OnBackColorChanged(EventArgs e) {
842                         base.OnBackColorChanged (e);
843                 }
844
845                 protected override void OnContextMenuChanged(EventArgs e) {
846                         base.OnContextMenuChanged (e);
847                 }
848
849                 protected override void OnHandleCreated(EventArgs e) {
850                         base.OnHandleCreated (e);
851                 }
852
853                 protected override void OnHandleDestroyed(EventArgs e) {
854                         base.OnHandleDestroyed (e);
855                 }
856
857                 protected virtual void OnHScroll(EventArgs e) {
858                         if (HScroll != null) {
859                                 HScroll(this, e);
860                         }
861                 }
862
863                 protected override void OnRightToLeftChanged(EventArgs e) {
864                         base.OnRightToLeftChanged (e);
865                 }
866
867                 protected override void OnSystemColorsChanged(EventArgs e) {
868                         base.OnSystemColorsChanged (e);
869                 }
870
871                 protected override void OnTextChanged(EventArgs e) {
872                         base.OnTextChanged (e);
873                 }
874
875                 protected virtual void OnVScroll(EventArgs e) {
876                         if (VScroll != null) {
877                                 VScroll(this, e);
878                         }
879                 }
880
881                 protected override void WndProc(ref Message m) {
882                         base.WndProc (ref m);
883                 }
884                 #endregion      // Protected Instance Methods
885
886                 #region Events
887                 [Browsable(false)]
888                 [EditorBrowsable(EditorBrowsableState.Never)]
889                 public event EventHandler                       BackgroundImageChanged;
890
891                 public event ContentsResizedEventHandler        ContentsResized;
892
893                 [Browsable(false)]
894                 [EditorBrowsable(EditorBrowsableState.Never)]
895                 public event EventHandler                       DoubleClick;
896
897                 [Browsable(false)]
898                 [EditorBrowsable(EditorBrowsableState.Never)]
899                 public event DragEventHandler                   DragDrop;
900
901                 [Browsable(false)]
902                 [EditorBrowsable(EditorBrowsableState.Never)]
903                 public event DragEventHandler                   DragEnter;
904
905                 [Browsable(false)]
906                 [EditorBrowsable(EditorBrowsableState.Never)]
907                 public event EventHandler                       DragLeave;
908
909                 [Browsable(false)]
910                 [EditorBrowsable(EditorBrowsableState.Never)]
911                 public event DragEventHandler                   DragOver;
912
913                 [Browsable(false)]
914                 [EditorBrowsable(EditorBrowsableState.Never)]
915                 public event GiveFeedbackEventHandler           GiveFeedback;
916
917                 public event EventHandler                       HScroll;
918                 public event EventHandler                       ImeChange;
919                 public event LinkClickedEventHandler            LinkClicked;
920                 public event EventHandler                       Protected;
921
922                 [Browsable(false)]
923                 [EditorBrowsable(EditorBrowsableState.Never)]
924                 public event QueryContinueDragEventHandler      QueryContinueDrag;
925                 public event EventHandler                       SelectionChanged;
926                 public event EventHandler                       VScroll;
927                 #endregion      // Events
928
929                 #region Private Methods
930                 private void HandleControl(RTF.RTF rtf) {
931                         switch(rtf.Major) {
932                                 case RTF.Major.Unicode: {
933                                         switch(rtf.Minor) {
934                                                 case Minor.UnicodeCharBytes: {
935                                                         rtf_skip_width = rtf.Param;
936                                                         break;
937                                                 }
938
939                                                 case Minor.UnicodeChar: {
940                                                         rtf_skip_count += rtf_skip_width;
941                                                         rtf_line.Append((char)rtf.Param);
942                                                         break;
943                                                 }
944                                         }
945                                         break;
946                                 }
947
948                                 case RTF.Major.Destination: {
949                                         Console.Write("[Got Destination control {0}]", rtf.Minor);
950                                         rtf.SkipGroup();
951                                         break;
952                                 }
953
954                                 case RTF.Major.CharAttr: {
955                                         switch(rtf.Minor) {
956                                                 case Minor.ForeColor: {
957                                                         System.Windows.Forms.RTF.Color  color;
958
959                                                         color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
960                                                         if (color != null) {
961                                                                 FlushText(false);
962                                                                 if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
963                                                                         this.rtf_color = new SolidBrush(ForeColor);
964                                                                 } else {
965                                                                         this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
966                                                                 }
967                                                         }
968                                                         break;
969                                                 }
970
971                                                 case Minor.FontSize: {
972                                                         this.rtf_rtffont_size = rtf.Param / 2;
973                                                         break;
974                                                 }
975
976                                                 case Minor.FontNum: {
977                                                         System.Windows.Forms.RTF.Font   font;
978
979                                                         font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
980                                                         if (font != null) {
981                                                                 FlushText(false);
982                                                                 this.rtf_rtffont = font;
983                                                         }
984                                                         break;
985                                                 }
986
987                                                 case Minor.Plain: {
988                                                         FlushText(false);
989                                                         rtf_rtfstyle = FontStyle.Regular;
990                                                         break;
991                                                 }
992
993                                                 case Minor.Bold: {
994                                                         FlushText(false);
995                                                         if (rtf.Param == RTF.RTF.NoParam) {
996                                                                 rtf_rtfstyle |= FontStyle.Bold;
997                                                         } else {
998                                                                 rtf_rtfstyle &= ~FontStyle.Bold;
999                                                         }
1000                                                         break;
1001                                                 }
1002
1003                                                 case Minor.Italic: {
1004                                                         FlushText(false);
1005                                                         if (rtf.Param == RTF.RTF.NoParam) {
1006                                                                 rtf_rtfstyle |= FontStyle.Italic;
1007                                                         } else {
1008                                                                 rtf_rtfstyle &= ~FontStyle.Italic;
1009                                                         }
1010                                                         break;
1011                                                 }
1012
1013                                                 case Minor.StrikeThru: {
1014                                                         FlushText(false);
1015                                                         if (rtf.Param == RTF.RTF.NoParam) {
1016                                                                 rtf_rtfstyle |= FontStyle.Strikeout;
1017                                                         } else {
1018                                                                 rtf_rtfstyle &= ~FontStyle.Strikeout;
1019                                                         }
1020                                                         break;
1021                                                 }
1022
1023                                                 case Minor.Underline: {
1024                                                         FlushText(false);
1025                                                         if (rtf.Param == RTF.RTF.NoParam) {
1026                                                                 rtf_rtfstyle |= FontStyle.Underline;
1027                                                         } else {
1028                                                                 rtf_rtfstyle &= ~FontStyle.Underline;
1029                                                         }
1030                                                         break;
1031                                                 }
1032
1033                                                 case Minor.NoUnderline: {
1034                                                         FlushText(false);
1035                                                         rtf_rtfstyle &= ~FontStyle.Underline;
1036                                                         break;
1037                                                 }
1038                                         }
1039                                         break;
1040                                 }
1041
1042                                 case RTF.Major.SpecialChar: {
1043                                         Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1044                                         SpecialChar(rtf);
1045                                         break;
1046                                 }
1047                         }
1048                 }
1049
1050                 private void SpecialChar(RTF.RTF rtf) {
1051                         switch(rtf.Minor) {
1052                                 case Minor.Page:
1053                                 case Minor.Sect:
1054                                 case Minor.Row:
1055                                 case Minor.Line:
1056                                 case Minor.Par: {
1057                                         FlushText(true);
1058                                         break;
1059                                 }
1060
1061                                 case Minor.Cell: {
1062                                         Console.Write(" ");
1063                                         break;
1064                                 }
1065
1066                                 case Minor.NoBrkSpace: {
1067                                         Console.Write(" ");
1068                                         break;
1069                                 }
1070
1071                                 case Minor.Tab: {
1072                                         Console.Write("\t");
1073                                         break;
1074                                 }
1075
1076                                 case Minor.NoBrkHyphen: {
1077                                         Console.Write("-");
1078                                         break;
1079                                 }
1080
1081                                 case Minor.Bullet: {
1082                                         Console.Write("*");
1083                                         break;
1084                                 }
1085
1086                                 case Minor.EmDash: {
1087                                         Console.Write("\97");
1088                                         break;
1089                                 }
1090
1091                                 case Minor.EnDash: {
1092                                         Console.Write("\96");
1093                                         break;
1094                                 }
1095
1096                                 case Minor.LQuote: {
1097                                         Console.Write("\91");
1098                                         break;
1099                                 }
1100
1101                                 case Minor.RQuote: {
1102                                         Console.Write("\92");
1103                                         break;
1104                                 }
1105
1106                                 case Minor.LDblQuote: {
1107                                         Console.Write("\93");
1108                                         break;
1109                                 }
1110
1111                                 case Minor.RDblQuote: {
1112                                         Console.Write("\94");
1113                                         break;
1114                                 }
1115
1116                                 default: {
1117                                         rtf.SkipGroup();
1118                                         break;
1119                                 }
1120                         }
1121                 }
1122
1123                 private void HandleText(RTF.RTF rtf) {
1124                         if (rtf_skip_count > 0) {
1125                                 rtf_skip_count--;
1126                                 return;
1127                         }
1128
1129                         if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1130                                 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1131                         } else {
1132                                 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1133                                         rtf_line.Append((char)rtf.Major);
1134                                 } else {
1135                                         //rtf_line.Append((char)rtf.Major);
1136                                         Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1137                                 }
1138                         }
1139                 }
1140
1141                 private void FlushText(bool newline) {
1142                         int             length;
1143                         Font            font;
1144
1145                         length = rtf_line.Length;
1146                         if (length == 0) {
1147                                 return;
1148                         }
1149
1150                         if (rtf_rtffont != null) {
1151                                 font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
1152                         } else {
1153                                 font = this.Font;
1154                         }
1155
1156                         if (rtf_cursor_x == 0) {
1157                                 document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color);
1158                         } else {
1159                                 Line    line;
1160
1161                                 line = document.GetLine(rtf_cursor_y);
1162                                 document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
1163                                 document.FormatText(line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, font, rtf_color); // FormatText is 1-based
1164                         }
1165
1166                         if (newline) {
1167                                 rtf_cursor_x = 0;
1168                                 rtf_cursor_y++;
1169                         } else {
1170                                 rtf_cursor_x += length;
1171                         }
1172                         rtf_line.Length = 0;    // Empty line
1173                 }
1174
1175                 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) {
1176                         int     x;
1177                         int     y;
1178
1179                         InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y);
1180                 }
1181                 private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y) {
1182                         RTF.RTF         rtf;
1183
1184                         rtf = new RTF.RTF(data);
1185
1186                         // Prepare
1187                         rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
1188                         rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
1189
1190                         rtf_skip_width = 0;
1191                         rtf_skip_count = 0;
1192                         rtf_line = new StringBuilder();
1193                         rtf_font = Font;
1194                         rtf_color = new SolidBrush(ForeColor);
1195                         rtf_rtffont_size = this.Font.Height;
1196                         rtf_rtfalign = HorizontalAlignment.Left;
1197                         rtf_rtffont = null;
1198                         rtf_cursor_x = cursor_x;
1199                         rtf_cursor_y = cursor_y;
1200
1201                         rtf_text_map = new RTF.TextMap();
1202                         RTF.TextMap.SetupStandardTable(rtf_text_map.Table);
1203
1204                         try {
1205                                 rtf.Read();     // That's it
1206                                 FlushText(false);
1207                         }
1208
1209                         catch (RTF.RTFException) {
1210                                 // Seems to be plain text...
1211                                 
1212                         }
1213
1214                         to_x = rtf_cursor_x;
1215                         to_y = rtf_cursor_y;
1216
1217                         document.RecalculateDocument(CreateGraphics(), cursor_y, document.Lines, false);
1218                         document.Invalidate(document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1);
1219                 }
1220
1221                 private void RichTextBox_HScrolled(object sender, EventArgs e) {
1222                         OnHScroll(e);
1223                 }
1224
1225                 private void RichTextBox_VScrolled(object sender, EventArgs e) {
1226                         OnVScroll(e);
1227                 }
1228
1229                 private void PointToTagPos(Point pt, out LineTag tag, out int pos) {
1230                         Point p;
1231
1232                         p = pt;
1233
1234                         if (p.X >= document.ViewPortWidth) {
1235                                 p.X = document.ViewPortWidth - 1;
1236                         } else if (p.X < 0) {
1237                                 p.X = 0;
1238                         }
1239
1240                         if (p.Y >= document.ViewPortHeight) {
1241                                 p.Y = document.ViewPortHeight - 1;
1242                         } else if (p.Y < 0) {
1243                                 p.Y = 0;
1244                         }
1245
1246                         tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos);
1247                 }
1248
1249                 private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) {
1250                         if (prev_index != font_index) {
1251                                 rtf.Append(String.Format("\\f{0}", font_index));        // Font table entry
1252                         }
1253
1254                         if ((prev_font == null) || (prev_font.Height != font.Height)) {
1255                                 rtf.Append(String.Format("\\fs{0}", font.Height * 2));          // Font size
1256                         }
1257
1258                         if ((prev_font == null) || (font.Bold != prev_font.Bold)) {
1259                                 if (font.Bold) {
1260                                         rtf.Append("\\b");
1261                                 } else {
1262                                         if (prev_font != null) {
1263                                                 rtf.Append("\\b0");
1264                                         }
1265                                 }
1266                         }
1267
1268                         if ((prev_font == null) || (font.Italic != prev_font.Italic)) {
1269                                 if (font.Italic) {
1270                                         rtf.Append("\\i");
1271                                 } else {
1272                                         if (prev_font != null) {
1273                                                 rtf.Append("\\i0");
1274                                         }
1275                                 }
1276                         }
1277
1278                         if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) {
1279                                 if (font.Strikeout) {
1280                                         rtf.Append("\\strike");
1281                                 } else {
1282                                         if (prev_font != null) {
1283                                                 rtf.Append("\\strike0");
1284                                         }
1285                                 }
1286                         }
1287
1288                         if ((prev_font == null) || (font.Underline != prev_font.Underline)) {
1289                                 if (font.Underline) {
1290                                         rtf.Append("\\ul");
1291                                 } else {
1292                                         if (prev_font != null) {
1293                                                 rtf.Append("\\ul0");
1294                                         }
1295                                 }
1296                         }
1297                 }
1298
1299                 [MonoTODO("Emit unicode and other special characters properly")]
1300                 private void EmitRTFText(StringBuilder rtf, string text) {
1301                         rtf.Append(text);
1302                 }
1303
1304                 private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) {
1305                         StringBuilder   sb;
1306                         ArrayList       fonts;
1307                         ArrayList       colors;
1308                         Color           color;
1309                         Font            font;
1310                         Line            line;
1311                         LineTag         tag;
1312                         int             pos;
1313                         int             line_no;
1314                         int             line_len;
1315                         int             i;
1316                         int             length;
1317
1318                         sb = new StringBuilder();
1319                         fonts = new ArrayList(10);
1320                         colors = new ArrayList(10);
1321
1322                         // Two runs, first we parse to determine tables;
1323                         // and unlike most of our processing here we work on tags
1324
1325                         line = start_line;
1326                         line_no = start_line.line_no;
1327                         pos = start_pos;
1328
1329                         // Add default font and color; to optimize document content we don't
1330                         // use this.Font and this.ForeColor but the font/color from the first tag
1331                         tag = LineTag.FindTag(start_line, pos);
1332                         font = tag.font;
1333                         color = ((SolidBrush)tag.color).Color;
1334                         fonts.Add(font.Name);
1335                         colors.Add(color);
1336
1337                         while (line_no <= end_line.line_no) {
1338                                 line = document.GetLine(line_no);
1339                                 tag = LineTag.FindTag(line, pos);
1340
1341                                 if (line_no != end_line.line_no) {
1342                                         line_len = line.text.Length;
1343                                 } else {
1344                                         line_len = end_pos;
1345                                 }
1346
1347                                 while (pos < line_len) {
1348                                         if (tag.font.Name != font.Name) {
1349                                                 font = tag.font;
1350                                                 if (!fonts.Contains(font.Name)) {
1351                                                         fonts.Add(font.Name);
1352                                                 }
1353                                         }
1354
1355                                         if (((SolidBrush)tag.color).Color != color) {
1356                                                 color = ((SolidBrush)tag.color).Color;
1357                                                 if (!colors.Contains(color)) {
1358                                                         colors.Add(color);
1359                                                 }
1360                                         }
1361
1362                                         pos += tag.length;
1363                                         tag = tag.next;
1364                                 }
1365                                 pos = 0;
1366                                 line_no++;
1367                         }
1368
1369                         // We have the tables, emit the header
1370                         sb.Append("{\\rtf1\\ansi");
1371                         sb.Append("\\ansicpg1252");     // FIXME - is this correct?
1372
1373                         // Default Font
1374                         sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
1375
1376                         // Default Language 
1377                         sb.Append("\\deflang1033\n");   // FIXME - always 1033?
1378
1379                         // Emit the font table
1380                         sb.Append("{\\fonttbl");
1381                         for (i = 0; i < fonts.Count; i++) {
1382                                 sb.Append(String.Format("{{\\f{0}", i));        // {Font 
1383                                 sb.Append("\\fnil");                    // Family
1384                                 sb.Append("\\fcharset0 ");              // Charset ANSI<space>
1385                                 sb.Append((string)fonts[i]);            // Font name
1386                                 sb.Append(";}");                        // }
1387                         }
1388                         sb.Append("}\n");
1389
1390                         // Emit the color table (if needed)
1391                         if (colors.Count > 1) {
1392                                 sb.Append("{\\colortbl ");                      // Header and NO! default color
1393                                 for (i = 0; i < colors.Count; i++) {
1394                                         sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R));
1395                                         sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G));
1396                                         sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
1397                                         sb.Append(";");
1398                                 }
1399                                 sb.Append("}\n");
1400                         }
1401
1402                         sb.Append("{\\*\\generator Mono RichTextBox;}");
1403                         // Emit initial paragraph settings
1404                         tag = LineTag.FindTag(start_line, start_pos);
1405                         sb.Append("\\pard");    // Reset to default paragraph properties
1406                         EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font);    // Font properties
1407                         sb.Append(" ");         // Space separator
1408
1409                         font = tag.font;
1410                         color = (Color)colors[0];
1411                         line = start_line;
1412                         line_no = start_line.line_no;
1413                         pos = start_pos;
1414
1415                         while (line_no <= end_line.line_no) {
1416                                 line = document.GetLine(line_no);
1417                                 tag = LineTag.FindTag(line, pos);
1418
1419                                 if (line_no != end_line.line_no) {
1420                                         line_len = line.text.Length;
1421                                 } else {
1422                                         line_len = end_pos;
1423                                 }
1424
1425                                 while (pos < line_len) {
1426                                         length = sb.Length;
1427
1428                                         if (tag.font != font) {
1429                                                 EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
1430                                                 font = tag.font;
1431                                         }
1432
1433                                         if (((SolidBrush)tag.color).Color != color) {
1434                                                 color = ((SolidBrush)tag.color).Color;
1435                                                 sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
1436                                         }
1437                                         if (length != sb.Length) {
1438                                                 sb.Append(" "); // Emit space to separate keywords from text
1439                                         }
1440
1441                                         // Emit the string itself
1442                                         if (line_no != end_line.line_no) {
1443                                                 EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1444                                         } else {
1445                                                 if (end_pos < (tag.start + tag.length - 1)) {
1446                                                         // Emit partial tag only, end_pos is inside this tag
1447                                                         EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
1448                                                 } else {
1449                                                         EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
1450                                                 }
1451                                         }
1452
1453                                         pos += tag.length;
1454                                         tag = tag.next;
1455                                 }
1456                                 if (!line.soft_break) {
1457                                         sb.Append("\\par\n");
1458                                 }
1459                                 pos = 0;
1460                                 line_no++;
1461                         }
1462
1463                         sb.Append("}\n");
1464
1465                         return sb;
1466                 }
1467                 #endregion      // Private Methods
1468         }
1469 }