diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs index f5641c67b0..bb20aaf261 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs @@ -285,9 +285,14 @@ namespace ICSharpCode.AvalonEdit.AddIn this.Encoding = reader.CurrentEncoding; } } + // raise event which allows removing existing NewLineConsistencyCheck overlays + if (LoadedFileContent != null) + LoadedFileContent(this, EventArgs.Empty); NewLineConsistencyCheck.StartConsistencyCheck(this); } + public event EventHandler LoadedFileContent; + public void Save(Stream stream) { // don't use TextEditor.Save here because that would touch the Modified flag, diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs index 98f7b9de67..1d553b4b95 100755 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs @@ -141,6 +141,8 @@ namespace ICSharpCode.AvalonEdit.AddIn CodeSnippet snippet = SnippetManager.Instance.FindSnippet(Path.GetExtension(editor.Adapter.FileName), word); if (snippet != null) { + snippet.TrackUsage("CustomTabCommand"); + editor.Adapter.Document.Remove(wordStart, editor.CaretOffset - wordStart); snippet.CreateAvalonEditSnippet(editor.Adapter).Insert(editor.TextArea); return; diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/NewLineConsistencyCheck.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/NewLineConsistencyCheck.cs index ec6aec8ad1..e0a26fbd5a 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/NewLineConsistencyCheck.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/NewLineConsistencyCheck.cs @@ -115,13 +115,25 @@ namespace ICSharpCode.AvalonEdit.AddIn }; editor.Children.Add(groupBox); - cancelButton.Click += delegate { + var featureUse = AnalyticsMonitorService.TrackFeature(typeof(NewLineConsistencyCheck)); + + EventHandler removeWarning = null; + removeWarning = delegate { editor.Children.Remove(groupBox); editor.PrimaryTextEditor.TextArea.Focus(); + editor.LoadedFileContent -= removeWarning; + + featureUse.EndTracking(); + }; + + editor.LoadedFileContent += removeWarning; + cancelButton.Click += delegate { + AnalyticsMonitorService.TrackFeature(typeof(NewLineConsistencyCheck), "cancelButton"); + removeWarning(null, null); }; normalizeButton.Click += delegate { - editor.Children.Remove(groupBox); - editor.PrimaryTextEditor.TextArea.Focus(); + AnalyticsMonitorService.TrackFeature(typeof(NewLineConsistencyCheck), "normalizeButton"); + removeWarning(null, null); TextDocument document = editor.Document; string newNewLine = (unix.IsChecked == true) ? "\n" : "\r\n"; diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/QuickClassBrowser.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/QuickClassBrowser.cs index 08b58465c9..6b60affc4e 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/QuickClassBrowser.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/QuickClassBrowser.cs @@ -9,7 +9,7 @@ using System; using System.Collections.Generic; using System.Windows.Controls; using System.Windows.Media; - +using ICSharpCode.Core; using ICSharpCode.NRefactory; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; @@ -242,6 +242,7 @@ namespace ICSharpCode.AvalonEdit.AddIn } memberItems.Sort(); if (jumpOnSelectionChange) { + AnalyticsMonitorService.TrackFeature(GetType(), "JumpToClass"); JumpTo(item, selectedClass.Region); } } @@ -260,6 +261,7 @@ namespace ICSharpCode.AvalonEdit.AddIn if (item != null) { IMember member = item.Entity as IMember; if (member != null && jumpOnSelectionChange) { + AnalyticsMonitorService.TrackFeature(GetType(), "JumpToMember"); JumpTo(item, member.Region); } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/CodeSnippet.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/CodeSnippet.cs index 9a2ba18cc9..9161dd99c4 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/CodeSnippet.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/CodeSnippet.cs @@ -240,5 +240,13 @@ namespace ICSharpCode.AvalonEdit.AddIn.Snippets return function(input); } } + + /// + /// Reports the snippet usage to UDC + /// + internal void TrackUsage(string activationMethod) + { + Core.AnalyticsMonitorService.TrackFeature(typeof(CodeSnippet), IsUserModified ? "usersnippet" : Name, activationMethod); + } } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs index 31c14e6d77..460a4a6ccc 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs @@ -74,6 +74,8 @@ namespace ICSharpCode.AvalonEdit.AddIn.Snippets using (context.Editor.Document.OpenUndoGroup()) { if (context.CompletionChar == '\t' || AlwaysInsertSnippet) { + codeSnippet.TrackUsage("SnippetCompletionItem"); + context.Editor.Document.Remove(context.StartOffset, context.Length); CreateSnippet().Insert(textArea); } else { diff --git a/src/Main/Base/Project/Src/Bookmarks/ClassMemberBookmark.cs b/src/Main/Base/Project/Src/Bookmarks/ClassMemberBookmark.cs index cdd871262d..3e79a8c1b4 100644 --- a/src/Main/Base/Project/Src/Bookmarks/ClassMemberBookmark.cs +++ b/src/Main/Base/Project/Src/Bookmarks/ClassMemberBookmark.cs @@ -8,7 +8,7 @@ using System; using System.Windows; using System.Windows.Input; - +using ICSharpCode.Core; using ICSharpCode.Core.Presentation; using ICSharpCode.SharpDevelop.Dom; @@ -36,7 +36,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks public const string ContextMenuPath = "/SharpDevelop/ViewContent/DefaultTextEditor/ClassMemberContextMenu"; - public virtual IImage Image { + public virtual IImage Image { get { return ClassBrowserIconService.GetIcon(member); } } @@ -47,7 +47,9 @@ namespace ICSharpCode.SharpDevelop.Bookmarks public virtual void MouseDown(MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) { - MenuService.ShowContextMenu(e.Source as UIElement, this, ContextMenuPath); + var f = AnalyticsMonitorService.TrackFeature("ICSharpCode.SharpDevelop.Bookmarks.ClassMemberBookmark.ShowContextMenu"); + var ctx = MenuService.ShowContextMenu(e.Source as UIElement, this, ContextMenuPath); + ctx.Closed += delegate { f.EndTracking(); }; e.Handled = true; } } @@ -73,7 +75,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks public const string ContextMenuPath = "/SharpDevelop/ViewContent/DefaultTextEditor/ClassBookmarkContextMenu"; - public virtual IImage Image { + public virtual IImage Image { get { return ClassBrowserIconService.GetIcon(@class); } @@ -86,7 +88,9 @@ namespace ICSharpCode.SharpDevelop.Bookmarks public virtual void MouseDown(MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) { - MenuService.ShowContextMenu(e.Source as UIElement, this, ContextMenuPath); + var f = AnalyticsMonitorService.TrackFeature("ICSharpCode.SharpDevelop.Bookmarks.ClassBookmark.ShowContextMenu"); + var ctx = MenuService.ShowContextMenu(e.Source as UIElement, this, ContextMenuPath); + ctx.Closed += delegate { f.EndTracking(); }; e.Handled = true; } } diff --git a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs index 33b07d9323..321bb94d1f 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs @@ -95,7 +95,7 @@ namespace ICSharpCode.SharpDevelop.Gui } } - mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath); + mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath, "MainMenu"); toolBars = ToolBarService.CreateToolBars(this, "/SharpDevelop/Workbench/ToolBar"); foreach (ToolBar tb in toolBars) { diff --git a/src/Main/Base/Project/Src/Project/BuildEngine.cs b/src/Main/Base/Project/Src/Project/BuildEngine.cs index 289c88e257..bba1cf57b1 100644 --- a/src/Main/Base/Project/Src/Project/BuildEngine.cs +++ b/src/Main/Base/Project/Src/Project/BuildEngine.cs @@ -55,7 +55,7 @@ namespace ICSharpCode.SharpDevelop.Project } else { guiBuildCancellation = new CancellationTokenSource(); IProgressMonitor progressMonitor = WorkbenchSingleton.StatusBar.CreateProgressMonitor(guiBuildCancellation.Token); - guiBuildTrackedFeature = AnalyticsMonitorService.TrackFeature("Build"); + guiBuildTrackedFeature = AnalyticsMonitorService.TrackFeature("ICSharpCode.SharpDevelop.Project.BuildEngine.Build"); WorkbenchSingleton.StatusBar.SetMessage(StringParser.Parse("${res:MainWindow.CompilerMessages.BuildVerb}...")); ProjectService.RaiseEventBuildStarted(new BuildEventArgs(project, options)); StartBuild(project, options, diff --git a/src/Main/Base/Project/Src/Project/Converter/UpgradeView.xaml.cs b/src/Main/Base/Project/Src/Project/Converter/UpgradeView.xaml.cs index 1be908abce..2892e0c48e 100644 --- a/src/Main/Base/Project/Src/Project/Converter/UpgradeView.xaml.cs +++ b/src/Main/Base/Project/Src/Project/Converter/UpgradeView.xaml.cs @@ -209,7 +209,7 @@ namespace ICSharpCode.SharpDevelop.Project.Converter void convertButton_Click(object sender, RoutedEventArgs e) { - Core.AnalyticsMonitorService.TrackFeature("UpgradeView.convertButton_Click"); + Core.AnalyticsMonitorService.TrackFeature(GetType(), "convertButton_Click"); CompilerVersion selectedCompiler = newVersionComboBox.SelectedValue as CompilerVersion; TargetFramework selectedFramework = newFrameworkComboBox.SelectedValue as TargetFramework; diff --git a/src/Main/Base/Project/Src/Project/Converter/UpgradeViewContent.cs b/src/Main/Base/Project/Src/Project/Converter/UpgradeViewContent.cs index 030bcb3970..09606673cd 100644 --- a/src/Main/Base/Project/Src/Project/Converter/UpgradeViewContent.cs +++ b/src/Main/Base/Project/Src/Project/Converter/UpgradeViewContent.cs @@ -21,7 +21,7 @@ namespace ICSharpCode.SharpDevelop.Project.Converter { var projects = solution.Projects.OfType().ToList(); if (projects.Count > 0 && projects.All(u => u.UpgradeDesired)) { - Core.AnalyticsMonitorService.TrackFeature("UpgradeView opened automatically"); + Core.AnalyticsMonitorService.TrackFeature(typeof(UpgradeView), "opened automatically"); WorkbenchSingleton.Workbench.ShowView(new UpgradeViewContent(solution)); } } diff --git a/src/Main/Core/Project/Src/Services/AnalyticsMonitor/AnalyticsMonitorService.cs b/src/Main/Core/Project/Src/Services/AnalyticsMonitor/AnalyticsMonitorService.cs index 7a893c355f..499c7f42af 100644 --- a/src/Main/Core/Project/Src/Services/AnalyticsMonitor/AnalyticsMonitorService.cs +++ b/src/Main/Core/Project/Src/Services/AnalyticsMonitor/AnalyticsMonitorService.cs @@ -80,5 +80,23 @@ namespace ICSharpCode.Core { } } + + + /// + /// Tracks a feature use. + /// + /// Class containing the feature + /// Name of the feature + /// Method used to 'activate' the feature (e.g. Menu, Toolbar, Shortcut, etc.) + /// Object that can be used to 'end' the feature use, if measuring time spans is desired. + public static IAnalyticsMonitorTrackedFeature TrackFeature(Type featureClass, string featureName = null, string activationMethod = null) + { + if (featureClass == null) + throw new ArgumentNullException("featureClass"); + if (featureName != null) + return TrackFeature(featureClass.FullName + "/" + featureName, activationMethod); + else + return TrackFeature(featureClass.FullName, activationMethod); + } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs index 24234be91c..2d997573e8 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs @@ -123,8 +123,11 @@ namespace ICSharpCode.Core.Presentation class MenuCommand : CoreMenuItem { - public MenuCommand(UIElement inputBindingOwner, Codon codon, object caller, bool createCommand) : base(codon, caller) + readonly string ActivationMethod; + + public MenuCommand(UIElement inputBindingOwner, Codon codon, object caller, bool createCommand, string activationMethod) : base(codon, caller) { + this.ActivationMethod = activationMethod; this.Command = CommandWrapper.GetCommand(codon, caller, createCommand); if (!string.IsNullOrEmpty(codon.Properties["shortcut"])) { KeyGesture kg = MenuService.ParseShortcut(codon.Properties["shortcut"]); @@ -154,7 +157,7 @@ namespace ICSharpCode.Core.Presentation base.OnClick(); string feature = GetFeatureName(); if (!string.IsNullOrEmpty(feature)) { - AnalyticsMonitorService.TrackFeature(feature, "Menu"); + AnalyticsMonitorService.TrackFeature(feature, ActivationMethod); } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs index 211fd14d5e..201745ed0f 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs @@ -106,14 +106,14 @@ namespace ICSharpCode.Core.Presentation public static ContextMenu CreateContextMenu(object owner, string addInTreePath) { - IList items = CreateUnexpandedMenuItems(null, AddInTree.BuildItems(addInTreePath, owner, false)); + IList items = CreateUnexpandedMenuItems(null, AddInTree.BuildItems(addInTreePath, owner, false), "ContextMenu"); return CreateContextMenu(items); } public static ContextMenu ShowContextMenu(UIElement parent, object owner, string addInTreePath) { ContextMenu menu = new ContextMenu(); - menu.ItemsSource = CreateMenuItems(menu, owner, addInTreePath); + menu.ItemsSource = CreateMenuItems(menu, owner, addInTreePath, "ContextMenu"); menu.PlacementTarget = parent; menu.IsOpen = true; return menu; @@ -131,9 +131,9 @@ namespace ICSharpCode.Core.Presentation return contextMenu; } - public static IList CreateMenuItems(UIElement inputBindingOwner, object owner, string addInTreePath) + public static IList CreateMenuItems(UIElement inputBindingOwner, object owner, string addInTreePath, string activationMethod = null) { - IList items = CreateUnexpandedMenuItems(inputBindingOwner, AddInTree.BuildItems(addInTreePath, owner, false)); + IList items = CreateUnexpandedMenuItems(inputBindingOwner, AddInTree.BuildItems(addInTreePath, owner, false), activationMethod); return ExpandMenuBuilders(items, false); } @@ -156,12 +156,12 @@ namespace ICSharpCode.Core.Presentation } } - internal static IList CreateUnexpandedMenuItems(UIElement inputBindingOwner, IEnumerable descriptors) + internal static IList CreateUnexpandedMenuItems(UIElement inputBindingOwner, IEnumerable descriptors, string activationMethod) { ArrayList result = new ArrayList(); if (descriptors != null) { foreach (MenuItemDescriptor descriptor in descriptors) { - result.Add(CreateMenuItemFromDescriptor(inputBindingOwner, descriptor)); + result.Add(CreateMenuItemFromDescriptor(inputBindingOwner, descriptor, activationMethod)); } } return result; @@ -191,7 +191,7 @@ namespace ICSharpCode.Core.Presentation return result; } - static object CreateMenuItemFromDescriptor(UIElement inputBindingOwner, MenuItemDescriptor descriptor) + static object CreateMenuItemFromDescriptor(UIElement inputBindingOwner, MenuItemDescriptor descriptor, string activationMethod) { Codon codon = descriptor.Codon; string type = codon.Properties.Contains("type") ? codon.Properties["type"] : "Command"; @@ -205,13 +205,13 @@ namespace ICSharpCode.Core.Presentation //return new MenuCheckBox(codon, descriptor.Caller); case "Item": case "Command": - return new MenuCommand(inputBindingOwner, codon, descriptor.Caller, createCommand); + return new MenuCommand(inputBindingOwner, codon, descriptor.Caller, createCommand, activationMethod); case "Menu": var item = new CoreMenuItem(codon, descriptor.Caller) { ItemsSource = new object[1], SetEnabled = true }; - var subItems = CreateUnexpandedMenuItems(inputBindingOwner, descriptor.SubItems); + var subItems = CreateUnexpandedMenuItems(inputBindingOwner, descriptor.SubItems, activationMethod); item.SubmenuOpened += (sender, args) => { item.ItemsSource = ExpandMenuBuilders(subItems, true); args.Handled = true; diff --git a/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarService.cs b/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarService.cs index 3e3f949c34..a63ee22ea8 100644 --- a/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarService.cs +++ b/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarService.cs @@ -72,9 +72,9 @@ namespace ICSharpCode.Core.Presentation return "Label"; //return new ToolBarLabel(codon, caller); case "DropDownButton": - return new ToolBarDropDownButton(codon, caller, MenuService.CreateUnexpandedMenuItems(null, descriptor.SubItems)); + return new ToolBarDropDownButton(codon, caller, MenuService.CreateUnexpandedMenuItems(null, descriptor.SubItems, "ToolbarDropDownMenu")); case "SplitButton": - return new ToolBarSplitButton(codon, caller, MenuService.CreateUnexpandedMenuItems(null, descriptor.SubItems)); + return new ToolBarSplitButton(codon, caller, MenuService.CreateUnexpandedMenuItems(null, descriptor.SubItems, "ToolbarDropDownMenu")); case "Builder": return codon.AddIn.CreateObject(codon.Properties["class"]); default: