Skip to content

Commit 5f6abf6

Browse files
committed
2 parents 718c056 + f737e14 commit 5f6abf6

File tree

6 files changed

+187
-5
lines changed

6 files changed

+187
-5
lines changed

RetailCoder.VBE/Common/ClipboardWriter.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,36 @@ namespace Rubberduck.Common
1010
public interface IClipboardWriter
1111
{
1212
void Write(string text);
13+
void AppendData(string format, object data);
14+
void Flush();
1315
}
1416

1517
public class ClipboardWriter : IClipboardWriter
1618
{
19+
private DataObject _data;
20+
1721
public void Write(string text)
1822
{
19-
Clipboard.SetText(text);
23+
this.AppendData(DataFormats.UnicodeText, text);
24+
this.Flush();
25+
}
26+
27+
public void AppendData(string format, object data)
28+
{
29+
if (_data == null)
30+
{
31+
_data = new DataObject();
32+
}
33+
_data.SetData(format, data);
34+
}
35+
36+
public void Flush()
37+
{
38+
if (_data != null)
39+
{
40+
Clipboard.SetDataObject(_data, true);
41+
_data = null;
42+
}
2043
}
2144
}
2245
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace Rubberduck.Common
9+
{
10+
public static class ExportFormatter
11+
{
12+
public static string Csv(object[][] data, string Title)
13+
{
14+
string s = "";
15+
string[] rows = new string[data.Length];
16+
for (var r = 0; r < data.Length; r++)
17+
{
18+
string[] row = new string[data[r].Length];
19+
for (var c = 0; c < data[r].Length; c++)
20+
{
21+
row[c] = CsvEncode(data[r][c]);
22+
}
23+
rows[r] = string.Join(",", row);
24+
}
25+
return CsvEncode(Title) + Environment.NewLine + string.Join(Environment.NewLine, rows);
26+
}
27+
28+
private static string CsvEncode(object value)
29+
{
30+
string s = "";
31+
if (value is string)
32+
{
33+
s = value.ToString();
34+
35+
//Escape commas
36+
if (s.IndexOf(",") >= 0 || s.IndexOf("\"") >= 0)
37+
{
38+
//replace CrLf with Lf
39+
s = s.Replace("\r\n", "\n");
40+
41+
//escape double-quotes
42+
s = "\"" + s.Replace("\"", "\"\"") + "\"";
43+
}
44+
}
45+
else
46+
{
47+
if (value != null)
48+
{
49+
s = value.ToString();
50+
}
51+
}
52+
return s;
53+
}
54+
55+
public static string HtmlClipboardFragment(object[][] data, string Title)
56+
{
57+
const string OffsetFormat = "0000000000";
58+
const string CFHeaderTemplate =
59+
"Version:1.0\r\n" +
60+
"StartHTML:{0}\r\n" +
61+
"EndHTML:{1}\r\n" +
62+
"StartFragment:{2}\r\n" +
63+
"EndFragment:{3}\r\n";
64+
65+
const string HtmlHeader =
66+
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n" +
67+
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n" +
68+
"<body>\r\n" +
69+
"<!--StartFragment-->\r\n";
70+
71+
const string HtmlFooter =
72+
"<!--EndFragment-->\r\n" +
73+
"</body>\r\n" +
74+
"</html>";
75+
76+
string html = ExportFormatter.HtmlTable(data,Title);
77+
78+
int CFHeaderLength = string.Format(CFHeaderTemplate, OffsetFormat, OffsetFormat, OffsetFormat, OffsetFormat).Length;
79+
int startFragment = CFHeaderLength + HtmlHeader.Length;
80+
int endFragment = startFragment + html.Length;
81+
int endHTML = endFragment + HtmlFooter.Length;
82+
83+
string CfHtml = string.Format(CFHeaderTemplate, CFHeaderLength.ToString(OffsetFormat), endHTML.ToString(OffsetFormat), startFragment.ToString(OffsetFormat), endFragment.ToString(OffsetFormat));
84+
85+
return CfHtml + HtmlHeader + html + HtmlFooter;
86+
}
87+
88+
public static string HtmlTable(object[][] data, string Title)
89+
{
90+
string[] rows = new string[data.Length];
91+
for (var r = 0; r < data.Length; r++)
92+
{
93+
string[] row = new string[data[r].Length];
94+
for (var c = 0; c < data[r].Length; c++)
95+
{
96+
row[c] = HtmlCell(data[r][c], r == data.Length - 1, c == 0 ? 5: 10);
97+
}
98+
rows[r] = " <tr>\r\n" + string.Join(Environment.NewLine, row) + "\r\n</tr>";
99+
}
100+
return "<table cellspacing=\"0\">\r\n" + string.Join(Environment.NewLine, rows) + "\r\n</table>\r\n";
101+
}
102+
103+
private static string HtmlCell(object value, bool BottomBorder = false, int LeftPadding = 10)
104+
{
105+
const string td = " <td style=\"{0}\"><div style=\"{1}\">{2}</div></td>";
106+
const string nbsp = "&#160;";
107+
108+
string CellContent = nbsp;
109+
bool AlignLeft = true;
110+
string Border = BottomBorder ? "0.5pt" : "";
111+
if (value != null)
112+
{
113+
CellContent = value.ToString().HtmlEncode();
114+
AlignLeft = value is string;
115+
}
116+
return string.Format(td, TdStyle(AlignLeft, Border), TdDivStyle(LeftPadding), CellContent);
117+
}
118+
119+
private static string TdStyle(bool AlignLeft = true, string BorderBottom = "")
120+
{
121+
const string tdstyle = "vertical-align: bottom; ";
122+
123+
string sAlign = AlignLeft ? "text-align: left; " : "text-align: right; ";
124+
string sBorder = BorderBottom.Length > 0 ? "border-bottom: " + BorderBottom + " solid #000000; " : "";
125+
126+
return tdstyle + sAlign + sBorder;
127+
}
128+
129+
private static string TdDivStyle(int LeftPadding)
130+
{
131+
return "vertical-align: bottom; padding-left: " + LeftPadding + "px; ";
132+
}
133+
134+
private static string HtmlEncode(this string value)
135+
{
136+
return WebUtility.HtmlEncode(value.ToString());
137+
}
138+
}
139+
}

RetailCoder.VBE/Inspections/ICodeInspectionResult.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ public interface ICodeInspectionResult : IComparable<ICodeInspectionResult>, ICo
1414
QualifiedSelection QualifiedSelection { get; }
1515
IInspection Inspection { get; }
1616
string ToCsvString();
17+
object[] ToArray();
1718
}
1819
}

RetailCoder.VBE/Inspections/InspectionResultBase.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,17 @@ public int CompareTo(object obj)
106106
return CompareTo(obj as ICodeInspectionResult);
107107
}
108108

109+
public object[] ToArray()
110+
{
111+
var module = QualifiedSelection.QualifiedName;
112+
return new object[] {Inspection.Severity.ToString(), Description, module.ProjectName, module.ComponentName, QualifiedSelection.Selection.StartLine };
113+
}
114+
109115
public string ToCsvString()
110116
{
111117
var module = QualifiedSelection.QualifiedName;
112118
return string.Format(
113-
"{0}, {1}, {2}, {3}, {4}",
119+
"\"{0}\",\"{1}\",\"{2}\",\"{3}\",{4}",
114120
Inspection.Severity,
115121
Description,
116122
module.ProjectName,

RetailCoder.VBE/Rubberduck.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@
277277
<ItemGroup>
278278
<Compile Include="AppMenu.cs" />
279279
<Compile Include="AutoSave\AutoSave.cs" />
280+
<Compile Include="Common\ExportFormatter.cs" />
280281
<Compile Include="Common\ClipboardWriter.cs" />
281282
<Compile Include="Common\DeclarationExtensions.cs" />
282283
<Compile Include="Common\Dispatch\DispatcherEventArgs.cs" />

RetailCoder.VBE/UI/CodeInspections/InspectionResultsViewModel.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
using System.Collections.Generic;
33
using System.Collections.ObjectModel;
44
using System.Diagnostics;
5+
using System.Globalization;
56
using System.Linq;
67
using System.Threading;
78
using System.Threading.Tasks;
9+
using System.Windows;
810
using System.Windows.Data;
911
using System.Windows.Input;
1012
using System.Windows.Threading;
@@ -283,14 +285,24 @@ private void ExecuteCopyResultsCommand(object parameter)
283285
{
284286
return;
285287
}
288+
var aResults = _results.Select(result => result.ToArray()).ToArray();
286289

287-
var results = string.Join("\n", _results.Select(result => result.ToString() + Environment.NewLine).ToArray());
288290
var resource = _results.Count == 1
289291
? RubberduckUI.CodeInspections_NumberOfIssuesFound_Singular
290292
: RubberduckUI.CodeInspections_NumberOfIssuesFound_Plural;
291-
var text = string.Format(resource, DateTime.Now, _results.Count) + Environment.NewLine + results;
292293

293-
_clipboard.Write(text);
294+
var title = string.Format(resource, DateTime.Now.ToString(CultureInfo.InstalledUICulture), _results.Count);
295+
296+
var textResults = title + Environment.NewLine + string.Join("", _results.Select(result => result.ToString() + Environment.NewLine).ToArray());
297+
var csvResults = ExportFormatter.Csv(aResults, title);
298+
var htmlResults = ExportFormatter.HtmlClipboardFragment(aResults, title);
299+
300+
//Add the formats from richest formatting to least formatting
301+
_clipboard.AppendData(DataFormats.Html, htmlResults);
302+
_clipboard.AppendData(DataFormats.CommaSeparatedValue, csvResults);
303+
_clipboard.AppendData(DataFormats.UnicodeText, textResults);
304+
305+
_clipboard.Flush();
294306
}
295307

296308
private bool CanExecuteCopyResultsCommand(object parameter)

0 commit comments

Comments
 (0)