Skip to content

Commit ba6c9b4

Browse files
committed
Merge pull request #51 from rubberduck-vba/next
sync with merged PR's in main repo
2 parents 1009854 + 5f6abf6 commit ba6c9b4

File tree

8 files changed

+207
-68
lines changed

8 files changed

+207
-68
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 & 1 deletion
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" />
@@ -554,7 +555,6 @@
554555
<DependentUpon>SearchView.xaml</DependentUpon>
555556
</Compile>
556557
<Compile Include="UI\FolderBrowser.cs" />
557-
<Compile Include="UI\GeneralConverters\EqualWidthConverter.cs" />
558558
<Compile Include="UI\IMessageBox.cs" />
559559
<Compile Include="UI\ParserErrors\ParseErrorListItem.cs" />
560560
<Compile Include="UI\Refactorings\EncapsulateFieldDialog.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)

RetailCoder.VBE/UI/GeneralConverters/EqualWidthConverter.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

RetailCoder.VBE/UI/Settings/SettingsControl.xaml

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
66
xmlns:settings="clr-namespace:Rubberduck.UI.Settings"
77
xmlns:converters="clr-namespace:Rubberduck.UI.Settings.Converters"
8-
xmlns:generalConverters="clr-namespace:Rubberduck.UI.GeneralConverters"
98
mc:Ignorable="d"
109
d:DesignHeight="300" d:DesignWidth="600"
1110
d:DataContext="{d:DesignInstance {x:Type settings:SettingsControlViewModel}, IsDesignTimeCreatable=False}">
1211
<UserControl.Resources>
13-
<generalConverters:EqualWidthConverter x:Key="EqualWidthConverter" />
14-
1512
<LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" EndPoint="0,1" StartPoint="0,0">
1613
<GradientStop Color="#FFD9F4FF" Offset="0"/>
1714
<GradientStop Color="#FF9BDDFB" Offset="1"/>
@@ -95,52 +92,33 @@
9592
BorderThickness="0, 1, 0, 0">
9693
<DockPanel VerticalAlignment="Center"
9794
Height="40"
98-
Background="{x:Static SystemColors.ControlDarkBrush}">
99-
<StackPanel Orientation="Horizontal"
100-
HorizontalAlignment="Right">
101-
<Button Name="ResetButton"
102-
Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=Settings_ResetSettings}"
95+
Background="{x:Static SystemColors.ControlDarkBrush}"
96+
Grid.IsSharedSizeScope="True">
97+
<Grid HorizontalAlignment="Right"
98+
Margin="5,0">
99+
<Grid.ColumnDefinitions>
100+
<ColumnDefinition SharedSizeGroup="SettingsButtons" />
101+
<ColumnDefinition SharedSizeGroup="SettingsButtons" />
102+
<ColumnDefinition SharedSizeGroup="SettingsButtons" />
103+
</Grid.ColumnDefinitions>
104+
<Button Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=Settings_ResetSettings}"
103105
Height="20"
104-
HorizontalAlignment="Right"
105-
Margin="20,0"
106-
Padding="10,0"
107-
Command="{Binding ResetButtonCommand}">
108-
<Button.MinWidth>
109-
<MultiBinding Converter="{StaticResource EqualWidthConverter}">
110-
<Binding ElementName="OkButton" Path="ActualWidth" />
111-
<Binding ElementName="CancelButton" Path="ActualWidth" />
112-
</MultiBinding>
113-
</Button.MinWidth>
114-
</Button>
115-
<Button Name="OkButton"
116-
Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=OK}"
106+
Margin="10,0"
107+
Padding="5,0"
108+
Command="{Binding ResetButtonCommand}" />
109+
<Button Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=OK}"
110+
Grid.Column="1"
117111
Height="20"
118-
HorizontalAlignment="Left"
119112
Margin="5,0"
120113
Padding="10,0"
121-
Command="{Binding OKButtonCommand}">
122-
<Button.MinWidth>
123-
<MultiBinding Converter="{StaticResource EqualWidthConverter}">
124-
<Binding ElementName="CancelButton" Path="ActualWidth" />
125-
<Binding ElementName="ResetButton" Path="ActualWidth" />
126-
</MultiBinding>
127-
</Button.MinWidth>
128-
</Button>
129-
<Button Name="CancelButton"
130-
Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=CancelButtonText}"
114+
Command="{Binding OKButtonCommand}" />
115+
<Button Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=CancelButtonText}"
116+
Grid.Column="2"
131117
Height="20"
132-
HorizontalAlignment="Right"
133118
Margin="5,0"
134119
Padding="10,0"
135-
Command="{Binding CancelButtonCommand}">
136-
<Button.MinWidth>
137-
<MultiBinding Converter="{StaticResource EqualWidthConverter}">
138-
<Binding ElementName="OkButton" Path="ActualWidth" />
139-
<Binding ElementName="ResetButton" Path="ActualWidth" />
140-
</MultiBinding>
141-
</Button.MinWidth>
142-
</Button>
143-
</StackPanel>
120+
Command="{Binding CancelButtonCommand}" />
121+
</Grid>
144122
</DockPanel>
145123
</Border>
146124
</Grid>

0 commit comments

Comments
 (0)