New tests.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / RichTextBox.cs
index 9de392fb2fbc4a13129aeeee8f13c3c3d6ccff1d..1db7f29a519e0819d7696faeb9cff1a41f001da9 100644 (file)
@@ -411,15 +411,21 @@ namespace System.Windows.Forms {
                                int cursor_x = document.selection_start.pos;
                                int cursor_y = document.selection_start.line.line_no;
 
-                               // If we have an empty just added line, tell our code to re-use it
+                               // The RFT parser by default, when finds our x cursor in 0, it thinks if needs to
+                               // add a new line; but in *this* scenario the line is already created, so force it to reuse it.
                                // Hackish, but works without touching the heart of the buggy parser.
-                               if (cursor_x == 0 && document.GetLine (cursor_y).text.Length == 0)
+                               if (cursor_x == 0)
                                        reuse_line = true;
 
                                InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
                                data.Close();
 
-                               document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
+                               int nl_length = document.LineEndingLength (XplatUI.RunningOnUnix ? LineEnding.Rich : LineEnding.Hard);
+                               document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * nl_length, 
+                                               out line, out tag, out sel_start);
+                               if (sel_start >= line.text.Length)
+                                       sel_start = line.text.Length -1;
+
                                document.SetSelection(line, sel_start);
                                document.PositionCaret(line, sel_start);
                                document.DisplayCaret();
@@ -437,6 +443,8 @@ namespace System.Windows.Forms {
                        }
 
                        set {
+                               // TextBox/TextBoxBase don't set Modified in this same property
+                               Modified = true;
                                base.SelectedText = value;
                        }
                }
@@ -1940,9 +1948,55 @@ namespace System.Windows.Forms {
                        }
                }
 
-               [MonoInternalNote ("Emit unicode and other special characters properly")]
+               static readonly char [] ReservedRTFChars = new char [] { '\\', '{', '}' };
+
                private void EmitRTFText(StringBuilder rtf, string text) {
-                       rtf.Append(text);
+                       int start = rtf.Length;
+                       int count = text.Length;
+
+                       // First emit simple unicode chars as escaped
+                       EmitEscapedUnicode (rtf, text);
+
+                       // This method emits user text *only*, so it's safe to escape any reserved rtf chars
+                       // Escape '\' first, since it is used later to escape the other chars
+                       if (text.IndexOfAny (ReservedRTFChars) > -1) {
+                               rtf.Replace ("\\", "\\\\", start, count);
+                               rtf.Replace ("{", "\\{", start, count);
+                               rtf.Replace ("}", "\\}", start, count);
+                       }
+               }
+
+               // The chars to be escaped use "\'" + its hexadecimal value.
+               private void EmitEscapedUnicode (StringBuilder sb, string text)
+               {
+                       int pos;
+                       int start = 0;
+
+                       while ((pos = IndexOfNonAscii (text, start)) > -1) {
+                               sb.Append (text, start, pos - start);
+
+                               int n = (int)text [pos];
+                               sb.Append ("\\'");
+                               sb.Append (n.ToString ("X"));
+
+                               start = pos + 1;
+                       }
+
+                       // Append remaining (maybe all) the text value.
+                       if (start < text.Length)
+                               sb.Append (text, start, text.Length - start);
+               }
+
+               // MS seems to be escaping values larger than 0x80
+               private int IndexOfNonAscii (string text, int startIndex)
+               {
+                       for (int i = startIndex; i < text.Length; i++) {
+                               int n = (int)text [i];
+                               if (n < 0 || n >= 0x80)
+                                       return i;
+                       }
+
+                       return -1;
                }
 
                // start_pos and end_pos are 0-based