diff options
author | Mike Krüger <mkrueger@xamarin.com> | 2012-04-30 21:12:52 +0400 |
---|---|---|
committer | Mike Krüger <mkrueger@xamarin.com> | 2012-04-30 21:12:52 +0400 |
commit | 8871f47474892b29671fc4261f67fd12c104c0e7 (patch) | |
tree | d3ddd83cf1fc7048ace9b936e43b7877bd7ba33f | |
parent | 71b528f5664cd84fccb022721189548539c736e3 (diff) |
Fixed 'Bug 4751 - RTF paste is broken'.
7 files changed, 211 insertions, 117 deletions
diff --git a/main/src/core/Mono.Texteditor/Makefile.am b/main/src/core/Mono.Texteditor/Makefile.am index 0f62f89174..d975e28bf5 100644 --- a/main/src/core/Mono.Texteditor/Makefile.am +++ b/main/src/core/Mono.Texteditor/Makefile.am @@ -56,6 +56,7 @@ FILES = \ Mono.TextEditor.Theatrics/Stage.cs \ Mono.TextEditor.Utils/Diff.cs \ Mono.TextEditor.Utils/RedBlackTree.cs \ + Mono.TextEditor.Utils/RtfWriter.cs \ Mono.TextEditor.Utils/TextBreaker.cs \ Mono.TextEditor.Utils/TextFileUtility.cs \ Mono.TextEditor.Vi/ViActionMaps.cs \ diff --git a/main/src/core/Mono.Texteditor/Mono.TextEditor.Utils/RtfWriter.cs b/main/src/core/Mono.Texteditor/Mono.TextEditor.Utils/RtfWriter.cs new file mode 100644 index 0000000000..c74c9442dc --- /dev/null +++ b/main/src/core/Mono.Texteditor/Mono.TextEditor.Utils/RtfWriter.cs @@ -0,0 +1,155 @@ +// +// RtfWriter.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com) +// +// 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. +using System; +using System.Text; +using System.Collections.Generic; + +namespace Mono.TextEditor.Utils +{ + public static class RtfWriter + { + static string CreateColorTable (List<Gdk.Color> colorList) + { + var colorTable = new StringBuilder (); + colorTable.Append (@"{\colortbl ;"); + for (int i = 0; i < colorList.Count; i++) { + Gdk.Color color = colorList [i]; + colorTable.Append (@"\red"); + colorTable.Append (color.Red / 256); + colorTable.Append (@"\green"); + colorTable.Append (color.Green / 256); + colorTable.Append (@"\blue"); + colorTable.Append (color.Blue / 256); + colorTable.Append (";"); + } + colorTable.Append ("}"); + return colorTable.ToString (); + } + + public static string GenerateRtf (TextEditorData data) + { + return GenerateRtf (data.Document, data.Document.SyntaxMode, data.ColorStyle, data.Options); + } + + public static string GenerateRtf (TextDocument doc, Mono.TextEditor.Highlighting.ISyntaxMode mode, Mono.TextEditor.Highlighting.ColorScheme style, ITextEditorOptions options) + { + var rtfText = new StringBuilder (); + var colorList = new List<Gdk.Color> (); + + var selection = new TextSegment (0, doc.TextLength); + int startLineNumber = doc.OffsetToLineNumber (selection.Offset); + int endLineNumber = doc.OffsetToLineNumber (selection.EndOffset); + + bool isItalic = false; + bool isBold = false; + int curColor = -1; + foreach (var line in doc.GetLinesBetween (startLineNumber, endLineNumber)) { + bool appendSpace = false; + foreach (var chunk in mode.GetChunks (style, line, line.Offset, line.Length)) { + int start = System.Math.Max (selection.Offset, chunk.Offset); + int end = System.Math.Min (chunk.EndOffset, selection.EndOffset); + var chunkStyle = style.GetChunkStyle (chunk); + if (start < end) { + if (isBold != chunkStyle.Bold) { + rtfText.Append (chunkStyle.Bold ? @"\b" : @"\b0"); + isBold = chunkStyle.Bold; + appendSpace = true; + } + if (isItalic != chunkStyle.Italic) { + rtfText.Append (chunkStyle.Italic ? @"\i" : @"\i0"); + isItalic = chunkStyle.Italic; + appendSpace = true; + } + if (!colorList.Contains (chunkStyle.Color)) + colorList.Add (chunkStyle.Color); + int color = colorList.IndexOf (chunkStyle.Color); + if (curColor != color) { + curColor = color; + rtfText.Append (@"\cf" + (curColor + 1)); + appendSpace = true; + } + for (int i = start; i < end; i++) { + char ch = doc.GetCharAt (i); + + switch (ch) { + case '\\': + rtfText.Append (@"\\"); + break; + case '{': + rtfText.Append (@"\{"); + break; + case '}': + rtfText.Append (@"\}"); + break; + case '\t': + rtfText.Append (@"\tab"); + appendSpace = true; + break; + default: + if (appendSpace) { + rtfText.Append (' '); + appendSpace = false; + } + rtfText.Append (ch); + break; + } + } + } + } + rtfText.Append (@"\par"); + rtfText.AppendLine (); + } + + var rtf = new StringBuilder(); + + rtf.Append (@"{\rtf1\ansi\deff0\adeflang1025"); + + // font table + rtf.Append (@"{\fonttbl"); + + rtf.Append (@"{\f0\fnil\fprq1\fcharset128 " + options.Font.Family + ";}"); + + rtf.Append ("}"); + + rtf.Append (CreateColorTable (colorList)); + + rtf.Append (@"\viewkind4\uc1\pard"); + + rtf.Append (@"\f0"); + try { + string fontName = options.Font.ToString (); + double fontSize = Double.Parse (fontName.Substring (fontName.LastIndexOf (' ') + 1), System.Globalization.CultureInfo.InvariantCulture) * 2; + rtf.Append (@"\fs"); + rtf.Append (fontSize); + } catch (Exception) {}; + rtf.Append (@"\cf1"); + rtf.Append (rtfText.ToString ()); + rtf.Append("}"); + return rtf.ToString (); + } + } +} + diff --git a/main/src/core/Mono.Texteditor/Mono.TextEditor.csproj b/main/src/core/Mono.Texteditor/Mono.TextEditor.csproj index cbd1477f78..202c24e6bb 100644 --- a/main/src/core/Mono.Texteditor/Mono.TextEditor.csproj +++ b/main/src/core/Mono.Texteditor/Mono.TextEditor.csproj @@ -206,6 +206,7 @@ <Compile Include="Mono.TextEditor\Standalone\IDocumentLine.cs" /> <Compile Include="Mono.TextEditor\Standalone\ITextAnchor.cs" /> <Compile Include="Mono.TextEditor\Standalone\TextLocation.cs" /> + <Compile Include="Mono.TextEditor.Utils\RtfWriter.cs" /> </ItemGroup> <ItemGroup> <None Include="Mono.TextEditor.dll.config"> diff --git a/main/src/core/Mono.Texteditor/Mono.TextEditor/Actions/ClipboardActions.cs b/main/src/core/Mono.Texteditor/Mono.TextEditor/Actions/ClipboardActions.cs index 4fdf900f1b..c024919bf4 100644 --- a/main/src/core/Mono.Texteditor/Mono.TextEditor/Actions/ClipboardActions.cs +++ b/main/src/core/Mono.Texteditor/Mono.TextEditor/Actions/ClipboardActions.cs @@ -34,6 +34,7 @@ using System.Text; using Gtk; using Mono.TextEditor.Highlighting; +using Mono.TextEditor.Utils; namespace Mono.TextEditor { @@ -93,7 +94,7 @@ namespace Mono.TextEditor } break; case RichTextType: - selection_data.Set (RTF_ATOM, UTF8_FORMAT, System.Text.Encoding.UTF8.GetBytes (GenerateRtf (copiedDocument, mode, docStyle, options))); + selection_data.Set (RTF_ATOM, UTF8_FORMAT, System.Text.Encoding.UTF8.GetBytes (RtfWriter.GenerateRtf (copiedDocument, mode, docStyle, options))); break; case MonoTextType: byte[] rawText = System.Text.Encoding.UTF8.GetBytes (monoDocument.Text); @@ -126,122 +127,7 @@ namespace Mono.TextEditor public Mono.TextEditor.Highlighting.ColorScheme docStyle; ITextEditorOptions options; Mono.TextEditor.Highlighting.ISyntaxMode mode; - - static string GenerateRtf (TextDocument doc, Mono.TextEditor.Highlighting.ISyntaxMode mode, Mono.TextEditor.Highlighting.ColorScheme style, ITextEditorOptions options) - { - StringBuilder rtfText = new StringBuilder (); - List<Gdk.Color> colorList = new List<Gdk.Color> (); - - var selection = new TextSegment (0, doc.TextLength); - int startLineNumber = doc.OffsetToLineNumber (selection.Offset); - int endLineNumber = doc.OffsetToLineNumber (selection.EndOffset); - - bool isItalic = false; - bool isBold = false; - int curColor = -1; - - foreach (var line in doc.GetLinesBetween (startLineNumber, endLineNumber)) { - bool appendSpace = false; - foreach (Chunk chunk in mode.GetChunks (style, line, line.Offset, line.Length)) { - int start = System.Math.Max (selection.Offset, chunk.Offset); - int end = System.Math.Min (chunk.EndOffset, selection.EndOffset); - ChunkStyle chunkStyle = style.GetChunkStyle (chunk); - if (start < end) { - if (isBold != chunkStyle.Bold) { - rtfText.Append (chunkStyle.Bold ? @"\b" : @"\b0"); - isBold = chunkStyle.Bold; - appendSpace = true; - } - if (isItalic != chunkStyle.Italic) { - rtfText.Append (chunkStyle.Italic ? @"\i" : @"\i0"); - isItalic = chunkStyle.Italic; - appendSpace = true; - } - if (!colorList.Contains (chunkStyle.Color)) - colorList.Add (chunkStyle.Color); - int color = colorList.IndexOf (chunkStyle.Color); - if (curColor != color) { - curColor = color; - rtfText.Append (@"\cf" + (curColor + 1)); - appendSpace = true; - } - for (int i = start; i < end; i++) { - char ch = doc.GetCharAt (i); - - switch (ch) { - case '\\': - rtfText.Append (@"\\"); - break; - case '{': - rtfText.Append (@"\{"); - break; - case '}': - rtfText.Append (@"\}"); - break; - case '\t': - rtfText.Append (@"\tab"); - appendSpace = true; - break; - default: - if (appendSpace) { - rtfText.Append (' '); - appendSpace = false; - } - rtfText.Append (ch); - break; - } - } - } - } - rtfText.Append (@"\par"); - rtfText.AppendLine (); - } - - // color table - - StringBuilder colorTable = new StringBuilder (); - colorTable.Append (@"{\colortbl ;"); - for (int i = 0; i < colorList.Count; i++) { - Gdk.Color color = colorList[i]; - colorTable.Append (@"\red"); - colorTable.Append (color.Red / 256); - colorTable.Append (@"\green"); - colorTable.Append (color.Green / 256); - colorTable.Append (@"\blue"); - colorTable.Append (color.Blue / 256); - colorTable.Append (";"); - } - colorTable.Append ("}"); - - StringBuilder rtf = new StringBuilder(); - - rtf.Append (@"{\rtf1\ansi\deff0\adeflang1025"); - - // font table - rtf.Append (@"{\fonttbl"); - rtf.Append (@"{\f0\fnil\fprq1\fcharset128 " + options.Font.Family + ";}"); - - rtf.Append ("}"); - - rtf.Append (colorTable.ToString ()); - - rtf.Append (@"\viewkind4\uc1\pard"); - - rtf.Append (@"\f0"); - try { - string fontName = options.Font.ToString (); - double fontSize = Double.Parse (fontName.Substring (fontName.LastIndexOf (' ') + 1), System.Globalization.CultureInfo.InvariantCulture) * 2; - rtf.Append (@"\fs"); - rtf.Append (fontSize); - } catch (Exception) {}; - rtf.Append (@"\cf1"); - rtf.Append (rtfText.ToString ()); - rtf.Append("}"); -// System.Console.WriteLine(rtf); - return rtf.ToString (); - } - public static Gtk.TargetList targetList; static CopyOperation () @@ -274,7 +160,7 @@ namespace Mono.TextEditor monoDocument = new TextDocument (); this.docStyle = data.ColorStyle; this.options = data.Options; - this.mode = data.Document.SyntaxMode != null && data.Options.EnableSyntaxHighlighting ? data.Document.SyntaxMode : new SyntaxMode (data.Document); + this.mode = SyntaxModeService.GetSyntaxMode (monoDocument, data.MimeType); switch (selection.SelectionMode) { case SelectionMode.Normal: isBlockMode = false; diff --git a/main/tests/UnitTests/Makefile.am b/main/tests/UnitTests/Makefile.am index f1a5a90bb7..5d1a97f2b3 100644 --- a/main/tests/UnitTests/Makefile.am +++ b/main/tests/UnitTests/Makefile.am @@ -57,6 +57,7 @@ FILES = \ Mono.TextEditor.Tests/InsertionModeTests.cs \ Mono.TextEditor.Tests/LineSplitterTests.cs \ Mono.TextEditor.Tests/RedBlackTreeTests.cs \ + Mono.TextEditor.Tests/RtfWriterTests.cs \ Mono.TextEditor.Tests/SearchTests.cs \ Mono.TextEditor.Tests/SegmentTreeTests.cs \ Mono.TextEditor.Tests/SelectionTests.cs \ diff --git a/main/tests/UnitTests/Mono.TextEditor.Tests/RtfWriterTests.cs b/main/tests/UnitTests/Mono.TextEditor.Tests/RtfWriterTests.cs new file mode 100644 index 0000000000..c25a137c1f --- /dev/null +++ b/main/tests/UnitTests/Mono.TextEditor.Tests/RtfWriterTests.cs @@ -0,0 +1,49 @@ +// +// RtfWriterTests.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com) +// +// 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. +using System; +using Mono.TextEditor.Utils; +using NUnit.Framework; +using Mono.TextEditor.Highlighting; + +namespace Mono.TextEditor.Tests +{ + [TestFixture()] + public class RtfWriterTests : TextEditorTestBase + { + [Test()] + public void TestSimpleCSharpRtf () + { + var data = Create ("class Foo {}"); + var style = SyntaxModeService.GetColorStyle (null, "TangoLight"); + ISyntaxMode mode = SyntaxModeService.GetSyntaxMode (data.Document, "text/x-csharp"); + string generatedRtf = RtfWriter.GenerateRtf (data.Document, mode, style, data.Options); + Assert.AreEqual ( + @"{\rtf1\ansi\deff0\adeflang1025{\fonttbl{\f0\fnil\fprq1\fcharset128 Mono;}}{\colortbl ;\red92\green53\blue102;\red0\green0\blue0;}\viewkind4\uc1\pard\f0\fs20\cf1\b\cf1 class\b0\cf2 Foo \{\}\par +}", generatedRtf); + } + } +} + diff --git a/main/tests/UnitTests/UnitTests.csproj b/main/tests/UnitTests/UnitTests.csproj index 048ebe77fc..7686f49145 100644 --- a/main/tests/UnitTests/UnitTests.csproj +++ b/main/tests/UnitTests/UnitTests.csproj @@ -234,6 +234,7 @@ <Compile Include="Mono.TextEditor.Tests.DefaultEditActions\FoldActionTests.cs" /> <Compile Include="Mono.TextEditor.Tests.DefaultEditActions\MiscActionsTest.cs" /> <Compile Include="Mono.TextEditor.Tests\BlockSelectionModeTests.cs" /> + <Compile Include="Mono.TextEditor.Tests\RtfWriterTests.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\md.targets" /> |