Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4918 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
33 changed files with 4857 additions and 166 deletions
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
<UserControl x:Class="ICSharpCode.StartPage.RecentProjectsControl" |
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
xmlns:core="http://icsharpcode.net/sharpdevelop/core"> |
||||
<StackPanel Orientation="Vertical"> |
||||
<ListView Name="lastProjectsListView" SelectionMode="Single" MouseDoubleClick="lastProjectsDoubleClick" KeyDown="lastProjectsKeyDown"> |
||||
<ListView.Resources> |
||||
<DataTemplate x:Key="nameCellTemplate"> |
||||
<TextBlock> |
||||
<Hyperlink Tag="{Binding}" Click="listViewHyperlinkClick"> |
||||
<TextBlock Text="{Binding Path=Name}" /> |
||||
</Hyperlink> |
||||
</TextBlock> |
||||
</DataTemplate> |
||||
</ListView.Resources> |
||||
<ListView.View> |
||||
<GridView> |
||||
<GridViewColumn CellTemplate="{StaticResource nameCellTemplate}" Header="{core:Localize Global.Name}" /> |
||||
<GridViewColumn DisplayMemberBinding="{Binding Path=LastModification}" Header="{core:Localize StartPage.StartMenu.ModifiedTable}" /> |
||||
<GridViewColumn DisplayMemberBinding="{Binding Path=Path}" Header="{core:Localize StartPage.StartMenu.LocationTable}" /> |
||||
</GridView> |
||||
</ListView.View> |
||||
</ListView> |
||||
<StackPanel Orientation="Horizontal" Margin="0,20,0,0"> |
||||
<Button Content="{core:Localize StartPage.StartMenu.OpenCombineButton}" Click="openSolutionClick" /> |
||||
<Button Content="{core:Localize StartPage.StartMenu.NewCombineButton}" Click="newSolutionClick" Margin="8,0,0,0" /> |
||||
</StackPanel> |
||||
</StackPanel> |
||||
</UserControl> |
||||
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Documents; |
||||
using System.Windows.Input; |
||||
|
||||
using ICSharpCode.Core.Presentation; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
|
||||
namespace ICSharpCode.StartPage |
||||
{ |
||||
/// <summary>
|
||||
/// Interaction logic for RecentProjectsControl.xaml
|
||||
/// </summary>
|
||||
public partial class RecentProjectsControl : UserControl |
||||
{ |
||||
public RecentProjectsControl() |
||||
{ |
||||
InitializeComponent(); |
||||
|
||||
SetBinding(HeaderProperty, new LocalizeExtension("StartPage.StartMenu.BarNameName").CreateBinding()); |
||||
BuildRecentProjectList(); |
||||
} |
||||
|
||||
public static readonly DependencyProperty HeaderProperty = HeaderedContentControl.HeaderProperty.AddOwner(typeof(RecentProjectsControl)); |
||||
|
||||
public object Header { |
||||
get { return GetValue(HeaderProperty); } |
||||
set { SetValue(HeaderProperty, value); } |
||||
} |
||||
|
||||
void BuildRecentProjectList() |
||||
{ |
||||
List<RecentOpenItem> items = new List<RecentOpenItem>(); |
||||
foreach (string path in FileService.RecentOpen.RecentProject) { |
||||
FileInfo file = new FileInfo(path); |
||||
if (file.Exists) { |
||||
items.Add( |
||||
new RecentOpenItem { |
||||
Name = System.IO.Path.GetFileNameWithoutExtension(path), |
||||
LastModification = file.LastWriteTime.ToShortDateString(), |
||||
Path = path |
||||
}); |
||||
} |
||||
} |
||||
lastProjectsListView.ItemsSource = items; |
||||
} |
||||
|
||||
class RecentOpenItem |
||||
{ |
||||
public string Name { get; set; } |
||||
public string LastModification { get; set; } |
||||
public string Path { get; set; } |
||||
} |
||||
|
||||
void lastProjectsDoubleClick(object sender, RoutedEventArgs e) |
||||
{ |
||||
RecentOpenItem item = (RecentOpenItem)lastProjectsListView.SelectedItem; |
||||
if (item != null) { |
||||
ProjectService.LoadSolutionOrProject(item.Path); |
||||
} |
||||
} |
||||
|
||||
void lastProjectsKeyDown(object sender, KeyEventArgs e) |
||||
{ |
||||
if (e.Key == Key.Return) { |
||||
lastProjectsDoubleClick(null, null); |
||||
} |
||||
} |
||||
|
||||
void listViewHyperlinkClick(object sender, RoutedEventArgs e) |
||||
{ |
||||
RecentOpenItem item = (RecentOpenItem)((Hyperlink)sender).Tag; |
||||
ProjectService.LoadSolutionOrProject(item.Path); |
||||
} |
||||
|
||||
void openSolutionClick(object sender, RoutedEventArgs e) |
||||
{ |
||||
new ICSharpCode.SharpDevelop.Project.Commands.LoadSolution().Run(); |
||||
} |
||||
|
||||
void newSolutionClick(object sender, RoutedEventArgs e) |
||||
{ |
||||
new ICSharpCode.SharpDevelop.Project.Commands.CreateNewSolution().Run(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,144 @@
@@ -0,0 +1,144 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.Core.Services; |
||||
using ICSharpCode.SharpDevelop; |
||||
using System.IO; |
||||
|
||||
namespace ICSharpCode.UsageDataCollector |
||||
{ |
||||
/// <summary>
|
||||
/// Main singleton class of the analytics. This class is thread-safe.
|
||||
/// </summary>
|
||||
public sealed class AnalyticsMonitor : IAnalyticsMonitor |
||||
{ |
||||
public static readonly AnalyticsMonitor Instance = new AnalyticsMonitor(); |
||||
|
||||
public static bool EnabledIsUndecided { |
||||
get { |
||||
return string.IsNullOrEmpty(PropertyService.Get("ICSharpCode.UsageDataCollector.Enabled")); |
||||
} |
||||
} |
||||
|
||||
public static bool Enabled { |
||||
get { |
||||
return string.Equals(PropertyService.Get("ICSharpCode.UsageDataCollector.Enabled"), bool.TrueString, StringComparison.OrdinalIgnoreCase); |
||||
} |
||||
set { |
||||
PropertyService.Set("ICSharpCode.UsageDataCollector.Enabled", value.ToString()); |
||||
if (value) { |
||||
Instance.OpenSession(); |
||||
} else { |
||||
Instance.CloseSession(); |
||||
Instance.TryDeleteDatabase(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
readonly object lockObj = new object(); |
||||
string dbFileName; |
||||
AnalyticsSessionWriter session; |
||||
|
||||
private AnalyticsMonitor() |
||||
{ |
||||
var container = ServiceManager.Instance.GetRequiredService<ThreadSafeServiceContainer>(); |
||||
container.TryAddService(typeof(IAnalyticsMonitor), this); |
||||
dbFileName = Path.Combine(PropertyService.ConfigDirectory, "usageData.dat"); |
||||
|
||||
SharpDevelop.Gui.WorkbenchSingleton.WorkbenchUnloaded += delegate { CloseSession(); }; |
||||
} |
||||
|
||||
public void OpenSession() |
||||
{ |
||||
lock (lockObj) { |
||||
if (session == null) { |
||||
try { |
||||
session = new AnalyticsSessionWriter(dbFileName); |
||||
} catch (DatabaseTooNewException) { |
||||
LoggingService.Warn("Could not use AnalyticsMonitor: too new version of database"); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void TryDeleteDatabase() |
||||
{ |
||||
lock (lockObj) { |
||||
CloseSession(); |
||||
try { |
||||
File.Delete(dbFileName); |
||||
} catch (IOException) { |
||||
} catch (AccessViolationException) { |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void CloseSession() |
||||
{ |
||||
lock (lockObj) { |
||||
if (session != null) { |
||||
session.Dispose(); |
||||
session = null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void TrackException(Exception exception) |
||||
{ |
||||
lock (lockObj) { |
||||
if (session != null) { |
||||
// TODO: recognize inner exceptions
|
||||
session.AddException(exception.GetType().FullName, exception.StackTrace); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public IAnalyticsMonitorTrackedFeature TrackFeature(string featureName, string activationMethod) |
||||
{ |
||||
TrackedFeature feature = new TrackedFeature(); |
||||
lock (lockObj) { |
||||
if (session != null) { |
||||
feature.IsTracked = true; |
||||
feature.FeatureID = session.AddFeatureUse(featureName, activationMethod); |
||||
} |
||||
} |
||||
return feature; |
||||
} |
||||
|
||||
void EndTracking(TrackedFeature feature) |
||||
{ |
||||
lock (lockObj) { |
||||
if (session != null && feature.IsTracked) { |
||||
feature.IsTracked = false; |
||||
session.WriteEndTimeForFeature(feature.FeatureID); |
||||
} |
||||
} |
||||
} |
||||
|
||||
sealed class TrackedFeature : IAnalyticsMonitorTrackedFeature |
||||
{ |
||||
internal bool IsTracked; |
||||
internal long FeatureID; |
||||
|
||||
public void EndTracking() |
||||
{ |
||||
Instance.EndTracking(this); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public class AutoStartCommand : AbstractCommand |
||||
{ |
||||
public override void Run() |
||||
{ |
||||
if (AnalyticsMonitor.Enabled) |
||||
AnalyticsMonitor.Instance.OpenSession(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,189 @@
@@ -0,0 +1,189 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using ICSharpCode.Core; |
||||
using System; |
||||
using System.Data.SQLite; |
||||
using System.Runtime.Serialization; |
||||
|
||||
namespace ICSharpCode.UsageDataCollector |
||||
{ |
||||
/// <summary>
|
||||
/// Creates an analytics session.
|
||||
/// </summary>
|
||||
public class AnalyticsSessionWriter : IDisposable |
||||
{ |
||||
SQLiteConnection connection; |
||||
long sessionID; |
||||
|
||||
public AnalyticsSessionWriter(string databaseFileName) |
||||
{ |
||||
SQLiteConnectionStringBuilder conn = new SQLiteConnectionStringBuilder(); |
||||
conn.Add("Data Source", databaseFileName); |
||||
|
||||
connection = new SQLiteConnection(conn.ConnectionString); |
||||
connection.Open(); |
||||
InitializeTables(); |
||||
|
||||
StartSession(); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates or upgrades the database
|
||||
/// </summary>
|
||||
void InitializeTables() |
||||
{ |
||||
using (SQLiteTransaction transaction = this.connection.BeginTransaction()) { |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = @"
|
||||
CREATE TABLE IF NOT EXISTS Properties ( |
||||
name TEXT NOT NULL PRIMARY KEY, |
||||
value TEXT NOT NULL |
||||
); |
||||
INSERT OR IGNORE INTO Properties (name, value) VALUES ('dbVersion', '1.0'); |
||||
INSERT OR IGNORE INTO Properties (name, value) VALUES ('userID', '" + Guid.NewGuid().ToString() + @"'); |
||||
";
|
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = "SELECT value FROM Properties WHERE name = 'dbVersion';"; |
||||
string version = (string)cmd.ExecuteScalar(); |
||||
if (version == null) |
||||
throw new InvalidOperationException("Error retrieving database version"); |
||||
if (version != "1.0") { |
||||
throw new DatabaseTooNewException(); |
||||
} |
||||
} |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = @"
|
||||
CREATE TABLE IF NOT EXISTS Sessions ( |
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |
||||
startTime TEXT NOT NULL, |
||||
endTime TEXT, |
||||
appVersion TEXT, |
||||
platform TEXT, |
||||
osVersion TEXT, |
||||
processorCount INTEGER, |
||||
dotnetRuntime TEXT, |
||||
language TEXT |
||||
); |
||||
CREATE TABLE IF NOT EXISTS FeatureUses ( |
||||
session INTEGER NOT NULL, |
||||
time TEXT NOT NULL, |
||||
endTime TEXT, |
||||
feature TEXT NOT NULL, |
||||
activationMethod TEXT |
||||
); |
||||
CREATE TABLE IF NOT EXISTS Exceptions ( |
||||
session INTEGER NOT NULL, |
||||
time TEXT NOT NULL, |
||||
type TEXT NOT NULL, |
||||
stackTrace TEXT |
||||
); |
||||
";
|
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
transaction.Commit(); |
||||
} |
||||
} |
||||
|
||||
void StartSession() |
||||
{ |
||||
using (SQLiteTransaction transaction = this.connection.BeginTransaction()) { |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = "INSERT INTO Sessions (startTime, appVersion, platform, osVersion, processorCount, dotnetRuntime, language)" + |
||||
" VALUES (datetime(), ?, ?, ?, ?, ?, ?);"; |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = RevisionClass.FullVersion }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = Environment.OSVersion.Platform.ToString() }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = Environment.OSVersion.Version.ToString() }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = Environment.ProcessorCount }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = Environment.Version.ToString() }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = ICSharpCode.Core.ResourceService.Language }); |
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = "SELECT last_insert_rowid();"; |
||||
sessionID = (long)cmd.ExecuteScalar(); |
||||
} |
||||
transaction.Commit(); |
||||
} |
||||
} |
||||
|
||||
void EndSession() |
||||
{ |
||||
using (SQLiteTransaction transaction = this.connection.BeginTransaction()) { |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = "UPDATE Sessions SET endTime = datetime() WHERE id = ?;"; |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = sessionID }); |
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
transaction.Commit(); |
||||
} |
||||
} |
||||
|
||||
public long AddFeatureUse(string featureName, string activationMethod) |
||||
{ |
||||
long featureRowId; |
||||
using (SQLiteTransaction transaction = this.connection.BeginTransaction()) { |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = "INSERT INTO FeatureUses (session, time, feature, activationMethod)" + |
||||
" VALUES (?, datetime(), ?, ?);"; |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = sessionID }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = featureName }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = activationMethod }); |
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = "SELECT last_insert_rowid();"; |
||||
featureRowId = (long)cmd.ExecuteScalar(); |
||||
} |
||||
transaction.Commit(); |
||||
} |
||||
return featureRowId; |
||||
} |
||||
|
||||
public void WriteEndTimeForFeature(long featureID) |
||||
{ |
||||
using (SQLiteTransaction transaction = this.connection.BeginTransaction()) { |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = "UPDATE FeatureUses SET endTime = datetime() WHERE ROWID = ?;"; |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = featureID }); |
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
transaction.Commit(); |
||||
} |
||||
} |
||||
|
||||
public void AddException(string exceptionType, string stacktrace) |
||||
{ |
||||
using (SQLiteTransaction transaction = this.connection.BeginTransaction()) { |
||||
using (SQLiteCommand cmd = this.connection.CreateCommand()) { |
||||
cmd.CommandText = "INSERT INTO Exceptions (session, time, type, stackTrace)" + |
||||
" VALUES (?, datetime(), ?, ?);"; |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = sessionID }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = exceptionType }); |
||||
cmd.Parameters.Add(new SQLiteParameter { Value = stacktrace }); |
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
transaction.Commit(); |
||||
} |
||||
} |
||||
|
||||
public void Dispose() |
||||
{ |
||||
EndSession(); |
||||
connection.Close(); |
||||
} |
||||
} |
||||
|
||||
[Serializable] |
||||
public class DatabaseTooNewException : Exception |
||||
{ |
||||
public DatabaseTooNewException() {} |
||||
protected DatabaseTooNewException(SerializationInfo info, StreamingContext context) : base(info, context) {} |
||||
} |
||||
} |
||||
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
#region Using directives
|
||||
|
||||
using System; |
||||
using System.Reflection; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
#endregion
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UsageDataCollector")] |
||||
[assembly: AssemblyDescription("Collects usage data and sends it to the SharpDevelop team")] |
||||
[assembly: AssemblyConfiguration("")] |
||||
[assembly: AssemblyTrademark("")] |
||||
[assembly: AssemblyCulture("")] |
||||
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
<gui:OptionPanel x:Class="ICSharpCode.UsageDataCollector.OptionPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:gui="clr-namespace:ICSharpCode.SharpDevelop.Gui;assembly=ICSharpCode.SharpDevelop" xmlns:core="http://icsharpcode.net/sharpdevelop/core" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
||||
<StackPanel> |
||||
<TextBlock TextWrapping="Wrap"> |
||||
We need your help! To improve SharpDevelop in the future, we would like to know which features are used most.<LineBreak /> |
||||
SharpDevelop can collect this information and upload it automatically. |
||||
</TextBlock> |
||||
<RadioButton Name="acceptRadio">I would like to participate - collect and upload usage data</RadioButton> |
||||
<RadioButton Name="declineRadio">I do not want to participate</RadioButton> |
||||
<TextBlock HorizontalAlignment="Left"> |
||||
<Hyperlink NavigateUri="http://www.example.com/UsageData">Privacy Statement</Hyperlink> |
||||
</TextBlock> |
||||
</StackPanel> |
||||
</gui:OptionPanel> |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
|
||||
namespace ICSharpCode.UsageDataCollector |
||||
{ |
||||
/// <summary>
|
||||
/// Interaction logic for OptionPage.xaml
|
||||
/// </summary>
|
||||
public partial class OptionPage : OptionPanel |
||||
{ |
||||
public OptionPage() |
||||
{ |
||||
InitializeComponent(); |
||||
} |
||||
|
||||
public override void LoadOptions() |
||||
{ |
||||
base.LoadOptions(); |
||||
if (!AnalyticsMonitor.EnabledIsUndecided) { |
||||
if (AnalyticsMonitor.Enabled) |
||||
acceptRadio.IsChecked = true; |
||||
else |
||||
declineRadio.IsChecked = true; |
||||
} |
||||
} |
||||
|
||||
public override bool SaveOptions() |
||||
{ |
||||
if (acceptRadio.IsChecked ?? false) |
||||
AnalyticsMonitor.Enabled = true; |
||||
else if (declineRadio.IsChecked ?? false) |
||||
AnalyticsMonitor.Enabled = false; |
||||
return base.SaveOptions(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<UserControl |
||||
x:Class="ICSharpCode.UsageDataCollector.StartPageMessage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:core="http://icsharpcode.net/sharpdevelop/core"> |
||||
<StackPanel> |
||||
<core:CollapsiblePanel |
||||
Name="mainPanel"> |
||||
<StackPanel> |
||||
<TextBlock |
||||
TextWrapping="Wrap"> |
||||
We need your help! To improve SharpDevelop in the future, we would like to know which features are used most.<LineBreak /> |
||||
SharpDevelop can collect this information and upload it automatically. |
||||
</TextBlock> |
||||
<RadioButton |
||||
Name="acceptRadio" |
||||
Checked="Radio_Checked">I would like to participate - collect and upload usage data</RadioButton> |
||||
<RadioButton |
||||
Name="declineRadio" |
||||
Checked="Radio_Checked">I do not want to participate</RadioButton> |
||||
<Button |
||||
Name="saveButton" |
||||
IsEnabled="False" |
||||
HorizontalAlignment="Left" |
||||
Margin="16 4" |
||||
Width="75" |
||||
Height="23" |
||||
Click="SaveButton_Click">Save</Button> |
||||
</StackPanel> |
||||
</core:CollapsiblePanel> |
||||
<core:CollapsiblePanel |
||||
Name="acceptedMessage" |
||||
IsCollapsed="True"> |
||||
<TextBlock> |
||||
Thank you for participating! You can still opt-out later using the SharpDevelop options. |
||||
</TextBlock> |
||||
</core:CollapsiblePanel> |
||||
<core:CollapsiblePanel |
||||
Name="declinedMessage" |
||||
IsCollapsed="True"> |
||||
<TextBlock> |
||||
You can still opt-in later using the SharpDevelop options. |
||||
</TextBlock> |
||||
</core:CollapsiblePanel> |
||||
<TextBlock |
||||
HorizontalAlignment="Left"> |
||||
<Hyperlink |
||||
NavigateUri="http://www.example.com/UsageData">Privacy Statement</Hyperlink> |
||||
</TextBlock> |
||||
</StackPanel> |
||||
</UserControl> |
||||
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Text; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Data; |
||||
using System.Windows.Documents; |
||||
using System.Windows.Input; |
||||
using System.Windows.Media; |
||||
|
||||
namespace ICSharpCode.UsageDataCollector |
||||
{ |
||||
/// <summary>
|
||||
/// Interaction logic for StartPageMessage.xaml
|
||||
/// </summary>
|
||||
public partial class StartPageMessage : UserControl |
||||
{ |
||||
public StartPageMessage() |
||||
{ |
||||
InitializeComponent(); |
||||
|
||||
this.Header = "Usage Data Collection"; |
||||
} |
||||
|
||||
void Radio_Checked(object sender, RoutedEventArgs e) |
||||
{ |
||||
saveButton.IsEnabled = true; |
||||
} |
||||
|
||||
void SaveButton_Click(object sender, RoutedEventArgs e) |
||||
{ |
||||
bool accepted = acceptRadio.IsChecked ?? false; |
||||
AnalyticsMonitor.Enabled = accepted; |
||||
mainPanel.IsCollapsed = true; |
||||
acceptedMessage.IsCollapsed = !accepted; |
||||
declinedMessage.IsCollapsed = accepted; |
||||
} |
||||
|
||||
public static readonly DependencyProperty HeaderProperty = HeaderedContentControl.HeaderProperty.AddOwner(typeof(StartPageMessage)); |
||||
|
||||
public object Header { |
||||
get { return GetValue(HeaderProperty); } |
||||
set { SetValue(HeaderProperty, value); } |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
<AddIn name = "Usage Data Collector" |
||||
author = "Daniel Grunwald" |
||||
url = "" |
||||
description = "Collects usage data and sends it to the SharpDevelop team" |
||||
addInManagerHidden = "preinstalled"> |
||||
|
||||
<Manifest> |
||||
<Identity name = "ICSharpCode.UsageDataCollector"/> |
||||
</Manifest> |
||||
|
||||
<Runtime> |
||||
<Import assembly = "UsageDataCollector.dll"/> |
||||
</Runtime> |
||||
|
||||
<Path name = "/SharpDevelop/ViewContent/StartPage/Items"> |
||||
<Condition name = "Compare" string = "${property:ICSharpCode.UsageDataCollector.Enabled}" equals = ""> |
||||
<Class id = "UsageDataCollector" |
||||
insertbefore = "RecentProjects" |
||||
class = "ICSharpCode.UsageDataCollector.StartPageMessage"/> |
||||
</Condition> |
||||
</Path> |
||||
|
||||
<Path name = "/Workspace/Autostart"> |
||||
<Condition name = "Compare" string = "${property:ICSharpCode.UsageDataCollector.Enabled}" equals = "True"> |
||||
<Class id = "UsageDataCollector" |
||||
class = "ICSharpCode.UsageDataCollector.AutoStartCommand"/> |
||||
</Condition> |
||||
</Path> |
||||
|
||||
<Path name="/SharpDevelop/Dialogs/OptionsDialog/UIOptions"> |
||||
<OptionPanel id = "UsageDataCollector" |
||||
label = "Usage Data Collector" |
||||
class = "ICSharpCode.UsageDataCollector.OptionPage" /> |
||||
</Path> |
||||
</AddIn> |
||||
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> |
||||
<PropertyGroup> |
||||
<ProjectGuid>{6B1CFE35-DA17-4DEB-9C6E-227E5E251DA0}</ProjectGuid> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
<OutputType>Library</OutputType> |
||||
<RootNamespace>ICSharpCode.UsageDataCollector</RootNamespace> |
||||
<AssemblyName>UsageDataCollector</AssemblyName> |
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
||||
<OutputPath>..\..\..\..\AddIns\AddIns\Misc\UsageDataCollector\</OutputPath> |
||||
<AllowUnsafeBlocks>False</AllowUnsafeBlocks> |
||||
<NoStdLib>False</NoStdLib> |
||||
<WarningLevel>4</WarningLevel> |
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' "> |
||||
<PlatformTarget>AnyCPU</PlatformTarget> |
||||
<RegisterForComInterop>False</RegisterForComInterop> |
||||
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> |
||||
<BaseAddress>4194304</BaseAddress> |
||||
<FileAlignment>4096</FileAlignment> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>Full</DebugType> |
||||
<Optimize>False</Optimize> |
||||
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> |
||||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> |
||||
<DebugSymbols>False</DebugSymbols> |
||||
<DebugType>None</DebugType> |
||||
<Optimize>True</Optimize> |
||||
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> |
||||
<DefineConstants>TRACE</DefineConstants> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Reference Include="PresentationCore"> |
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework> |
||||
</Reference> |
||||
<Reference Include="PresentationFramework"> |
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework> |
||||
</Reference> |
||||
<Reference Include="System" /> |
||||
<Reference Include="System.Data" /> |
||||
<Reference Include="System.Data.SQLite"> |
||||
<HintPath>..\..\..\Libraries\SQLite\System.Data.SQLite.dll</HintPath> |
||||
<Private>True</Private> |
||||
</Reference> |
||||
<Reference Include="System.Drawing" /> |
||||
<Reference Include="System.Windows.Forms" /> |
||||
<Reference Include="System.Xml" /> |
||||
<Reference Include="WindowsBase"> |
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework> |
||||
</Reference> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<None Include="UsageDataCollector.addin"> |
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
||||
</None> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Compile Include="..\..\..\Main\GlobalAssemblyInfo.cs"> |
||||
<Link>Configuration\GlobalAssemblyInfo.cs</Link> |
||||
</Compile> |
||||
<Compile Include="AnalyticsMonitor.cs" /> |
||||
<Compile Include="AnalyticsSessionWriter.cs" /> |
||||
<Compile Include="Configuration\AssemblyInfo.cs" /> |
||||
<Compile Include="OptionPage.xaml.cs"> |
||||
<DependentUpon>OptionPage.xaml</DependentUpon> |
||||
<SubType>Code</SubType> |
||||
</Compile> |
||||
<Compile Include="StartPageMessage.xaml.cs"> |
||||
<DependentUpon>StartPageMessage.xaml</DependentUpon> |
||||
<SubType>Code</SubType> |
||||
</Compile> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Page Include="OptionPage.xaml" /> |
||||
<Page Include="StartPageMessage.xaml" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<ProjectReference Include="..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj"> |
||||
<Project>{2748AD25-9C63-4E12-877B-4DCE96FBED54}</Project> |
||||
<Name>ICSharpCode.SharpDevelop</Name> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\..\..\Main\Core\Project\ICSharpCode.Core.csproj"> |
||||
<Project>{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}</Project> |
||||
<Name>ICSharpCode.Core</Name> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\..\..\Main\ICSharpCode.Core.Presentation\ICSharpCode.Core.Presentation.csproj"> |
||||
<Project>{7E4A7172-7FF5-48D0-B719-7CD959DD1AC9}</Project> |
||||
<Name>ICSharpCode.Core.Presentation</Name> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
</ItemGroup> |
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> |
||||
</Project> |
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using ICSharpCode.Core.Services; |
||||
using System; |
||||
|
||||
namespace ICSharpCode.Core |
||||
{ |
||||
/// <summary>
|
||||
/// Allows marking the end-time of feature uses.
|
||||
/// </summary>
|
||||
/// <remarks>Implementations of this interface must be thread-safe.</remarks>
|
||||
public interface IAnalyticsMonitorTrackedFeature |
||||
{ |
||||
void EndTracking(); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Allows tracking feature use.
|
||||
/// All methods on this class are thread-safe.
|
||||
/// </summary>
|
||||
public static class AnalyticsMonitorService |
||||
{ |
||||
/// <summary>
|
||||
/// Tracks an exception that has occurred.
|
||||
/// </summary>
|
||||
public static void TrackException(Exception exception) |
||||
{ |
||||
if (exception == null) |
||||
throw new ArgumentNullException("exception"); |
||||
IAnalyticsMonitor monitor = ServiceManager.Instance.GetService<IAnalyticsMonitor>(); |
||||
if (monitor != null) { |
||||
monitor.TrackException(exception); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Tracks a feature use.
|
||||
/// </summary>
|
||||
/// <param name="featureName">Name of the feature</param>
|
||||
/// <returns>Object that can be used to 'end' the feature use, if measuring time spans is desired.</returns>
|
||||
public static IAnalyticsMonitorTrackedFeature TrackFeature(string featureName) |
||||
{ |
||||
return TrackFeature(featureName, null); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Tracks a feature use.
|
||||
/// </summary>
|
||||
/// <param name="featureName">Name of the feature</param>
|
||||
/// <param name="activationMethod">Method used to 'activate' the feature (e.g. Menu, Toolbar, Shortcut, etc.)</param>
|
||||
/// <returns>Object that can be used to 'end' the feature use, if measuring time spans is desired.</returns>
|
||||
public static IAnalyticsMonitorTrackedFeature TrackFeature(string featureName, string activationMethod) |
||||
{ |
||||
if (featureName == null) |
||||
throw new ArgumentNullException("featureName"); |
||||
|
||||
if (activationMethod != null) |
||||
LoggingService.Debug("Activated feature '" + featureName + "', activation=" + activationMethod); |
||||
else |
||||
LoggingService.Debug("Activated feature '" + featureName + "'"); |
||||
|
||||
IAnalyticsMonitor monitor = ServiceManager.Instance.GetService<IAnalyticsMonitor>(); |
||||
if (monitor != null) { |
||||
return monitor.TrackFeature(featureName, activationMethod) ?? DummyFeature.Instance; |
||||
} else { |
||||
return DummyFeature.Instance; |
||||
} |
||||
} |
||||
|
||||
sealed class DummyFeature : IAnalyticsMonitorTrackedFeature |
||||
{ |
||||
public static readonly DummyFeature Instance = new DummyFeature(); |
||||
|
||||
public void EndTracking() |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
|
||||
namespace ICSharpCode.Core.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Interface for AnalyticsMonitorService.
|
||||
/// </summary>
|
||||
/// <remarks>Implementations of this interface must be thread-safe.</remarks>
|
||||
public interface IAnalyticsMonitor |
||||
{ |
||||
void TrackException(Exception exception); |
||||
IAnalyticsMonitorTrackedFeature TrackFeature(string featureName, string activationMethod); |
||||
} |
||||
} |
||||
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Data; |
||||
using System.Windows.Media.Animation; |
||||
|
||||
namespace ICSharpCode.Core.Presentation |
||||
{ |
||||
/// <summary>
|
||||
/// Allows animated collapsing of the content of this panel.
|
||||
/// </summary>
|
||||
public class CollapsiblePanel : ContentControl |
||||
{ |
||||
static CollapsiblePanel() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(CollapsiblePanel), |
||||
new FrameworkPropertyMetadata(typeof(CollapsiblePanel))); |
||||
} |
||||
|
||||
public static readonly DependencyProperty IsCollapsedProperty = DependencyProperty.Register( |
||||
"IsCollapsed", typeof(bool), typeof(CollapsiblePanel), |
||||
new UIPropertyMetadata(false, new PropertyChangedCallback(OnIsCollapsedChanged))); |
||||
|
||||
public bool IsCollapsed { |
||||
get { return (bool)GetValue(IsCollapsedProperty); } |
||||
set { SetValue(IsCollapsedProperty, value); } |
||||
} |
||||
|
||||
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register( |
||||
"Duration", typeof(TimeSpan), typeof(CollapsiblePanel), |
||||
new UIPropertyMetadata(TimeSpan.FromMilliseconds(500))); |
||||
|
||||
/// <summary>
|
||||
/// The duration in milliseconds of the animation.
|
||||
/// </summary>
|
||||
public TimeSpan Duration { |
||||
get { return (TimeSpan)GetValue(DurationProperty); } |
||||
set { SetValue(DurationProperty, value); } |
||||
} |
||||
|
||||
protected internal static readonly DependencyProperty AnimationProgressProperty = DependencyProperty.Register( |
||||
"AnimationProgress", typeof(double), typeof(CollapsiblePanel), |
||||
new FrameworkPropertyMetadata(1.0)); |
||||
|
||||
/// <summary>
|
||||
/// Value between 0 and 1 specifying how far the animation currently is.
|
||||
/// </summary>
|
||||
protected internal double AnimationProgress { |
||||
get { return (double)GetValue(AnimationProgressProperty); } |
||||
set { SetValue(AnimationProgressProperty, value); } |
||||
} |
||||
|
||||
static void OnIsCollapsedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
{ |
||||
((CollapsiblePanel)d).SetupAnimation((bool)e.NewValue); |
||||
} |
||||
|
||||
void SetupAnimation(bool isCollapsed) |
||||
{ |
||||
if (this.IsLoaded) { |
||||
// If the animation is already running, calculate remaining portion of the time
|
||||
double currentProgress = AnimationProgress; |
||||
if (!isCollapsed) { |
||||
currentProgress = 1.0 - currentProgress; |
||||
} |
||||
|
||||
DoubleAnimation animation = new DoubleAnimation(); |
||||
animation.To = isCollapsed ? 0.0 : 1.0; |
||||
animation.Duration = TimeSpan.FromSeconds(Duration.TotalSeconds * currentProgress); |
||||
animation.FillBehavior = FillBehavior.HoldEnd; |
||||
|
||||
this.BeginAnimation(AnimationProgressProperty, animation); |
||||
} else { |
||||
this.AnimationProgress = isCollapsed ? 0.0 : 1.0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
sealed class CollapsiblePanelProgressToVisibilityConverter : IValueConverter |
||||
{ |
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) |
||||
{ |
||||
if (value is double) |
||||
return (double)value > 0 ? Visibility.Visible : Visibility.Collapsed; |
||||
else |
||||
return Visibility.Visible; |
||||
} |
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue