diff --git a/RetailCoder.VBE/API/ParserState.cs b/RetailCoder.VBE/API/ParserState.cs index 9fe6baaf40..a21643abc3 100644 --- a/RetailCoder.VBE/API/ParserState.cs +++ b/RetailCoder.VBE/API/ParserState.cs @@ -68,7 +68,7 @@ public void Initialize(VBE vbe) Func preprocessorFactory = () => new VBAPreprocessor(double.Parse(vbe.Version, CultureInfo.InvariantCulture)); _attributeParser = new AttributeParser(new ModuleExporter(), preprocessorFactory); - _parser = new RubberduckParser(vbe, _state, _attributeParser, preprocessorFactory, + _parser = new RubberduckParser(_state, _attributeParser, preprocessorFactory, new List { new DebugDeclarations(_state), new FormEventDeclarations(_state) }); } diff --git a/RetailCoder.VBE/Common/RubberduckHooks.cs b/RetailCoder.VBE/Common/RubberduckHooks.cs index e6d6a21241..c0a0c5d5d3 100644 --- a/RetailCoder.VBE/Common/RubberduckHooks.cs +++ b/RetailCoder.VBE/Common/RubberduckHooks.cs @@ -173,12 +173,6 @@ public void Detach() private void hook_MessageReceived(object sender, HookEventArgs e) { - var active = User32.GetForegroundWindow(); - if (active != _mainWindowHandle) - { - return; - } - var hotkey = sender as IHotkey; if (hotkey != null) { @@ -207,6 +201,16 @@ private IntPtr WindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam) case WM.SETFOCUS: Attach(); break; + case WM.RUBBERDUCK_CHILD_FOCUS: + if (lParam == IntPtr.Zero) + { + Detach(); + } + else + { + Attach(); + } + return IntPtr.Zero; case WM.NCACTIVATE: if (wParam == IntPtr.Zero) { @@ -235,14 +239,11 @@ private bool HandleHotkeyMessage(IntPtr wParam) var processed = false; try { - if (User32.IsVbeWindowActive(_mainWindowHandle)) + var hook = Hooks.OfType().SingleOrDefault(k => k.HotkeyInfo.HookId == wParam); + if (hook != null) { - var hook = Hooks.OfType().SingleOrDefault(k => k.HotkeyInfo.HookId == wParam); - if (hook != null) - { - hook.OnMessageReceived(); - processed = true; - } + hook.OnMessageReceived(); + processed = true; } } catch (Exception exception) diff --git a/RetailCoder.VBE/Common/WinAPI/User32.cs b/RetailCoder.VBE/Common/WinAPI/User32.cs index 674fbe2143..dc0ea56c9a 100644 --- a/RetailCoder.VBE/Common/WinAPI/User32.cs +++ b/RetailCoder.VBE/Common/WinAPI/User32.cs @@ -180,6 +180,9 @@ public static class User32 [DllImport("user32.dll", SetLastError = true)] internal static extern bool UnregisterDeviceNotification(IntPtr handle); + [DllImport("user32.dll", CharSet = CharSet.Auto)] + internal static extern IntPtr SendMessage(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam); + /// /// A helper function that returns true when the specified handle is that of the foreground window. /// diff --git a/RetailCoder.VBE/Common/WinAPI/WM.cs b/RetailCoder.VBE/Common/WinAPI/WM.cs index 5cfba2be9c..cf3fdbd184 100644 --- a/RetailCoder.VBE/Common/WinAPI/WM.cs +++ b/RetailCoder.VBE/Common/WinAPI/WM.cs @@ -922,6 +922,11 @@ public enum WM : uint /// SYSTIMER = 0x118, + /// + /// Private message to signal focus set/lost for a DockableWindowHost. Set wParam to the DockableWindowHost hWnd, lParam to zero for lost focus, non-zero for gained focus. + /// + RUBBERDUCK_CHILD_FOCUS = USER + 0x0F00, + /// /// The accessibility state has changed. /// diff --git a/RetailCoder.VBE/Inspections/InspectionResultBase.cs b/RetailCoder.VBE/Inspections/InspectionResultBase.cs index 9b010795f4..e3adfd60e2 100644 --- a/RetailCoder.VBE/Inspections/InspectionResultBase.cs +++ b/RetailCoder.VBE/Inspections/InspectionResultBase.cs @@ -121,7 +121,7 @@ public int CompareTo(object obj) public object[] ToArray() { var module = QualifiedSelection.QualifiedName; - return new object[] { Inspection.Severity.ToString(), module.ProjectTitle, module.ComponentName, Description, QualifiedSelection.Selection.StartLine, QualifiedSelection.Selection.StartColumn }; + return new object[] { Inspection.Severity.ToString(), module.ProjectName, module.ComponentName, Description, QualifiedSelection.Selection.StartLine, QualifiedSelection.Selection.StartColumn }; } public string ToCsvString() diff --git a/RetailCoder.VBE/Navigation/CodeExplorer/CodeExplorerViewModel.cs b/RetailCoder.VBE/Navigation/CodeExplorer/CodeExplorerViewModel.cs index 660d0257fc..dbeaa9bf96 100644 --- a/RetailCoder.VBE/Navigation/CodeExplorer/CodeExplorerViewModel.cs +++ b/RetailCoder.VBE/Navigation/CodeExplorer/CodeExplorerViewModel.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Windows.Input; using Microsoft.Vbe.Interop; using NLog; using Rubberduck.Navigation.Folders; @@ -87,17 +86,6 @@ public CodeExplorerItemViewModel SelectedItem _selectedItem = value; OnPropertyChanged(); - if (_selectedItem is CodeExplorerProjectViewModel) - { - var vbe = _selectedItem.GetSelectedDeclaration().Project.VBE; - var project = vbe.VBProjects.Cast().FirstOrDefault(f => f.HelpFile == _selectedItem.GetSelectedDeclaration().Project.HelpFile); - - if (project != null) - { - vbe.ActiveVBProject = project; - } - } - // ReSharper disable ExplicitCallerInfoArgument OnPropertyChanged("CanExecuteIndenterCommand"); OnPropertyChanged("CanExecuteRenameCommand"); @@ -189,25 +177,27 @@ public string PanelTitle return string.Empty; } - if (SelectedItem is CodeExplorerProjectViewModel) + if (!(SelectedItem is ICodeExplorerDeclarationViewModel)) { - var node = (CodeExplorerProjectViewModel)SelectedItem; - return node.Declaration.IdentifierName + string.Format(" - ({0})", node.Declaration.DeclarationType); + return SelectedItem.Name; } - if (SelectedItem is CodeExplorerComponentViewModel) - { - var node = (CodeExplorerComponentViewModel)SelectedItem; - return node.Declaration.IdentifierName + string.Format(" - ({0})", node.Declaration.DeclarationType); - } + var declaration = SelectedItem.GetSelectedDeclaration(); + + var nameWithDeclarationType = declaration.IdentifierName + + string.Format(" - ({0})", RubberduckUI.ResourceManager.GetString( + "DeclarationType_" + declaration.DeclarationType, UI.Settings.Settings.Culture)); - if (SelectedItem is CodeExplorerMemberViewModel) + if (string.IsNullOrEmpty(declaration.AsTypeName)) { - var node = (CodeExplorerMemberViewModel)SelectedItem; - return node.Declaration.IdentifierName + string.Format(" - ({0})", node.Declaration.DeclarationType); + return nameWithDeclarationType; } - return SelectedItem.Name; + var typeName = declaration.HasTypeHint + ? Declaration.TypeHintToTypeName[declaration.TypeHint] + : declaration.AsTypeName; + + return nameWithDeclarationType + ": " + typeName; } } diff --git a/RetailCoder.VBE/UI/CodeExplorer/CodeExplorerControl.xaml b/RetailCoder.VBE/UI/CodeExplorer/CodeExplorerControl.xaml index 259ddfbe52..05606efb88 100644 --- a/RetailCoder.VBE/UI/CodeExplorer/CodeExplorerControl.xaml +++ b/RetailCoder.VBE/UI/CodeExplorer/CodeExplorerControl.xaml @@ -374,7 +374,8 @@ CommandParameter="{Binding SelectedItem}" /> + Command="{Binding OpenProjectPropertiesCommand}" + CommandParameter="{Binding SelectedItem}" /> - - + + @@ -776,7 +777,7 @@ CommandParameter="{Binding SelectedItem}" Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=CodeExplorer_FindAllReferencesText}" /> - + diff --git a/RetailCoder.VBE/UI/CodeExplorer/Commands/CodeExplorer_OpenProjectPropertiesCommand.cs b/RetailCoder.VBE/UI/CodeExplorer/Commands/CodeExplorer_OpenProjectPropertiesCommand.cs index 3525a4abdb..835cfccedb 100644 --- a/RetailCoder.VBE/UI/CodeExplorer/Commands/CodeExplorer_OpenProjectPropertiesCommand.cs +++ b/RetailCoder.VBE/UI/CodeExplorer/Commands/CodeExplorer_OpenProjectPropertiesCommand.cs @@ -1,5 +1,7 @@ +using System.Runtime.InteropServices; using Microsoft.Vbe.Interop; using NLog; +using Rubberduck.Navigation.CodeExplorer; using Rubberduck.UI.Command; namespace Rubberduck.UI.CodeExplorer.Commands @@ -13,10 +15,36 @@ public CodeExplorer_OpenProjectPropertiesCommand(VBE vbe) : base(LogManager.GetC _vbe = vbe; } + protected override bool CanExecuteImpl(object parameter) + { + return parameter != null || _vbe.VBProjects.Count == 1; + } + protected override void ExecuteImpl(object parameter) { const int openProjectPropertiesId = 2578; + if (_vbe.VBProjects.Count == 1) + { + _vbe.CommandBars.FindControl(Id: openProjectPropertiesId).Execute(); + return; + } + + var node = parameter as CodeExplorerItemViewModel; + while (!(node is ICodeExplorerDeclarationViewModel)) + { + node = node.Parent; // the project node is an ICodeExplorerDeclarationViewModel--no worries here + } + + try + { + _vbe.ActiveVBProject = node.GetSelectedDeclaration().Project; + } + catch (COMException) + { + return; // the project was probably removed from the VBE, but not from the CE + } + _vbe.CommandBars.FindControl(Id: openProjectPropertiesId).Execute(); } } diff --git a/RetailCoder.VBE/UI/Command/AddTestMethodCommand.cs b/RetailCoder.VBE/UI/Command/AddTestMethodCommand.cs index a835f7a7fe..8652e14ada 100644 --- a/RetailCoder.VBE/UI/Command/AddTestMethodCommand.cs +++ b/RetailCoder.VBE/UI/Command/AddTestMethodCommand.cs @@ -34,8 +34,17 @@ protected override bool CanExecuteImpl(object parameter) d.DeclarationType == DeclarationType.ProceduralModule && d.Annotations.Any(a => a.AnnotationType == AnnotationType.TestModule)); - // the code modules consistently match correctly, but the components don't - return testModules.Any(a => a.QualifiedName.QualifiedModuleName.Component.CodeModule == _vbe.SelectedVBComponent.CodeModule); + try + { + // the code modules consistently match correctly, but the components don't + return testModules.Any(a => + a.QualifiedName.QualifiedModuleName.Component.CodeModule == + _vbe.SelectedVBComponent.CodeModule); + } + catch (COMException) + { + return false; + } } protected override void ExecuteImpl(object parameter) diff --git a/RetailCoder.VBE/UI/Command/AddTestMethodExpectedErrorCommand.cs b/RetailCoder.VBE/UI/Command/AddTestMethodExpectedErrorCommand.cs index 2c38b618c5..605df28a2a 100644 --- a/RetailCoder.VBE/UI/Command/AddTestMethodExpectedErrorCommand.cs +++ b/RetailCoder.VBE/UI/Command/AddTestMethodExpectedErrorCommand.cs @@ -34,8 +34,17 @@ protected override bool CanExecuteImpl(object parameter) d.DeclarationType == DeclarationType.ProceduralModule && d.Annotations.Any(a => a.AnnotationType == AnnotationType.TestModule)); - // the code modules consistently match correctly, but the components don't - return testModules.Any(a => a.QualifiedName.QualifiedModuleName.Component.CodeModule == _vbe.SelectedVBComponent.CodeModule); + try + { + // the code modules consistently match correctly, but the components don't + return testModules.Any(a => + a.QualifiedName.QualifiedModuleName.Component.CodeModule == + _vbe.SelectedVBComponent.CodeModule); + } + catch (COMException) + { + return false; + } } protected override void ExecuteImpl(object parameter) diff --git a/RetailCoder.VBE/UI/DockableToolwindowPresenter.cs b/RetailCoder.VBE/UI/DockableToolwindowPresenter.cs index 9cfb34bc42..3bcd94013c 100644 --- a/RetailCoder.VBE/UI/DockableToolwindowPresenter.cs +++ b/RetailCoder.VBE/UI/DockableToolwindowPresenter.cs @@ -62,7 +62,7 @@ private Window CreateToolWindow(IDockableUserControl control) toolWindow.Visible = false; //hide it again - userControlHost.AddUserControl(control as UserControl); + userControlHost.AddUserControl(control as UserControl, new IntPtr(_vbe.MainWindow.HWnd)); return toolWindow; } diff --git a/RetailCoder.VBE/UI/DockableWindowHost.cs b/RetailCoder.VBE/UI/DockableWindowHost.cs index d552b0f30e..b505bafce3 100644 --- a/RetailCoder.VBE/UI/DockableWindowHost.cs +++ b/RetailCoder.VBE/UI/DockableWindowHost.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; +using Rubberduck.Common.WinAPI; using Rubberduck.VBEditor; namespace Rubberduck.UI @@ -40,10 +41,10 @@ private struct Rect private IntPtr _parentHandle; private SubClassingWindow _subClassingWindow; - internal void AddUserControl(UserControl control) + internal void AddUserControl(UserControl control, IntPtr vbeHwnd) { _parentHandle = GetParent(Handle); - _subClassingWindow = new SubClassingWindow(_parentHandle); + _subClassingWindow = new SubClassingWindow(_parentHandle, vbeHwnd); _subClassingWindow.CallBackEvent += OnCallBackEvent; if (control != null) @@ -116,27 +117,35 @@ public class SubClassingWindow : NativeWindow public event SubClassingWindowEventHandler CallBackEvent; public delegate void SubClassingWindowEventHandler(object sender, SubClassingWindowEventArgs e); + private readonly IntPtr _vbeHwnd; + private void OnCallBackEvent(SubClassingWindowEventArgs e) { Debug.Assert(CallBackEvent != null, "CallBackEvent != null"); CallBackEvent(this, e); } - public SubClassingWindow(IntPtr handle) + public SubClassingWindow(IntPtr handle, IntPtr vbeHwnd) { + _vbeHwnd = vbeHwnd; AssignHandle(handle); } protected override void WndProc(ref Message msg) { - const int wmSize = 0x5; - - if (msg.Msg == wmSize) + switch ((uint)msg.Msg) { - var args = new SubClassingWindowEventArgs(msg); - OnCallBackEvent(args); + case (uint)WM.SIZE: + var args = new SubClassingWindowEventArgs(msg); + OnCallBackEvent(args); + break; + case (uint)WM.SETFOCUS: + User32.SendMessage(_vbeHwnd, WM.RUBBERDUCK_CHILD_FOCUS, Handle, Handle); + break; + case (uint)WM.KILLFOCUS: + User32.SendMessage(_vbeHwnd, WM.RUBBERDUCK_CHILD_FOCUS, Handle, IntPtr.Zero); + break; } - base.WndProc(ref msg); } diff --git a/RetailCoder.VBE/UnitTesting/TestMethod.cs b/RetailCoder.VBE/UnitTesting/TestMethod.cs index 22802ecc78..7f9dac5d66 100644 --- a/RetailCoder.VBE/UnitTesting/TestMethod.cs +++ b/RetailCoder.VBE/UnitTesting/TestMethod.cs @@ -109,7 +109,7 @@ public NavigateCodeEventArgs GetNavigationArgs() public object[] ToArray() { - return new object[] { Declaration.QualifiedName.QualifiedModuleName.ProjectTitle, Declaration.QualifiedName.QualifiedModuleName.ComponentName, Declaration.IdentifierName, + return new object[] { Declaration.QualifiedName.QualifiedModuleName.ProjectName, Declaration.QualifiedName.QualifiedModuleName.ComponentName, Declaration.IdentifierName, _result.Outcome.ToString(), _result.Output, _result.StartTime.ToString(CultureInfo.InvariantCulture), _result.EndTime.ToString(CultureInfo.InvariantCulture), _result.Duration }; } diff --git a/Rubberduck.Parsing/VBA/RubberduckParser.cs b/Rubberduck.Parsing/VBA/RubberduckParser.cs index d3d74ffbb4..eb8f8fc805 100644 --- a/Rubberduck.Parsing/VBA/RubberduckParser.cs +++ b/Rubberduck.Parsing/VBA/RubberduckParser.cs @@ -10,7 +10,6 @@ using Rubberduck.VBEditor; using Rubberduck.Parsing.Preprocessing; using System.Diagnostics; -using Rubberduck.VBEditor.Extensions; using System.IO; using NLog; // ReSharper disable LoopCanBeConvertedToQuery @@ -26,8 +25,7 @@ public class RubberduckParser : IRubberduckParser private readonly IDictionary, Attributes>> _componentAttributes = new Dictionary, Attributes>>(); - - private readonly VBE _vbe; + private readonly RubberduckParserState _state; private readonly IAttributeParser _attributeParser; private readonly Func _preprocessorFactory; @@ -35,13 +33,11 @@ private readonly IDictionary preprocessorFactory, IEnumerable customDeclarationLoaders) { - _vbe = vbe; _state = state; _attributeParser = attributeParser; _preprocessorFactory = preprocessorFactory; @@ -106,13 +102,7 @@ private void ReparseRequested(object sender, ParseRequestEventArgs e) /// public void Parse(CancellationTokenSource token) { - if (State.Projects.Count == 0) - { - foreach (var project in _vbe.VBProjects.UnprotectedProjects()) - { - State.AddProject(project.HelpFile); - } - } + State.RefreshProjects(); var components = new List(); foreach (var project in State.Projects) @@ -188,13 +178,7 @@ public void Parse(CancellationTokenSource token) /// private void ParseAll(CancellationTokenSource token) { - if (State.Projects.Count == 0) - { - foreach (var project in _vbe.VBProjects.UnprotectedProjects()) - { - State.AddProject(project.HelpFile); - } - } + State.RefreshProjects(); var components = new List(); foreach (var project in State.Projects) @@ -232,7 +216,6 @@ private void ParseAll(CancellationTokenSource token) } var toParse = new List(); - foreach (var component in components) { if (State.IsNewOrModified(component)) @@ -310,6 +293,13 @@ private void ParseAll(CancellationTokenSource token) Task.WaitAll(parseTasks); + if (token.IsCancellationRequested) + { + return; + } + + Debug.Assert(State.ParseTrees.Count == components.Count); + if (State.Status < ParserState.Error) { State.SetStatusAndFireStateChanged(ParserState.ResolvedDeclarations); diff --git a/Rubberduck.Parsing/VBA/RubberduckParserState.cs b/Rubberduck.Parsing/VBA/RubberduckParserState.cs index c170278bb6..af6c3137cb 100644 --- a/Rubberduck.Parsing/VBA/RubberduckParserState.cs +++ b/Rubberduck.Parsing/VBA/RubberduckParserState.cs @@ -96,7 +96,7 @@ private void Sinks_ProjectAdded(object sender, IProjectEventArgs e) Logger.Debug("Project '{0}' was added.", e.ProjectId); - AddProject(e.ProjectId); // note side-effect: assigns ProjectId/HelpFile + RefreshProjects(); // note side-effect: assigns ProjectId/HelpFile OnParseRequested(sender); } @@ -122,7 +122,7 @@ private void Sinks_ProjectRenamed(object sender, IProjectRenamedEventArgs e) Logger.Debug("Project {0} was renamed.", e.ProjectId); RemoveProject(e.ProjectId); - AddProject(e.ProjectId); + RefreshProjects(); OnParseRequested(sender); } @@ -189,7 +189,7 @@ private void Sinks_ComponentRenamed(object sender, IComponentRenamedEventArgs e) RemoveProject(e.ProjectId); Logger.Debug("Project '{0}' was removed.", e.ComponentName); - AddProject(e.ProjectId); + RefreshProjects(); } else { @@ -209,49 +209,23 @@ public void OnStatusMessageUpdate(string message) } } - public void AddProject(string projectId) + /// + /// Refreshes our list of cached projects. + /// Be sure to reparse after calling this in case there + /// were projects with duplicate ID's to clear the old + /// declarations referencing the project by the old ID. + /// + public void RefreshProjects() { - var projects = new List(); - foreach (VBProject p in _vbe.VBProjects) + _projects.Clear(); + foreach (VBProject project in _vbe.VBProjects) { - if (p.HelpFile != null && _projects.Keys.Contains(p.HelpFile)) + if (string.IsNullOrEmpty(project.HelpFile) || _projects.Keys.Contains(project.HelpFile)) { - continue; + project.AssignProjectId(); } - projects.Add(p); - } - - if (projects.Count == 0) - { - Logger.Debug("Project was not found and will not be added to parser state."); - return; - } - - foreach (var project in projects) - { - if (project.Protection == vbext_ProjectProtection.vbext_pp_locked) - { - // adding protected project to parser state is asking for COMExceptions.. - Logger.Debug("Project is protected and will not be added to parser state."); - return; - } - - if (string.IsNullOrEmpty(project.HelpFile)) - { - // assigns the help file and returns the value to reduce COM calls - projectId = project.AssignProjectId(); - } - - if (!_projects.ContainsKey(projectId)) - { - _projects.Add(projectId, project); - } - - foreach (VBComponent component in project.VBComponents) - { - _moduleStates.TryAdd(new QualifiedModuleName(component), new ModuleState(ParserState.Pending)); - } + _projects.Add(project.HelpFile, project); } } @@ -723,70 +697,18 @@ public void ClearBuiltInReferences() { continue; } - - var hasReference = false; + foreach (var reference in declaration.References) - { - hasReference = true; - break; - } - - if (hasReference) { declaration.ClearReferences(); + break; } } } public bool ClearStateCache(VBComponent component, bool notifyStateChanged = false) { - if (component == null) { return false; } - - var match = new QualifiedModuleName(component); - - var keys = new List { match }; - foreach (var key in _moduleStates.Keys) - { - if (key.Equals(match) && !keys.Contains(key)) - { - keys.Add(key); - } - } - - var success = RemoveKeysFromCollections(keys); - - var projectId = component.Collection.Parent.HelpFile; - var sameProjectDeclarations = new List>(); - foreach (var item in _moduleStates) - { - if (item.Key.ProjectId == projectId) - { - sameProjectDeclarations.Add(new KeyValuePair(item.Key, item.Value)); - } - } - - var projectCount = 0; - foreach (var item in sameProjectDeclarations) - { - if (item.Value.Declarations == null) { continue; } - - foreach (var declaration in item.Value.Declarations) - { - if (declaration.Key.DeclarationType == DeclarationType.Project) - { - projectCount++; - break; - } - } - } - - if (notifyStateChanged) - { - OnStateChanged(ParserState.ResolvedDeclarations); // trigger test explorer and code explorer updates - OnStateChanged(ParserState.Ready); // trigger find all references &c. updates - } - - return success; + return component != null && ClearStateCache(new QualifiedModuleName(component), notifyStateChanged); } public bool ClearStateCache(QualifiedModuleName component, bool notifyStateChanged = false) @@ -802,31 +724,6 @@ public bool ClearStateCache(QualifiedModuleName component, bool notifyStateChang var success = RemoveKeysFromCollections(keys); - var projectId = component.ProjectId; - var sameProjectDeclarations = new List>(); - foreach (var item in _moduleStates) - { - if (item.Key.ProjectId == projectId) - { - sameProjectDeclarations.Add(new KeyValuePair(item.Key, item.Value)); - } - } - - var projectCount = 0; - foreach (var item in sameProjectDeclarations) - { - if (item.Value.Declarations == null) { continue; } - - foreach (var declaration in item.Value.Declarations) - { - if (declaration.Key.DeclarationType == DeclarationType.Project) - { - projectCount++; - break; - } - } - } - if (notifyStateChanged) { OnStateChanged(ParserState.ResolvedDeclarations); // trigger test explorer and code explorer updates @@ -914,13 +811,19 @@ public bool IsDirty() { foreach (var project in Projects) { - foreach (VBComponent component in project.VBComponents) + try { - if (IsNewOrModified(component)) + foreach (VBComponent component in project.VBComponents) { - return true; + if (IsNewOrModified(component)) + { + return true; + } } } + catch (COMException) + { + } } return false; diff --git a/Rubberduck.VBEEditor/QualifiedModuleName.cs b/Rubberduck.VBEEditor/QualifiedModuleName.cs index a5e6a5f685..58d277c2d4 100644 --- a/Rubberduck.VBEEditor/QualifiedModuleName.cs +++ b/Rubberduck.VBEEditor/QualifiedModuleName.cs @@ -9,22 +9,6 @@ namespace Rubberduck.VBEditor /// public struct QualifiedModuleName { - private static string GetDisplayName(VBProject project) - { - try - { - if (project.HelpFile != project.VBE.ActiveVBProject.HelpFile) - { - project.VBE.ActiveVBProject = project; - } - return project.VBE.MainWindow.Caption.Split(' ').Last(); - } - catch - { - return string.Empty; - } - } - public static string GetProjectId(VBProject project) { if (project == null) @@ -55,7 +39,7 @@ public QualifiedModuleName(VBProject project) _projectName = project.Name; _projectPath = string.Empty; _projectId = GetProjectId(project); - _projectDisplayName = GetDisplayName(project); + _projectDisplayName = string.Empty; _contentHashCode = 0; } @@ -67,9 +51,9 @@ public QualifiedModuleName(VBComponent component) _componentName = component == null ? string.Empty : component.Name; _project = component == null ? null : component.Collection.Parent; _projectName = _project == null ? string.Empty : _project.Name; - _projectDisplayName = GetDisplayName(_project); _projectPath = string.Empty; _projectId = GetProjectId(_project); + _projectDisplayName = string.Empty; _contentHashCode = 0; if (component == null) @@ -121,37 +105,40 @@ public QualifiedMemberName QualifyMemberName(string member) public string ComponentName { get { return _componentName ?? string.Empty; } } public string Name { get { return ToString(); } } - - private readonly string _projectDisplayName; - public string ProjectDisplayName { get { return _projectDisplayName; } } - /// - /// returns: "ProjectName (DisplayName)" as typically displayed in VBE Project Explorer - /// - public string ProjectTitle - { - get - { - return _projectName + (_projectDisplayName != null ? " (" + _projectDisplayName + ")" : string.Empty); - } - } - private readonly string _projectName; + public string ProjectName { get { return _projectName; } } - public string ProjectName - { - get - { - return _projectName; - } - } private readonly string _projectPath; + public string ProjectPath { get { return _projectPath; } } - public string ProjectPath + // because this causes a flicker in the VBE, we only want to do it once. + // we also want to defer it as long as possible because it is only + // needed in a couple places, and QualifiedModuleName is used in many places. + private string _projectDisplayName; + public string ProjectDisplayName { get { - return _projectPath; + if (_projectDisplayName != string.Empty) + { + return _projectDisplayName; + } + + try + { + if (_project.HelpFile != _project.VBE.ActiveVBProject.HelpFile) + { + _project.VBE.ActiveVBProject = _project; + } + + _projectDisplayName = _project.VBE.MainWindow.Caption.Split(' ').Last(); + return _projectDisplayName; + } + catch + { + return string.Empty; + } } } diff --git a/RubberduckTests/MockParser.cs b/RubberduckTests/MockParser.cs index 6e2831a75d..2884c90bbd 100644 --- a/RubberduckTests/MockParser.cs +++ b/RubberduckTests/MockParser.cs @@ -41,7 +41,7 @@ public static RubberduckParser Create(VBE vbe, RubberduckParserState state) public static RubberduckParser Create(VBE vbe, RubberduckParserState state, IAttributeParser attributeParser) { - return new RubberduckParser(vbe, state, attributeParser, + return new RubberduckParser(state, attributeParser, () => new VBAPreprocessor(double.Parse(vbe.Version, CultureInfo.InvariantCulture)), new List {new DebugDeclarations(state), new FormEventDeclarations(state)}); }