internal bool auto_word_select;
internal int bullet_indent;
internal bool detect_urls;
+ private bool reuse_line; // Sometimes we are loading text with already available lines
internal int margin_right;
internal float zoom;
private StringBuilder rtf_line;
auto_size = false;
auto_word_select = false;
bullet_indent = 0;
- max_length = Int32.MaxValue;
+ base.MaxLength = Int32.MaxValue;
margin_right = 0;
zoom = 1;
base.Multiline = true;
return backColor;
}
+ internal override void RaiseSelectionChanged()
+ {
+ OnSelectionChanged (EventArgs.Empty);
+ }
+
private void RichTextBox_LostFocus(object sender, EventArgs e) {
Invalidate();
}
}
#if NET_2_0
- [MonoTODO ("Stub")]
+ [MonoTODO ("Stub, does nothing")]
[DefaultValue (false)]
public bool EnableAutoDragDrop {
get { return enable_auto_drag_drop; }
}
#if NET_2_0
- [MonoTODO ("Stub")]
+ [MonoTODO ("Stub, does nothing")]
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public RichTextBoxLanguageOptions LanguageOption {
[DefaultValue(Int32.MaxValue)]
public override int MaxLength {
- get {
- return base.max_length;
- }
-
- set {
- base.max_length = value;
- }
+ get { return base.MaxLength; }
+ set { base.MaxLength = value; }
}
[DefaultValue(true)]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [MonoTODO]
public string RedoActionName {
get {
return document.undo.RedoActionName;
}
#if NET_2_0
- [MonoTODO ("Stub")]
+ [MonoTODO ("Stub, does nothing")]
[Browsable (false)]
[DefaultValue (true)]
[EditorBrowsable (EditorBrowsableState.Never)]
[DefaultValue(0)]
[Localizable(true)]
- [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
+ [MonoTODO ("Stub, does nothing")]
+ [MonoInternalNote ("Teach TextControl.RecalculateLine to consider the right margin as well")]
public int RightMargin {
get {
return margin_right;
sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
- InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y, out chars);
+ int cursor_x = document.selection_start.pos;
+ int cursor_y = document.selection_start.line.line_no;
+
+ // 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)
+ 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();
}
set {
+ // TextBox/TextBoxBase don't set Modified in this same property
+ Modified = true;
base.SelectedText = value;
}
}
}
#if NET_2_0
- [MonoTODO ("Stub")]
+ [MonoTODO ("Stub, does nothing")]
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public Color SelectionBackColor {
[Browsable(false)]
[DefaultValue(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [MonoTODO]
+ [MonoTODO ("Stub, does nothing")]
public bool SelectionBullet {
get {
return false;
[Browsable(false)]
[DefaultValue(0)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [MonoTODO]
+ [MonoTODO ("Stub, does nothing")]
public int SelectionCharOffset {
get {
return 0;
[Browsable(false)]
[DefaultValue(0)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [MonoTODO]
+ [MonoTODO ("Stub, does nothing")]
public int SelectionHangingIndent {
get {
return 0;
[Browsable(false)]
[DefaultValue(0)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [MonoTODO]
+ [MonoTODO ("Stub, does nothing")]
public int SelectionIndent {
get {
return 0;
[Browsable(false)]
[DefaultValue(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [MonoTODO]
+ [MonoTODO ("Stub, does nothing")]
public bool SelectionProtected {
get {
return false;
[Browsable(false)]
[DefaultValue(0)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [MonoTODO]
+ [MonoTODO ("Stub, does nothing")]
public int SelectionRightIndent {
get {
return 0;
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- [MonoTODO]
+ [MonoTODO ("Stub, does nothing")]
public int[] SelectionTabs {
get {
return new int[0];
}
[DefaultValue(false)]
- [MonoTODO]
+ [MonoTODO ("Stub, does nothing")]
public bool ShowSelectionMargin {
get {
return false;
sb.Append (buffer, 0, charsRead);
charsRead = sr.Read (buffer, 0, buffer.Length);
}
+
+ // Remove the EOF converted to an extra EOL by the StreamReader
+ if (sb.Length > 0 && sb [sb.Length - 1] == '\n')
+ sb.Remove (sb.Length - 1, 1);
+
base.Text = sb.ToString();
return;
}
ScrollToCaret ();
}
- [MonoTODO("Make smarter RTF detection?")]
public void LoadFile(string path) {
- if (path.EndsWith(".rtf")) {
- LoadFile(path, RichTextBoxStreamType.RichText);
- } else {
- LoadFile(path, RichTextBoxStreamType.PlainText);
- }
+ LoadFile (path, RichTextBoxStreamType.RichText);
}
public void LoadFile(string path, RichTextBoxStreamType fileType) {
}
for (i = 1; i < document.Lines; i++) {
- bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
+ // Normalize the new lines to the system ones
+ string line_text = document.GetLine (i).TextWithoutEnding () + Environment.NewLine;
+ bytes = encoding.GetBytes(line_text);
data.Write(bytes, 0, bytes.Length);
}
bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
eh (this, e);
}
- [MonoTODO("Determine when to call this")]
+ [MonoTODO ("Stub, never called")]
protected virtual void OnImeChange(EventArgs e) {
EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
if (eh != null)
remove { base.QueryContinueDrag -= value; }
}
- [MonoTODO("Currently does not ever fire")]
+ [MonoTODO ("Event never raised")]
public event EventHandler SelectionChanged {
add { Events.AddHandler (SelectionChangedEvent, value); }
remove { Events.RemoveHandler (SelectionChangedEvent, value); }
}
}
- [MonoTODO("Add QuadJust support for justified alignment")]
+ [MonoInternalNote ("Add QuadJust support for justified alignment")]
private void HandleControl(RTF.RTF rtf) {
switch(rtf.Major) {
case RTF.Major.Unicode: {
rtf_chars += rtf_line.Length;
-
-
- if (rtf_cursor_x == 0) {
- if (newline && rtf_line.ToString ().EndsWith ("\n") == false)
- rtf_line.Append ("\n");
+ // Try to re-use if we are told so - this usually happens when we are inserting a flow of rtf text
+ // with an already alive line.
+ if (rtf_cursor_x == 0 && !reuse_line) {
+ if (newline && rtf_line.ToString ().EndsWith (Environment.NewLine) == false)
+ rtf_line.Append (Environment.NewLine);
document.Add (rtf_cursor_y, rtf_line.ToString (), rtf_style.rtf_rtfalign, font, rtf_style.rtf_color,
newline ? LineEnding.Rich : LineEnding.Wrap);
FormatSpecified.Font | FormatSpecified.Color);
}
if (newline) {
- document.Split (line, rtf_cursor_x + length);
line = document.GetLine (rtf_cursor_y);
line.ending = LineEnding.Rich;
- if (line.Text.EndsWith ("\n") == false)
- line.Text += "\n";
+ if (line.Text.EndsWith (Environment.NewLine) == false)
+ line.Text += Environment.NewLine;
}
+
+ reuse_line = false; // sanity assignment - in this case we have already re-used one line.
}
if (newline) {
}
}
- [MonoTODO("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
sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
// Default Language
- sb.Append("\\deflang1033\n"); // FIXME - always 1033?
+ sb.Append("\\deflang1033" + Environment.NewLine); // FIXME - always 1033?
// Emit the font table
sb.Append("{\\fonttbl");
sb.Append((string)fonts[i]); // Font name
sb.Append(";}"); // }
}
- sb.Append("}\n");
+ sb.Append("}");
+ sb.Append(Environment.NewLine);
// Emit the color table (if needed)
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))) {
sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
sb.Append(";");
}
- sb.Append("}\n");
+ sb.Append("}");
+ sb.Append(Environment.NewLine);
}
sb.Append("{\\*\\generator Mono RichTextBox;}");
}
if (pos >= line.text.Length) {
if (line.ending != LineEnding.Wrap) {
- sb.Append("\\par\n");
+ sb.Append("\\par");
+ sb.Append(Environment.NewLine);
}
}
pos = 0;
line_no++;
}
- sb.Append("}\n");
+ sb.Append("}");
+ sb.Append(Environment.NewLine);
return sb;
}