diff options
Diffstat (limited to 'mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs')
-rw-r--r-- | mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs | 1612 |
1 files changed, 1612 insertions, 0 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs new file mode 100644 index 00000000000..4259fb6b797 --- /dev/null +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs @@ -0,0 +1,1612 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok <pbartok@novell.com> +// +// + +// NOT COMPLETE + +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Text; +using RTF=System.Windows.Forms.RTF; + +namespace System.Windows.Forms { + public class RichTextBox : TextBoxBase { + #region Local Variables + internal bool auto_word_select; + internal int bullet_indent; + internal bool can_redo; + internal bool detect_urls; + internal string redo_action_name; + internal int margin_right; + internal string undo_action_name; + internal float zoom; + + private RTF.TextMap rtf_text_map; + private int rtf_skip_width; + private int rtf_skip_count; + private StringBuilder rtf_line; + private SolidBrush rtf_color; + private RTF.Font rtf_rtffont; + private int rtf_rtffont_size; + private FontStyle rtf_rtfstyle; + private HorizontalAlignment rtf_rtfalign; + private int rtf_cursor_x; + private int rtf_cursor_y; + #endregion // Local Variables + + #region Public Constructors + public RichTextBox() { + accepts_return = true; + auto_word_select = false; + bullet_indent = 0; + can_redo = false; + detect_urls = true; + max_length = Int32.MaxValue; + redo_action_name = string.Empty; + margin_right = 0; + undo_action_name = string.Empty; + zoom = 1; + base.Multiline = true; + document.CRLFSize = 1; + + scrollbars = RichTextBoxScrollBars.Both; + alignment = HorizontalAlignment.Left; + LostFocus += new EventHandler(RichTextBox_LostFocus); + GotFocus += new EventHandler(RichTextBox_GotFocus); + BackColor = ThemeEngine.Current.ColorWindow; + ForeColor = ThemeEngine.Current.ColorWindowText; + base.HScrolled += new EventHandler(RichTextBox_HScrolled); + base.VScrolled += new EventHandler(RichTextBox_VScrolled); + } + #endregion // Public Constructors + + #region Private & Internal Methods + private void RichTextBox_LostFocus(object sender, EventArgs e) { + has_focus = false; + Invalidate(); + } + + private void RichTextBox_GotFocus(object sender, EventArgs e) { + has_focus = true; + Invalidate(); + } + #endregion // Private & Internal Methods + + #region Public Instance Properties + public override bool AllowDrop { + get { + return base.AllowDrop; + } + + set { + base.AllowDrop = value; + } + } + + [DefaultValue(false)] + [Localizable(true)] + public override bool AutoSize { + get { + return auto_size; + } + + set { + base.AutoSize = value; + } + } + + [DefaultValue(false)] + public bool AutoWordSelection { + get { + return auto_word_select; + } + + set { + auto_word_select = true; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override System.Drawing.Image BackgroundImage { + get { + return background_image; + } + + set { + base.BackgroundImage = value; + } + } + + [DefaultValue(0)] + [Localizable(true)] + public int BulletIndent { + get { + return bullet_indent; + } + + set { + bullet_indent = value; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool CanRedo { + get { + return can_redo; + } + } + + [DefaultValue(true)] + public bool DetectUrls { + get { + return detect_urls; + } + + set { + detect_urls = true; + } + } + + public override Font Font { + get { + return base.Font; + } + + set { + if (font != value) { + Line start; + Line end; + + if (auto_size) { + if (PreferredHeight != Height) { + Height = PreferredHeight; + } + } + + base.Font = value; + + // Font changes always set the whole doc to that font + start = document.GetLine(1); + end = document.GetLine(document.Lines); + document.FormatText(start, 1, end, end.text.Length + 1, base.Font, new SolidBrush(this.ForeColor)); + } + } + } + + public override Color ForeColor { + get { + return base.ForeColor; + } + + set { + base.ForeColor = value; + } + } + + [DefaultValue(Int32.MaxValue)] + public override int MaxLength { + get { + return base.max_length; + } + + set { + base.max_length = value; + } + } + + [DefaultValue(true)] + public override bool Multiline { + get { + return multiline; + } + + set { + base.Multiline = value; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MonoTODO] + public string RedoActionName { + get { + return redo_action_name; + } + } + + [DefaultValue(0)] + [Localizable(true)] + [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")] + public int RightMargin { + get { + return margin_right; + } + + set { + margin_right = value; + } + } + + [Browsable(false)] + [DefaultValue("")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Rtf { + get { + Line start_line; + Line end_line; + int current; + int total; + + start_line = document.GetLine(1); + end_line = document.GetLine(document.Lines); + return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString(); + } + + set { + MemoryStream data; + + document.Empty(); + data = new MemoryStream(Encoding.ASCII.GetBytes(value), false); + + InsertRTFFromStream(data, 0, 1); + + data.Close(); + } + } + + [DefaultValue(RichTextBoxScrollBars.Both)] + [Localizable(true)] + public RichTextBoxScrollBars ScrollBars { + get { + return scrollbars; + } + + set { + scrollbars = value; + } + } + + [Browsable(false)] + [DefaultValue("")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string SelectedRtf { + get { + return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString(); + } + + set { + MemoryStream data; + int x; + int y; + Line line; + + if (document.selection_visible) { + document.ReplaceSelection(""); + } + + data = new MemoryStream(Encoding.ASCII.GetBytes(value), false); + InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y); + data.Close(); + + line = document.GetLine(y); + document.SetSelection(document.GetLine(y), x); + document.PositionCaret(line, x); + document.DisplayCaret(); + + OnTextChanged(EventArgs.Empty); + } + } + + [Browsable(false)] + [DefaultValue("")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public override string SelectedText { + get { + return base.SelectedText; + } + + set { + base.SelectedText = value; + } + } + + [Browsable(false)] + [DefaultValue(HorizontalAlignment.Left)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public HorizontalAlignment SelectionAlignment { + get { + HorizontalAlignment align; + Line start; + Line end; + Line line; + + start = document.ParagraphStart(document.selection_start.line); + align = start.alignment; + + end = document.ParagraphEnd(document.selection_end.line); + + line = start; + + while (true) { + if (line.alignment != align) { + return HorizontalAlignment.Left; + } + + if (line == end) { + break; + } + line = document.GetLine(line.line_no + 1); + } + + return align; + } + + set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart(document.selection_start.line); + + end = document.ParagraphEnd(document.selection_end.line); + + line = start; + + while (true) { + line.alignment = value; + + if (line == end) { + break; + } + line = document.GetLine(line.line_no + 1); + } + this.CalculateDocument(); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Color SelectionColor { + get { + Color color; + LineTag start; + LineTag end; + LineTag tag; + + start = document.selection_start.tag; + end = document.selection_end.tag; + color = ((SolidBrush)document.selection_start.tag.color).Color; + + tag = start; + while (true) { + if (!color.Equals(((SolidBrush)tag.color).Color)) { + return Color.Empty; + } + + if (tag == end) { + break; + } + + tag = document.NextTag(tag); + + if (tag == null) { + break; + } + } + + return color; + } + + set { + int sel_start; + int sel_end; + + sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos); + sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos); +Console.WriteLine("FIXME - SelectionColor should not alter font"); + document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, document.selection_start.tag.font, new SolidBrush(value)); + + document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos); + document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos); + + document.UpdateView(document.selection_start.line, 0); + document.AlignCaret(); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Font SelectionFont { + get { + Font font; + LineTag start; + LineTag end; + LineTag tag; + + start = document.selection_start.tag; + end = document.selection_end.tag; + font = document.selection_start.tag.font; + + tag = start; + while (true) { + if (!font.Equals(tag.font)) { + return null; + } + + if (tag == end) { + break; + } + + tag = document.NextTag(tag); + + if (tag == null) { + break; + } + } + + return font; + } + + set { + int sel_start; + int sel_end; + + sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos); + sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos); + + document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, value, document.selection_start.tag.color); + + document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos); + document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos); + + document.UpdateView(document.selection_start.line, 0); + document.AlignCaret(); + + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public override int SelectionLength { + get { + return base.SelectionLength; + } + + set { + base.SelectionLength = value; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public RichTextBoxSelectionTypes SelectionType { + get { + if (document.selection_start == document.selection_end) { + return RichTextBoxSelectionTypes.Empty; + } + + // Lazy, but works + if (SelectedText.Length > 1) { + return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text; + } + + return RichTextBoxSelectionTypes.Text; + } + } + + [Localizable(true)] + public override string Text { + get { + return base.Text; + } + + set { + base.Text = value; + } + } + + [Browsable(false)] + public override int TextLength { + get { + return base.TextLength; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string UndoActionName { + get { + return document.undo.UndoName; + } + } + + [Localizable(true)] + [DefaultValue(1)] + public float ZoomFactor { + get { + return zoom; + } + + set { + zoom = value; + } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override Size DefaultSize { + get { + return new Size(100, 96); + } + } + #endregion // Protected Instance Properties + + #region Public Instance Methods + public bool CanPaste(DataFormats.Format clipFormat) { + if ((clipFormat.Name == DataFormats.Rtf) || + (clipFormat.Name == DataFormats.Text) || + (clipFormat.Name == DataFormats.UnicodeText)) { + return true; + } + return false; + } + + public int Find(char[] characterSet) { + return Find(characterSet, -1, -1); + } + + public int Find(char[] characterSet, int start) { + return Find(characterSet, start, -1); + } + + public int Find(char[] characterSet, int start, int end) { + Document.Marker start_mark; + Document.Marker end_mark; + Document.Marker result; + + if (start == -1) { + document.GetMarker(out start_mark, true); + } else { + Line line; + LineTag tag; + int pos; + + start_mark = new Document.Marker(); + + document.CharIndexToLineTag(start, out line, out tag, out pos); + start_mark.line = line; + start_mark.tag = tag; + start_mark.pos = pos; + } + + if (end == -1) { + document.GetMarker(out end_mark, false); + } else { + Line line; + LineTag tag; + int pos; + + end_mark = new Document.Marker(); + + document.CharIndexToLineTag(end, out line, out tag, out pos); + end_mark.line = line; + end_mark.tag = tag; + end_mark.pos = pos; + } + + if (document.FindChars(characterSet, start_mark, end_mark, out result)) { + return document.LineTagToCharIndex(result.line, result.pos); + } + + return -1; + } + + public int Find(string str) { + return Find(str, -1, -1, RichTextBoxFinds.None); + } + + public int Find(string str, int start, int end, RichTextBoxFinds options) { + Document.Marker start_mark; + Document.Marker end_mark; + Document.Marker result; + + if (start == -1) { + document.GetMarker(out start_mark, true); + } else { + Line line; + LineTag tag; + int pos; + + start_mark = new Document.Marker(); + + document.CharIndexToLineTag(start, out line, out tag, out pos); + + start_mark.line = line; + start_mark.tag = tag; + start_mark.pos = pos; + } + + if (end == -1) { + document.GetMarker(out end_mark, false); + } else { + Line line; + LineTag tag; + int pos; + + end_mark = new Document.Marker(); + + document.CharIndexToLineTag(end, out line, out tag, out pos); + + end_mark.line = line; + end_mark.tag = tag; + end_mark.pos = pos; + } + + if (document.Find(str, start_mark, end_mark, out result, options)) { + return document.LineTagToCharIndex(result.line, result.pos); + } + + return -1; + } + + public int Find(string str, int start, RichTextBoxFinds options) { + return Find(str, start, -1, options); + } + + public int Find(string str, RichTextBoxFinds options) { + return Find(str, -1, -1, options); + } + + public char GetCharFromPosition(Point pt) { + LineTag tag; + int pos; + + PointToTagPos(pt, out tag, out pos); + + if (pos >= tag.line.text.Length) { + return '\n'; + } + + return tag.line.text[pos]; + + } + + public int GetCharIndexFromPosition(Point pt) { + LineTag tag; + int pos; + + PointToTagPos(pt, out tag, out pos); + + return document.LineTagToCharIndex(tag.line, pos); + } + + public int GetLineFromCharIndex(int index) { + Line line; + LineTag tag; + int pos; + + document.CharIndexToLineTag(index, out line, out tag, out pos); + + return line.LineNo - 1; + } + + public Point GetPositionFromCharIndex(int index) { + Line line; + LineTag tag; + int pos; + + document.CharIndexToLineTag(index, out line, out tag, out pos); + + return new Point((int)line.widths[pos] + 1, line.Y + 1); + } + + public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) { + RTF.RTF rtf; // Not 'using SWF.RTF' to avoid ambiguities with font and color + + document.Empty(); + + // FIXME - ignoring unicode + if (fileType == RichTextBoxStreamType.PlainText) { + StringBuilder sb; + int count; + byte[] buffer; + + try { + sb = new StringBuilder((int)data.Length); + buffer = new byte[1024]; + } + + catch { + throw new IOException("Not enough memory to load document"); + } + + count = 0; + while (count < data.Length) { + count += data.Read(buffer, count, 1024); + sb.Append(buffer); + } + base.Text = sb.ToString(); + return; + } + + InsertRTFFromStream(data, 0, 1); + } + + [MonoTODO("Make smarter RTF detection?")] + public void LoadFile(string path) { + if (path.EndsWith(".rtf")) { + LoadFile(path, RichTextBoxStreamType.RichText); + } else { + LoadFile(path, RichTextBoxStreamType.PlainText); + } + } + + public void LoadFile(string path, RichTextBoxStreamType fileType) { + FileStream data; + + data = null; + + try { + data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024); + LoadFile(data, fileType); + } + + catch { + throw new IOException("Could not open file " + path); + } + + finally { + if (data != null) { + data.Close(); + } + } + } + + public void Paste(DataFormats.Format clipFormat) { + base.Paste(clipFormat, false); + } + + [MonoTODO()] + public void Redo() { + } + + public void SaveFile(Stream data, RichTextBoxStreamType fileType) { + Encoding encoding; + int i; + Byte[] bytes; + + + if (fileType == RichTextBoxStreamType.UnicodePlainText) { + encoding = Encoding.Unicode; + } else { + encoding = Encoding.ASCII; + } + + switch(fileType) { + case RichTextBoxStreamType.PlainText: + case RichTextBoxStreamType.TextTextOleObjs: + case RichTextBoxStreamType.UnicodePlainText: { + if (!multiline) { + bytes = encoding.GetBytes(document.Root.text.ToString()); + data.Write(bytes, 0, bytes.Length); + return; + } + + for (i = 1; i < document.Lines; i++) { + bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine); + data.Write(bytes, 0, bytes.Length); + } + bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString()); + data.Write(bytes, 0, bytes.Length); + return; + } + } + + // If we're here we're saving RTF + Line start_line; + Line end_line; + StringBuilder rtf; + int current; + int total; + + start_line = document.GetLine(1); + end_line = document.GetLine(document.Lines); + rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length); + total = rtf.Length; + bytes = new Byte[4096]; + + // Let's chunk it so we don't use up all memory... + for (i = 0; i < total; i += 1024) { + if ((i + 1024) < total) { + current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0); + } else { + current = total - i; + current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0); + } + data.Write(bytes, 0, current); + } + } + + public void SaveFile(string path) { + if (path.EndsWith(".rtf")) { + SaveFile(path, RichTextBoxStreamType.RichText); + } else { + SaveFile(path, RichTextBoxStreamType.PlainText); + } + } + + public void SaveFile(string path, RichTextBoxStreamType fileType) { + FileStream data; + + data = null; + +// try { + data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false); + SaveFile(data, fileType); +// } + +// catch { +// throw new IOException("Could not write document to file " + path); +// } + +// finally { + if (data != null) { + data.Close(); + } +// } + } + + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected virtual object CreateRichEditOleCallback() { + throw new NotImplementedException(); + } + + protected override void OnBackColorChanged(EventArgs e) { + base.OnBackColorChanged (e); + } + + protected virtual void OnContentsResized(ContentsResizedEventArgs e) { + if (ContentsResized != null) { + ContentsResized(this, e); + } + } + + protected override void OnContextMenuChanged(EventArgs e) { + base.OnContextMenuChanged (e); + } + + protected override void OnHandleCreated(EventArgs e) { + base.OnHandleCreated (e); + } + + protected override void OnHandleDestroyed(EventArgs e) { + base.OnHandleDestroyed (e); + } + + protected virtual void OnHScroll(EventArgs e) { + if (HScroll != null) { + HScroll(this, e); + } + } + + [MonoTODO("Determine when to call this")] + protected virtual void OnImeChange(EventArgs e) { + if (ImeChange != null) { + ImeChange(this, e); + } + } + + protected virtual void OnLinkClicked(LinkClickedEventArgs e) { + if (LinkClicked != null) { + LinkClicked(this, e); + } + } + + protected virtual void OnProtected(EventArgs e) { + if (Protected != null) { + Protected(this, e); + } + } + + protected override void OnRightToLeftChanged(EventArgs e) { + base.OnRightToLeftChanged (e); + } + + protected virtual void OnSelectionChanged(EventArgs e) { + if (SelectionChanged != null) { + SelectionChanged(this, e); + } + } + + protected override void OnSystemColorsChanged(EventArgs e) { + base.OnSystemColorsChanged (e); + } + + protected override void OnTextChanged(EventArgs e) { + base.OnTextChanged (e); + } + + protected virtual void OnVScroll(EventArgs e) { + if (VScroll != null) { + VScroll(this, e); + } + } + + protected override void WndProc(ref Message m) { + base.WndProc (ref m); + } + #endregion // Protected Instance Methods + + #region Events + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public event EventHandler BackgroundImageChanged; + + public event ContentsResizedEventHandler ContentsResized; + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public event EventHandler DoubleClick; + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public event DragEventHandler DragDrop { + add { + base.DragDrop += value; + } + + remove { + base.DragDrop -= value; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public event DragEventHandler DragEnter { + add { + base.DragEnter += value; + } + + remove { + base.DragEnter -= value; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public event EventHandler DragLeave { + add { + base.DragLeave += value; + } + + remove { + base.DragLeave -= value; + } + } + + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public event DragEventHandler DragOver { + add { + base.DragOver += value; + } + + remove { + base.DragOver -= value; + } + } + + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public event GiveFeedbackEventHandler GiveFeedback; + + public event EventHandler HScroll; + public event EventHandler ImeChange; + public event LinkClickedEventHandler LinkClicked; + public event EventHandler Protected; + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public event QueryContinueDragEventHandler QueryContinueDrag; + public event EventHandler SelectionChanged; + public event EventHandler VScroll; + #endregion // Events + + #region Private Methods + private void HandleControl(RTF.RTF rtf) { + switch(rtf.Major) { + case RTF.Major.Unicode: { + switch(rtf.Minor) { + case Minor.UnicodeCharBytes: { + rtf_skip_width = rtf.Param; + break; + } + + case Minor.UnicodeChar: { + rtf_skip_count += rtf_skip_width; + rtf_line.Append((char)rtf.Param); + break; + } + } + break; + } + + case RTF.Major.Destination: { + Console.Write("[Got Destination control {0}]", rtf.Minor); + rtf.SkipGroup(); + break; + } + + case RTF.Major.CharAttr: { + switch(rtf.Minor) { + case Minor.ForeColor: { + System.Windows.Forms.RTF.Color color; + + color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param); + if (color != null) { + FlushText(rtf, false); + if (color.Red == -1 && color.Green == -1 && color.Blue == -1) { + this.rtf_color = new SolidBrush(ForeColor); + } else { + this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue)); + } + } + break; + } + + case Minor.FontSize: { + FlushText(rtf, false); + this.rtf_rtffont_size = rtf.Param / 2; + break; + } + + case Minor.FontNum: { + System.Windows.Forms.RTF.Font font; + + font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param); + if (font != null) { + FlushText(rtf, false); + this.rtf_rtffont = font; + } + break; + } + + case Minor.Plain: { + FlushText(rtf, false); + rtf_rtfstyle = FontStyle.Regular; + break; + } + + case Minor.Bold: { + FlushText(rtf, false); + if (rtf.Param == RTF.RTF.NoParam) { + rtf_rtfstyle |= FontStyle.Bold; + } else { + rtf_rtfstyle &= ~FontStyle.Bold; + } + break; + } + + case Minor.Italic: { + FlushText(rtf, false); + if (rtf.Param == RTF.RTF.NoParam) { + rtf_rtfstyle |= FontStyle.Italic; + } else { + rtf_rtfstyle &= ~FontStyle.Italic; + } + break; + } + + case Minor.StrikeThru: { + FlushText(rtf, false); + if (rtf.Param == RTF.RTF.NoParam) { + rtf_rtfstyle |= FontStyle.Strikeout; + } else { + rtf_rtfstyle &= ~FontStyle.Strikeout; + } + break; + } + + case Minor.Underline: { + FlushText(rtf, false); + if (rtf.Param == RTF.RTF.NoParam) { + rtf_rtfstyle |= FontStyle.Underline; + } else { + rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline; + } + break; + } + + case Minor.NoUnderline: { + FlushText(rtf, false); + rtf_rtfstyle &= ~FontStyle.Underline; + break; + } + } + break; + } + + case RTF.Major.SpecialChar: { + Console.Write("[Got SpecialChar control {0}]", rtf.Minor); + SpecialChar(rtf); + break; + } + } + } + + private void SpecialChar(RTF.RTF rtf) { + switch(rtf.Minor) { + case Minor.Page: + case Minor.Sect: + case Minor.Row: + case Minor.Line: + case Minor.Par: { + FlushText(rtf, true); + break; + } + + case Minor.Cell: { + Console.Write(" "); + break; + } + + case Minor.NoBrkSpace: { + Console.Write(" "); + break; + } + + case Minor.Tab: { + Console.Write("\t"); + break; + } + + case Minor.NoBrkHyphen: { + Console.Write("-"); + break; + } + + case Minor.Bullet: { + Console.Write("*"); + break; + } + + case Minor.EmDash: { + Console.Write("—"); + break; + } + + case Minor.EnDash: { + Console.Write("–"); + break; + } + + case Minor.LQuote: { + Console.Write("‘"); + break; + } + + case Minor.RQuote: { + Console.Write("’"); + break; + } + + case Minor.LDblQuote: { + Console.Write("“"); + break; + } + + case Minor.RDblQuote: { + Console.Write("”"); + break; + } + + default: { + rtf.SkipGroup(); + break; + } + } + } + + private void HandleText(RTF.RTF rtf) { + if (rtf_skip_count > 0) { + rtf_skip_count--; + return; + } + + if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) { + rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]); + } else { + if ((int)rtf.Major > 31 && (int)rtf.Major < 128) { + rtf_line.Append((char)rtf.Major); + } else { + //rtf_line.Append((char)rtf.Major); + Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major); + } + } + } + + private void FlushText(RTF.RTF rtf, bool newline) { + int length; + Font font; + + length = rtf_line.Length; + if (length == 0) { + return; + } + + if (rtf_rtffont == null) { + // First font in table is default + rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0); + } + + font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle); + + if (rtf_color == null) { + System.Windows.Forms.RTF.Color color; + + // First color in table is default + color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0); + + if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) { + rtf_color = new SolidBrush(ForeColor); + } else { + rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue)); + } + } + + if (rtf_cursor_x == 0) { + document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color); + } else { + Line line; + + line = document.GetLine(rtf_cursor_y); + document.InsertString(line, rtf_cursor_x, rtf_line.ToString()); + document.FormatText(line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, font, rtf_color); // FormatText is 1-based + } + + if (newline) { + rtf_cursor_x = 0; + rtf_cursor_y++; + } else { + rtf_cursor_x += length; + } + rtf_line.Length = 0; // Empty line + } + + private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) { + int x; + int y; + + InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y); + } + + private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y) { + RTF.RTF rtf; + + rtf = new RTF.RTF(data); + + // Prepare + rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText); + rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl); + + rtf_skip_width = 0; + rtf_skip_count = 0; + rtf_line = new StringBuilder(); + rtf_color = null; + rtf_rtffont_size = (int)this.Font.Size; + rtf_rtfalign = HorizontalAlignment.Left; + rtf_rtfstyle = FontStyle.Regular; + rtf_rtffont = null; + rtf_cursor_x = cursor_x; + rtf_cursor_y = cursor_y; + rtf.DefaultFont(this.Font.Name); + + rtf_text_map = new RTF.TextMap(); + RTF.TextMap.SetupStandardTable(rtf_text_map.Table); + + try { + rtf.Read(); // That's it + FlushText(rtf, false); + } + + catch (RTF.RTFException) { + // Seems to be plain text... + + } + + to_x = rtf_cursor_x; + to_y = rtf_cursor_y; + + document.RecalculateDocument(CreateGraphics(), cursor_y, document.Lines, false); + document.Invalidate(document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1); + } + + private void RichTextBox_HScrolled(object sender, EventArgs e) { + OnHScroll(e); + } + + private void RichTextBox_VScrolled(object sender, EventArgs e) { + OnVScroll(e); + } + + private void PointToTagPos(Point pt, out LineTag tag, out int pos) { + Point p; + + p = pt; + + if (p.X >= document.ViewPortWidth) { + p.X = document.ViewPortWidth - 1; + } else if (p.X < 0) { + p.X = 0; + } + + if (p.Y >= document.ViewPortHeight) { + p.Y = document.ViewPortHeight - 1; + } else if (p.Y < 0) { + p.Y = 0; + } + + tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos); + } + + private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) { + if (prev_index != font_index) { + rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry + } + + if ((prev_font == null) || (prev_font.Size != font.Size)) { + rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size + } + + if ((prev_font == null) || (font.Bold != prev_font.Bold)) { + if (font.Bold) { + rtf.Append("\\b"); + } else { + if (prev_font != null) { + rtf.Append("\\b0"); + } + } + } + + if ((prev_font == null) || (font.Italic != prev_font.Italic)) { + if (font.Italic) { + rtf.Append("\\i"); + } else { + if (prev_font != null) { + rtf.Append("\\i0"); + } + } + } + + if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) { + if (font.Strikeout) { + rtf.Append("\\strike"); + } else { + if (prev_font != null) { + rtf.Append("\\strike0"); + } + } + } + + if ((prev_font == null) || (font.Underline != prev_font.Underline)) { + if (font.Underline) { + rtf.Append("\\ul"); + } else { + if (prev_font != null) { + rtf.Append("\\ul0"); + } + } + } + } + + [MonoTODO("Emit unicode and other special characters properly")] + private void EmitRTFText(StringBuilder rtf, string text) { + rtf.Append(text); + } + + // start_pos and end_pos are 0-based + private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) { + StringBuilder sb; + ArrayList fonts; + ArrayList colors; + Color color; + Font font; + Line line; + LineTag tag; + int pos; + int line_no; + int line_len; + int i; + int length; + + sb = new StringBuilder(); + fonts = new ArrayList(10); + colors = new ArrayList(10); + + // Two runs, first we parse to determine tables; + // and unlike most of our processing here we work on tags + + line = start_line; + line_no = start_line.line_no; + pos = start_pos; + + // Add default font and color; to optimize document content we don't + // use this.Font and this.ForeColor but the font/color from the first tag + tag = LineTag.FindTag(start_line, pos); + font = tag.font; + color = ((SolidBrush)tag.color).Color; + fonts.Add(font.Name); + colors.Add(color); + + while (line_no <= end_line.line_no) { + line = document.GetLine(line_no); + tag = LineTag.FindTag(line, pos); + + if (line_no != end_line.line_no) { + line_len = line.text.Length; + } else { + line_len = end_pos; + } + + while (pos < line_len) { + if (tag.font.Name != font.Name) { + font = tag.font; + if (!fonts.Contains(font.Name)) { + fonts.Add(font.Name); + } + } + + if (((SolidBrush)tag.color).Color != color) { + color = ((SolidBrush)tag.color).Color; + if (!colors.Contains(color)) { + colors.Add(color); + } + } + + pos = tag.start + tag.length - 1; + tag = tag.next; + } + pos = 0; + line_no++; + } + + // We have the tables, emit the header + sb.Append("{\\rtf1\\ansi"); + sb.Append("\\ansicpg1252"); // FIXME - is this correct? + + // Default Font + sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name))); + + // Default Language + sb.Append("\\deflang1033\n"); // FIXME - always 1033? + + // Emit the font table + sb.Append("{\\fonttbl"); + for (i = 0; i < fonts.Count; i++) { + sb.Append(String.Format("{{\\f{0}", i)); // {Font + sb.Append("\\fnil"); // Family + sb.Append("\\fcharset0 "); // Charset ANSI<space> + sb.Append((string)fonts[i]); // Font name + sb.Append(";}"); // } + } + sb.Append("}\n"); + + // 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("{\\colortbl "); // Header and NO! default color + for (i = 0; i < colors.Count; i++) { + sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R)); + sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G)); + sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B)); + sb.Append(";"); + } + sb.Append("}\n"); + } + + sb.Append("{\\*\\generator Mono RichTextBox;}"); + // Emit initial paragraph settings + tag = LineTag.FindTag(start_line, start_pos); + sb.Append("\\pard"); // Reset to default paragraph properties + EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font); // Font properties + sb.Append(" "); // Space separator + + font = tag.font; + color = (Color)colors[0]; + line = start_line; + line_no = start_line.line_no; + pos = start_pos; + + while (line_no <= end_line.line_no) { + line = document.GetLine(line_no); + tag = LineTag.FindTag(line, pos); + + if (line_no != end_line.line_no) { + line_len = line.text.Length; + } else { + line_len = end_pos; + } + + while (pos < line_len) { + length = sb.Length; + + if (tag.font != font) { + EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font); + font = tag.font; + } + + if (((SolidBrush)tag.color).Color != color) { + color = ((SolidBrush)tag.color).Color; + sb.Append(String.Format("\\cf{0}", colors.IndexOf(color))); + } + if (length != sb.Length) { + sb.Append(" "); // Emit space to separate keywords from text + } + + // Emit the string itself + if (line_no != end_line.line_no) { + EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1)); + } else { + if (end_pos < (tag.start + tag.length - 1)) { + // Emit partial tag only, end_pos is inside this tag + EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos)); + } else { + EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1)); + } + } + + pos = tag.start + tag.length - 1; + tag = tag.next; + } + if (pos >= line.text.Length) { + if (!line.soft_break) { + sb.Append("\\par\n"); + } + } + pos = 0; + line_no++; + } + + sb.Append("}\n"); + + return sb; + } + #endregion // Private Methods + } +} |