// // // // // $Revision$ // using System; using System.Collections.Generic; using System.Drawing; using System.Text; using ICSharpCode.TextEditor.Document; namespace ICSharpCode.TextEditor.Util { public class RtfWriter { static Dictionary colors; static int colorNum; static StringBuilder colorString; public static string GenerateRtf(TextArea textArea) { colors = new Dictionary(); colorNum = 0; colorString = new StringBuilder(); StringBuilder rtf = new StringBuilder(); rtf.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1031"); BuildFontTable(textArea.Document, rtf); rtf.Append('\n'); string fileContent = BuildFileContent(textArea); BuildColorTable(textArea.Document, rtf); rtf.Append('\n'); rtf.Append(@"\viewkind4\uc1\pard"); rtf.Append(fileContent); rtf.Append("}"); return rtf.ToString(); } static void BuildColorTable(IDocument doc, StringBuilder rtf) { rtf.Append(@"{\colortbl ;"); rtf.Append(colorString.ToString()); rtf.Append("}"); } static void BuildFontTable(IDocument doc, StringBuilder rtf) { rtf.Append(@"{\fonttbl"); rtf.Append(@"{\f0\fmodern\fprq1\fcharset0 " + doc.TextEditorProperties.Font.Name + ";}"); rtf.Append("}"); } static string BuildFileContent(TextArea textArea) { StringBuilder rtf = new StringBuilder(); bool firstLine = true; Color curColor = Color.Black; bool oldItalic = false; bool oldBold = false; bool escapeSequence = false; foreach (ISelection selection in textArea.SelectionManager.SelectionCollection) { int selectionOffset = textArea.Document.PositionToOffset(selection.StartPosition); int selectionEndOffset = textArea.Document.PositionToOffset(selection.EndPosition); for (int i = selection.StartPosition.Y; i <= selection.EndPosition.Y; ++i) { LineSegment line = textArea.Document.GetLineSegment(i); int offset = line.Offset; if (line.Words == null) { continue; } foreach (TextWord word in line.Words) { switch (word.Type) { case TextWordType.Space: if (selection.ContainsOffset(offset)) { rtf.Append(' '); } ++offset; break; case TextWordType.Tab: if (selection.ContainsOffset(offset)) { rtf.Append(@"\tab"); } ++offset; escapeSequence = true; break; case TextWordType.Word: Color c = word.Color; if (offset + word.Word.Length > selectionOffset && offset < selectionEndOffset) { string colorstr = c.R + ", " + c.G + ", " + c.B; if (!colors.ContainsKey(colorstr)) { colors[colorstr] = ++colorNum; colorString.Append(@"\red" + c.R + @"\green" + c.G + @"\blue" + c.B + ";"); } if (c != curColor || firstLine) { rtf.Append(@"\cf" + colors[colorstr].ToString()); curColor = c; escapeSequence = true; } if (oldItalic != word.Italic) { if (word.Italic) { rtf.Append(@"\i"); } else { rtf.Append(@"\i0"); } oldItalic = word.Italic; escapeSequence = true; } if (oldBold != word.Bold) { if (word.Bold) { rtf.Append(@"\b"); } else { rtf.Append(@"\b0"); } oldBold = word.Bold; escapeSequence = true; } if (firstLine) { rtf.Append(@"\f0\fs" + (textArea.TextEditorProperties.Font.Size * 2)); firstLine = false; } if (escapeSequence) { rtf.Append(' '); escapeSequence = false; } string printWord; if (offset < selectionOffset) { printWord = word.Word.Substring(selectionOffset - offset); } else if (offset + word.Word.Length > selectionEndOffset) { printWord = word.Word.Substring(0, (offset + word.Word.Length) - selectionEndOffset); } else { printWord = word.Word; } AppendText(rtf, printWord); } offset += word.Length; break; } } if (offset < selectionEndOffset) { rtf.Append(@"\par"); } rtf.Append('\n'); } } return rtf.ToString(); } static void AppendText(StringBuilder rtfOutput, string text) { //rtf.Append(printWord.Replace(@"\", @"\\").Replace("{", "\\{").Replace("}", "\\}")); foreach (char c in text) { switch (c) { case '\\': rtfOutput.Append(@"\\"); break; case '{': rtfOutput.Append("\\{"); break; case '}': rtfOutput.Append("\\}"); break; default: if (c < 256) { rtfOutput.Append(c); } else { // yes, RTF really expects signed 16-bit integers! rtfOutput.Append("\\u" + unchecked((short)c).ToString() + "?"); } break; } } } } }