for WinForms
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
7.6 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.TextEditor.Util
{
public class RtfWriter
{
private static Dictionary<string, int> colors;
private static int colorNum;
private static StringBuilder colorString;
public static string GenerateRtf(TextArea textArea)
{
colors = new Dictionary<string, int>();
colorNum = 0;
colorString = new StringBuilder();
var rtf = new StringBuilder();
rtf.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1031");
BuildFontTable(textArea.Document, rtf);
rtf.Append(value: '\n');
var fileContent = BuildFileContent(textArea);
BuildColorTable(rtf);
rtf.Append(value: '\n');
rtf.Append(@"\viewkind4\uc1\pard");
rtf.Append(fileContent);
rtf.Append("}");
return rtf.ToString();
}
private static void BuildColorTable(StringBuilder rtf)
{
rtf.Append(@"{\colortbl ;");
rtf.Append(colorString);
rtf.Append("}");
}
private static void BuildFontTable(IDocument doc, StringBuilder rtf)
{
rtf.Append(@"{\fonttbl");
rtf.Append(@"{\f0\fmodern\fprq1\fcharset0 " + doc.TextEditorProperties.Font.Name + ";}");
rtf.Append("}");
}
private static string BuildFileContent(TextArea textArea)
{
var rtf = new StringBuilder();
var firstLine = true;
var curColor = SystemColors.WindowText;
var oldItalic = false;
var oldBold = false;
var escapeSequence = false;
foreach (var selection in textArea.SelectionManager.SelectionCollection)
{
var selectionOffset = textArea.Document.PositionToOffset(selection.StartPosition);
var selectionEndOffset = textArea.Document.PositionToOffset(selection.EndPosition);
for (var i = selection.StartPosition.Y; i <= selection.EndPosition.Y; ++i)
{
var line = textArea.Document.GetLineSegment(i);
var offset = line.Offset;
if (line.Words == null)
continue;
foreach (var word in line.Words)
switch (word.Type)
{
case TextWordType.Space:
if (selection.ContainsOffset(offset))
rtf.Append(value: ' ');
++offset;
break;
case TextWordType.Tab:
if (selection.ContainsOffset(offset))
rtf.Append(@"\tab");
++offset;
escapeSequence = true;
break;
case TextWordType.Word:
var c = word.Color;
if (offset + word.Word.Length > selectionOffset && offset < selectionEndOffset)
{
var 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]);
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(value: ' ');
escapeSequence = false;
}
string printWord;
if (offset < selectionOffset)
printWord = word.Word.Substring(selectionOffset - offset);
else if (offset + word.Word.Length > selectionEndOffset)
printWord = word.Word.Substring(startIndex: 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(value: '\n');
}
}
return rtf.ToString();
}
private static void AppendText(StringBuilder rtfOutput, string text)
{
//rtf.Append(printWord.Replace(@"\", @"\\").Replace("{", "\\{").Replace("}", "\\}"));
foreach (var 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
rtfOutput.Append("\\u" + unchecked((short)c) + "?");
break;
}
}
}
}