Skip to content

Commit 0200dc7

Browse files
authored
Merge pull request #3701 from bclothier/EventInterface
Event interface
2 parents 15b4678 + d8d648a commit 0200dc7

File tree

18 files changed

+444
-298
lines changed

18 files changed

+444
-298
lines changed

RetailCoder.VBE/API/VBA/ParserState.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Rubberduck.UI.Command.MenuItems;
1212
using Rubberduck.Parsing.Symbols;
1313
using Rubberduck.VBEditor.ComManagement;
14+
using Rubberduck.VBEditor.Events;
1415
using Rubberduck.VBEditor.SafeComWrappers.VBA;
1516

1617
namespace Rubberduck.API.VBA

Rubberduck.Parsing/VBA/RubberduckParserState.cs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
using Rubberduck.VBEditor.ComManagement;
1919
using Rubberduck.VBEditor.Events;
2020
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
21-
using Rubberduck.VBEditor.SafeComWrappers.VBA;
2221

2322
// ReSharper disable LoopCanBeConvertedToQuery
2423

@@ -63,7 +62,8 @@ public sealed class RubberduckParserState : IDisposable, IDeclarationFinderProvi
6362
public DeclarationFinder DeclarationFinder { get; private set; }
6463

6564
private readonly IVBE _vbe;
66-
private readonly IProjectsRepository _projectRepository;
65+
private readonly IProjectsRepository _projectRepository;
66+
private readonly IVBEEvents _vbeEvents;
6767
private readonly IHostApplication _hostApp;
6868
private readonly IDeclarationFinderFactory _declarationFinderFactory;
6969

@@ -82,9 +82,9 @@ public RubberduckParserState(IVBE vbe, IProjectsRepository projectRepository, ID
8282
throw new ArgumentException(nameof(projectRepository));
8383
}
8484

85-
8685
_vbe = vbe;
8786
_projectRepository = projectRepository;
87+
_vbeEvents = VBEEvents.Initialize(_vbe);
8888
_declarationFinderFactory = declarationFinderFactory;
8989

9090
var values = Enum.GetValues(typeof(ParserState));
@@ -115,22 +115,22 @@ public void RefreshDeclarationFinder()
115115

116116
private void AddEventHandlers()
117117
{
118-
VBProjects.ProjectAdded += Sinks_ProjectAdded;
119-
VBProjects.ProjectRemoved += Sinks_ProjectRemoved;
120-
VBProjects.ProjectRenamed += Sinks_ProjectRenamed;
121-
VBComponents.ComponentAdded += Sinks_ComponentAdded;
122-
VBComponents.ComponentRemoved += Sinks_ComponentRemoved;
123-
VBComponents.ComponentRenamed += Sinks_ComponentRenamed;
118+
_vbeEvents.ProjectAdded += Sinks_ProjectAdded;
119+
_vbeEvents.ProjectRemoved += Sinks_ProjectRemoved;
120+
_vbeEvents.ProjectRenamed += Sinks_ProjectRenamed;
121+
_vbeEvents.ComponentAdded += Sinks_ComponentAdded;
122+
_vbeEvents.ComponentRemoved += Sinks_ComponentRemoved;
123+
_vbeEvents.ComponentRenamed += Sinks_ComponentRenamed;
124124
}
125125

126126
private void RemoveEventHandlers()
127127
{
128-
VBProjects.ProjectAdded -= Sinks_ProjectAdded;
129-
VBProjects.ProjectRemoved -= Sinks_ProjectRemoved;
130-
VBProjects.ProjectRenamed -= Sinks_ProjectRenamed;
131-
VBComponents.ComponentAdded -= Sinks_ComponentAdded;
132-
VBComponents.ComponentRemoved -= Sinks_ComponentRemoved;
133-
VBComponents.ComponentRenamed -= Sinks_ComponentRenamed;
128+
_vbeEvents.ProjectAdded -= Sinks_ProjectAdded;
129+
_vbeEvents.ProjectRemoved -= Sinks_ProjectRemoved;
130+
_vbeEvents.ProjectRenamed -= Sinks_ProjectRenamed;
131+
_vbeEvents.ComponentAdded -= Sinks_ComponentAdded;
132+
_vbeEvents.ComponentRemoved -= Sinks_ComponentRemoved;
133+
_vbeEvents.ComponentRenamed -= Sinks_ComponentRenamed;
134134
}
135135

136136
private void Sinks_ProjectAdded(object sender, ProjectEventArgs e)
@@ -349,7 +349,7 @@ public void SetModuleState(QualifiedModuleName module, ParserState state, Syntax
349349
private IVBProject GetProject(string projectId)
350350
{
351351
return _projectRepository.Project(projectId);
352-
}
352+
}
353353

354354
public void EvaluateParserState()
355355
{
@@ -952,6 +952,7 @@ public void Dispose()
952952

953953
CoClasses?.Clear();
954954
RemoveEventHandlers();
955+
VBEEvents.Terminate();
955956

956957
_moduleStates.Clear();
957958

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
3+
namespace Rubberduck.VBEditor.Events
4+
{
5+
public interface IVBEEvents
6+
{
7+
event EventHandler<ProjectEventArgs> ProjectAdded;
8+
event EventHandler<ProjectEventArgs> ProjectRemoved;
9+
event EventHandler<ProjectRenamedEventArgs> ProjectRenamed;
10+
event EventHandler<ProjectEventArgs> ProjectActivated;
11+
event EventHandler<ComponentEventArgs> ComponentAdded;
12+
event EventHandler<ComponentEventArgs> ComponentRemoved;
13+
event EventHandler<ComponentRenamedEventArgs> ComponentRenamed;
14+
event EventHandler<ComponentEventArgs> ComponentSelected;
15+
event EventHandler<ComponentEventArgs> ComponentActivated;
16+
event EventHandler<ComponentEventArgs> ComponentReloaded;
17+
event EventHandler EventsTerminated;
18+
}
19+
}

Rubberduck.VBEEditor/Events/VBENativeServices.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ public static void UnhookEvents()
6363
info.Subclass.FocusChange -= FocusDispatcher;
6464
info.Subclass.Dispose();
6565
}
66-
SafeComWrappers.VBA.VBProjects.DetatchEvents();
67-
SafeComWrappers.VBA.VBComponents.DetatchEvents();
66+
VBEEvents.Terminate();
6867
}
6968
}
7069

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Rubberduck.VBEditor.SafeComWrappers;
5+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
6+
7+
namespace Rubberduck.VBEditor.Events
8+
{
9+
public sealed class VBEEvents : IVBEEvents
10+
{
11+
private static VBEEvents _instance;
12+
private static readonly object Lock = new object();
13+
private readonly IVBProjects _projects;
14+
private readonly Dictionary<string, IVBComponents> _components;
15+
16+
public static VBEEvents Initialize(IVBE vbe)
17+
{
18+
lock (Lock)
19+
{
20+
if (_instance == null)
21+
{
22+
_instance = new VBEEvents(vbe);
23+
}
24+
}
25+
26+
return _instance;
27+
}
28+
29+
public static void Terminate()
30+
{
31+
lock (Lock)
32+
{
33+
if (_instance == null)
34+
{
35+
return;
36+
}
37+
38+
_instance.Dispose();
39+
_instance = null;
40+
}
41+
}
42+
43+
private VBEEvents(IVBE vbe)
44+
{
45+
_components = new Dictionary<string, IVBComponents>();
46+
47+
if (_projects != null)
48+
{
49+
return;
50+
}
51+
52+
_projects = vbe.VBProjects;
53+
54+
_projects.AttachEvents();
55+
_projects.ProjectAdded += ProjectAddedHandler;
56+
_projects.ProjectRemoved += ProjectRemovedHandler;
57+
_projects.ProjectRenamed += ProjectRenamedHandler;
58+
_projects.ProjectActivated += ProjectActivatedHandler;
59+
foreach (var project in _projects)
60+
using (project)
61+
{
62+
{
63+
RegisterComponents(project);
64+
}
65+
}
66+
}
67+
68+
private void RegisterComponents(IVBProject project)
69+
{
70+
if (project.IsWrappingNullReference || project.Protection != ProjectProtection.Unprotected)
71+
{
72+
return;
73+
}
74+
75+
if (string.IsNullOrWhiteSpace(project.ProjectId))
76+
{
77+
project.AssignProjectId();
78+
}
79+
80+
var components = project.VBComponents;
81+
_components.Add(project.ProjectId, components);
82+
83+
components.AttachEvents();
84+
components.ComponentAdded += ComponentAddedHandler;
85+
components.ComponentRemoved += ComponentRemovedHandler;
86+
components.ComponentRenamed += ComponentRenamedHandler;
87+
components.ComponentActivated += ComponentActivatedHandler;
88+
components.ComponentSelected += ComponentSelectedHandler;
89+
components.ComponentReloaded += ComponentReloadedHandler;
90+
}
91+
92+
private void UnregisterComponents(string projectId)
93+
{
94+
if (!_components.ContainsKey(projectId))
95+
{
96+
return;
97+
}
98+
99+
using (var components = _components[projectId])
100+
{
101+
components.ComponentAdded -= ComponentAddedHandler;
102+
components.ComponentRemoved -= ComponentRemovedHandler;
103+
components.ComponentRenamed -= ComponentRenamedHandler;
104+
components.ComponentActivated -= ComponentActivatedHandler;
105+
components.ComponentSelected -= ComponentSelectedHandler;
106+
components.ComponentReloaded -= ComponentReloadedHandler;
107+
components.DetachEvents();
108+
109+
_components.Remove(projectId);
110+
}
111+
}
112+
113+
public event EventHandler<ProjectEventArgs> ProjectAdded;
114+
private void ProjectAddedHandler(object sender, ProjectEventArgs e)
115+
{
116+
if (!_components.ContainsKey(e.ProjectId))
117+
{
118+
RegisterComponents(e.Project);
119+
}
120+
ProjectAdded?.Invoke(sender, e);
121+
}
122+
123+
public event EventHandler<ProjectEventArgs> ProjectRemoved;
124+
private void ProjectRemovedHandler(object sender, ProjectEventArgs e)
125+
{
126+
UnregisterComponents(e.ProjectId);
127+
ProjectRemoved?.Invoke(sender, e);
128+
}
129+
130+
public event EventHandler<ProjectRenamedEventArgs> ProjectRenamed;
131+
private void ProjectRenamedHandler(object sender, ProjectRenamedEventArgs e)
132+
{
133+
ProjectRenamed?.Invoke(sender, e);
134+
}
135+
136+
public event EventHandler<ProjectEventArgs> ProjectActivated;
137+
private void ProjectActivatedHandler(object sender, ProjectEventArgs e)
138+
{
139+
ProjectActivated?.Invoke(sender, e);
140+
}
141+
142+
public event EventHandler<ComponentEventArgs> ComponentAdded;
143+
private void ComponentAddedHandler(object sender, ComponentEventArgs e)
144+
{
145+
ComponentAdded?.Invoke(sender, e);
146+
}
147+
148+
public event EventHandler<ComponentEventArgs> ComponentRemoved;
149+
private void ComponentRemovedHandler(object sender, ComponentEventArgs e)
150+
{
151+
ComponentRemoved?.Invoke(sender, e);
152+
}
153+
154+
public event EventHandler<ComponentRenamedEventArgs> ComponentRenamed;
155+
private void ComponentRenamedHandler(object sender, ComponentRenamedEventArgs e)
156+
{
157+
ComponentRenamed?.Invoke(sender, e);
158+
}
159+
160+
public event EventHandler<ComponentEventArgs> ComponentActivated;
161+
private void ComponentActivatedHandler(object sender, ComponentEventArgs e)
162+
{
163+
ComponentActivated?.Invoke(sender, e);
164+
}
165+
166+
public event EventHandler<ComponentEventArgs> ComponentSelected;
167+
private void ComponentSelectedHandler(object sender, ComponentEventArgs e)
168+
{
169+
ComponentSelected?.Invoke(sender, e);
170+
}
171+
172+
public event EventHandler<ComponentEventArgs> ComponentReloaded;
173+
private void ComponentReloadedHandler(object sender, ComponentEventArgs e)
174+
{
175+
ComponentReloaded?.Invoke(sender, e);
176+
}
177+
178+
public event EventHandler EventsTerminated;
179+
180+
#region IDisposable
181+
182+
private bool _disposed;
183+
/// <remarks>
184+
/// This is a not a true implementation of IDisposable pattern
185+
/// because the method is made private and is available only
186+
/// via the static method <see cref="Terminate"/> to provide
187+
/// a single point of entry for disposing the singleton class
188+
/// </remarks>
189+
private void Dispose(bool disposing)
190+
{
191+
if (!_disposed && _projects != null)
192+
{
193+
EventsTerminated?.Invoke(this, EventArgs.Empty);
194+
195+
var projectIds = _components.Keys.ToArray();
196+
foreach (var projectid in projectIds)
197+
{
198+
UnregisterComponents(projectid);
199+
}
200+
201+
_projects.ProjectActivated -= ProjectActivatedHandler;
202+
_projects.ProjectRenamed -= ProjectRenamedHandler;
203+
_projects.ProjectRemoved -= ProjectRemovedHandler;
204+
_projects.ProjectAdded -= ProjectAddedHandler;
205+
_projects.DetachEvents();
206+
_projects.Dispose();
207+
208+
_disposed = true;
209+
}
210+
}
211+
212+
~VBEEvents()
213+
{
214+
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
215+
Dispose(false);
216+
}
217+
218+
// This code added to correctly implement the disposable pattern.
219+
private void Dispose()
220+
{
221+
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
222+
Dispose(true);
223+
GC.SuppressFinalize(this);
224+
}
225+
#endregion
226+
}
227+
}

Rubberduck.VBEEditor/Rubberduck.VBEditor.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<LangVersion>7.2</LangVersion>
3434
</PropertyGroup>
3535
<ItemGroup>
36+
<Reference Include="CustomMarshalers" />
3637
<Reference Include="Interop.SldWorks.Extensibility">
3738
<HintPath>..\libs\Interop.SldWorks.Extensibility.dll</HintPath>
3839
<EmbedInteropTypes>True</EmbedInteropTypes>
@@ -132,6 +133,7 @@
132133
<Compile Include="ComManagement\ComSafeManager.cs" />
133134
<Compile Include="ComManagement\IProjectsProvider.cs" />
134135
<Compile Include="ComManagement\IProjectsRepository.cs" />
136+
<Compile Include="Events\IVbeEvents.cs" />
135137
<Compile Include="ComManagement\ProjectsRepository.cs" />
136138
<Compile Include="ComManagement\TypeLibs\TypeInfos.cs" />
137139
<Compile Include="ComManagement\TypeLibs\TypeLibs.cs" />
@@ -145,13 +147,15 @@
145147
<Compile Include="Events\ProjectEventArgs.cs" />
146148
<Compile Include="Events\ProjectRenamedEventArgs.cs" />
147149
<Compile Include="Events\SelectionChangedEventArgs.cs" />
150+
<Compile Include="Events\VBEEvents.cs" />
148151
<Compile Include="Events\VBENativeServices.cs" />
149152
<Compile Include="Events\WindowChangedEventArgs.cs" />
150153
<Compile Include="Extensions\VBComponentExtensions.cs" />
151154
<Compile Include="Extensions\KeyValuePairExtensions.cs" />
152155
<Compile Include="Extensions\MSAccessComponentTypeExtensions.cs" />
153156
<Compile Include="SafeComWrappers\Office.Core\Abstract\IUserForm.cs" />
154157
<Compile Include="SafeComWrappers\Abstract\ISafeComWrapper.cs" />
158+
<Compile Include="SafeComWrappers\Abstract\ISafeEventedComWrapper.cs" />
155159
<Compile Include="SafeComWrappers\DispatcherEventArgs.cs" />
156160
<Compile Include="SafeComWrappers\MSAccessComponentType.cs" />
157161
<Compile Include="SafeComWrappers\MSForms\ControlType.cs" />
@@ -185,6 +189,7 @@
185189
<Compile Include="SafeComWrappers\Office.Core\Abstract\ICommandBarControls.cs" />
186190
<Compile Include="SafeComWrappers\Office.Core\Abstract\ICommandBarPopup.cs" />
187191
<Compile Include="SafeComWrappers\Office.Core\Abstract\ICommandBars.cs" />
192+
<Compile Include="SafeComWrappers\SafeEventedComWrapper.cs" />
188193
<Compile Include="SafeComWrappers\VB6\AddIn.cs" />
189194
<Compile Include="SafeComWrappers\VB6\AddIns.cs" />
190195
<Compile Include="SafeComWrappers\VB6\Application.cs" />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Rubberduck.VBEditor.SafeComWrappers.Abstract
2+
{
3+
public interface ISafeEventedComWrapper : ISafeComWrapper
4+
{
5+
void AttachEvents();
6+
void DetachEvents();
7+
}
8+
}

0 commit comments

Comments
 (0)