11using System ;
22using System . Collections . Generic ;
33using System . ComponentModel . Composition ;
4- using System . Diagnostics ;
5- using System . Globalization ;
64using System . Linq ;
75using System . Threading ;
86using GitHub . Extensions ;
9- using GitHub . Logging ;
107using GitHub . Models ;
118using GitHub . Services ;
129using Microsoft . TeamFoundation . Controls ;
13- using Microsoft . VisualStudio . Shell ;
14- using Microsoft . VisualStudio . TeamFoundation . Git . Extensibility ;
15- using Serilog ;
1610
1711namespace GitHub . VisualStudio . Base
1812{
1913 [ Export ( typeof ( ITeamExplorerServiceHolder ) ) ]
2014 [ PartCreationPolicy ( CreationPolicy . Shared ) ]
2115 public class TeamExplorerServiceHolder : ITeamExplorerServiceHolder
2216 {
23- static readonly ILogger log = LogManager . ForContext < TeamExplorerServiceHolder > ( ) ;
2417 readonly Dictionary < object , Action < ILocalRepositoryModel > > activeRepoHandlers = new Dictionary < object , Action < ILocalRepositoryModel > > ( ) ;
2518 ILocalRepositoryModel activeRepo ;
2619 bool activeRepoNotified = false ;
2720
2821 IServiceProvider serviceProvider ;
29- IVSGitExt gitService ;
30- IVSUIContext gitUIContext ;
31- IVSUIContextFactory uiContextFactory ;
22+ readonly IVSGitExt gitService ;
3223
3324 // ActiveRepositories PropertyChanged event comes in on a non-main thread
3425 readonly SynchronizationContext syncContext ;
3526
3627 /// <summary>
37- /// This class relies on IVSUIContextFactory to get the UIContext object that provides information
38- /// when VS switches repositories. Unfortunately, for some reason MEF fails to create the instance
39- /// when imported from the constructor, so it's imported manually when first accessed via the
40- /// ServiceProvider instance (when mocking, make sure that the ServiceProvider includes this factory)
28+ /// This class relies on IVSGitExt that provides information when VS switches repositories.
4129 /// </summary>
42- /// <param name="gitService"></param>
30+ /// <param name="gitService">Used for monitoring the active repository. </param>
4331 [ ImportingConstructor ]
4432 public TeamExplorerServiceHolder ( IVSGitExt gitService )
4533 {
46- this . GitService = gitService ;
34+ this . gitService = gitService ;
4735 syncContext = SynchronizationContext . Current ;
36+
37+ UpdateActiveRepo ( ) ;
38+ gitService . ActiveRepositoriesChanged += UpdateActiveRepo ;
4839 }
4940
41+
5042 // set by the sections when they get initialized
5143 public IServiceProvider ServiceProvider
5244 {
@@ -59,8 +51,6 @@ public IServiceProvider ServiceProvider
5951 serviceProvider = value ;
6052 if ( serviceProvider == null )
6153 return ;
62- GitUIContext = GitUIContext ?? UIContextFactory . GetUIContext ( new Guid ( Guids . GitSccProviderId ) ) ;
63- UIContextChanged ( GitUIContext ? . IsActive ?? false , false ) ;
6454 }
6555 }
6656
@@ -133,12 +123,6 @@ public void ClearServiceProvider(IServiceProvider provider)
133123 ServiceProvider = null ;
134124 }
135125
136- public void Refresh ( )
137- {
138- GitUIContext = GitUIContext ?? UIContextFactory . GetUIContext ( new Guid ( Guids . GitSccProviderId ) ) ;
139- UIContextChanged ( GitUIContext ? . IsActive ?? false , true ) ;
140- }
141-
142126 void NotifyActiveRepo ( )
143127 {
144128 lock ( activeRepoHandlers )
@@ -149,51 +133,6 @@ void NotifyActiveRepo()
149133 }
150134 }
151135
152- void UIContextChanged ( object sender , IVSUIContextChangedEventArgs e )
153- {
154- Guard . ArgumentNotNull ( e , nameof ( e ) ) ;
155-
156- ActiveRepo = null ;
157- UIContextChanged ( e . Activated , false ) ;
158- }
159-
160- /// <summary>
161- /// This is called on a background thread. Do not do synchronous GetService calls here.
162- /// </summary>
163- /// <param name="active"></param>
164- /// <param name="refresh"></param>
165- async void UIContextChanged ( bool active , bool refresh )
166- {
167- Debug . Assert ( ServiceProvider != null , "UIContextChanged called before service provider is set" ) ;
168- if ( ServiceProvider == null )
169- return ;
170-
171- if ( active )
172- {
173- if ( ActiveRepo == null || refresh )
174- {
175- ActiveRepo = await System . Threading . Tasks . Task . Run ( ( ) =>
176- {
177- var repos = GitService . ActiveRepositories ;
178- // Looks like this might return null after a while, for some unknown reason
179- // if it does, let's refresh the GitService instance in case something got wonky
180- // and try again. See issue #23
181- if ( repos == null )
182- {
183- log . Error ( "Error 2001: ActiveRepositories is null. GitService: '{GitService}'" , GitService ) ;
184- GitService . Refresh ( ServiceProvider ) ;
185- repos = GitService . ActiveRepositories ;
186- if ( repos == null )
187- log . Error ( "Error 2002: ActiveRepositories is null. GitService: '{GitService}'" , GitService ) ;
188- }
189- return repos ? . FirstOrDefault ( ) ;
190- } ) ;
191- }
192- }
193- else
194- ActiveRepo = null ;
195- }
196-
197136 void UpdateActiveRepo ( )
198137 {
199138 var repo = gitService . ActiveRepositories . FirstOrDefault ( ) ;
@@ -227,114 +166,5 @@ ITeamExplorerPage PageService
227166 {
228167 get { return ServiceProvider . GetServiceSafe < ITeamExplorerPage > ( ) ; }
229168 }
230-
231- IVSUIContext GitUIContext
232- {
233- get { return gitUIContext ; }
234- set
235- {
236- if ( gitUIContext == value )
237- return ;
238- if ( gitUIContext != null )
239- gitUIContext . UIContextChanged -= UIContextChanged ;
240- gitUIContext = value ;
241- if ( gitUIContext != null )
242- gitUIContext . UIContextChanged += UIContextChanged ;
243- }
244- }
245-
246- IVSGitExt GitService
247- {
248- get { return gitService ; }
249- set
250- {
251- if ( gitService == value )
252- return ;
253- if ( gitService != null )
254- gitService . ActiveRepositoriesChanged -= UpdateActiveRepo ;
255- gitService = value ;
256- if ( gitService != null )
257- gitService . ActiveRepositoriesChanged += UpdateActiveRepo ;
258- }
259- }
260-
261- IVSUIContextFactory UIContextFactory
262- {
263- get
264- {
265- if ( uiContextFactory == null )
266- {
267- uiContextFactory = ServiceProvider . GetServiceSafe < IVSUIContextFactory > ( ) ;
268- }
269- return uiContextFactory ;
270- }
271- }
272- }
273-
274- [ Export ( typeof ( IVSUIContextFactory ) ) ]
275- [ PartCreationPolicy ( CreationPolicy . Shared ) ]
276- class VSUIContextFactory : IVSUIContextFactory
277- {
278- public IVSUIContext GetUIContext ( Guid contextGuid )
279- {
280- return new VSUIContext ( UIContext . FromUIContextGuid ( contextGuid ) ) ;
281- }
282- }
283-
284- class VSUIContextChangedEventArgs : IVSUIContextChangedEventArgs
285- {
286- public bool Activated { get ; }
287-
288- public VSUIContextChangedEventArgs ( bool activated )
289- {
290- Activated = activated ;
291- }
292- }
293-
294- class VSUIContext : IVSUIContext
295- {
296- readonly UIContext context ;
297- readonly Dictionary < EventHandler < IVSUIContextChangedEventArgs > , EventHandler < UIContextChangedEventArgs > > handlers =
298- new Dictionary < EventHandler < IVSUIContextChangedEventArgs > , EventHandler < UIContextChangedEventArgs > > ( ) ;
299- public VSUIContext ( UIContext context )
300- {
301- this . context = context ;
302- }
303-
304- public bool IsActive { get { return context . IsActive ; } }
305-
306- public event EventHandler < IVSUIContextChangedEventArgs > UIContextChanged
307- {
308- add
309- {
310- EventHandler < UIContextChangedEventArgs > handler = null ;
311- if ( ! handlers . TryGetValue ( value , out handler ) )
312- {
313- handler = ( s , e ) => value . Invoke ( s , new VSUIContextChangedEventArgs ( e . Activated ) ) ;
314- handlers . Add ( value , handler ) ;
315- }
316- context . UIContextChanged += handler ;
317- }
318- remove
319- {
320- EventHandler < UIContextChangedEventArgs > handler = null ;
321- if ( handlers . TryGetValue ( value , out handler ) )
322- {
323- handlers . Remove ( value ) ;
324- context . UIContextChanged -= handler ;
325- }
326- }
327- }
328- }
329-
330- static class IGitRepositoryInfoExtensions
331- {
332- /// <summary>
333- /// Create a LocalRepositoryModel from a VS git repo object
334- /// </summary>
335- public static ILocalRepositoryModel ToModel ( this IGitRepositoryInfo repo )
336- {
337- return repo == null ? null : new LocalRepositoryModel ( repo . RepositoryPath ) ;
338- }
339169 }
340170}
0 commit comments