1 /*******************************************************************************
2 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v1.0
7 * which accompanies this distribution, and is available at
8 * http://www.eclipse.org/legal/epl-v10.html
9 *******************************************************************************/
10 package org
.eclipse
.egit
.ui
;
12 import java
.net
.Authenticator
;
13 import java
.net
.ProxySelector
;
14 import java
.util
.ArrayList
;
15 import java
.util
.HashSet
;
16 import java
.util
.Iterator
;
17 import java
.util
.LinkedHashSet
;
18 import java
.util
.List
;
21 import org
.eclipse
.core
.net
.proxy
.IProxyService
;
22 import org
.eclipse
.core
.resources
.IProject
;
23 import org
.eclipse
.core
.resources
.IResource
;
24 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
25 import org
.eclipse
.core
.runtime
.CoreException
;
26 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
27 import org
.eclipse
.core
.runtime
.IStatus
;
28 import org
.eclipse
.core
.runtime
.Status
;
29 import org
.eclipse
.core
.runtime
.SubProgressMonitor
;
30 import org
.eclipse
.core
.runtime
.jobs
.ISchedulingRule
;
31 import org
.eclipse
.core
.runtime
.jobs
.Job
;
32 import org
.eclipse
.egit
.core
.internal
.trace
.GitTraceLocation
;
33 import org
.eclipse
.egit
.core
.project
.RepositoryMapping
;
34 import org
.eclipse
.jface
.util
.IPropertyChangeListener
;
35 import org
.eclipse
.jface
.util
.PropertyChangeEvent
;
36 import org
.eclipse
.jgit
.lib
.IndexChangedEvent
;
37 import org
.eclipse
.jgit
.lib
.RefsChangedEvent
;
38 import org
.eclipse
.jgit
.lib
.Repository
;
39 import org
.eclipse
.jgit
.lib
.RepositoryListener
;
40 import org
.eclipse
.jgit
.transport
.SshSessionFactory
;
41 import org
.eclipse
.jsch
.core
.IJSchService
;
42 import org
.eclipse
.swt
.graphics
.Font
;
43 import org
.eclipse
.swt
.widgets
.Display
;
44 import org
.eclipse
.ui
.plugin
.AbstractUIPlugin
;
45 import org
.eclipse
.ui
.themes
.ITheme
;
46 import org
.osgi
.framework
.BundleContext
;
47 import org
.osgi
.framework
.ServiceReference
;
50 * This is a plugin singleton mostly controlling logging.
52 public class Activator
extends AbstractUIPlugin
{
55 * The one and only instance
57 private static Activator plugin
;
60 * Property listeners for plugin specific events
62 private static List
<IPropertyChangeListener
> propertyChangeListeners
=
63 new ArrayList
<IPropertyChangeListener
>(5);
66 * Property constant indicating the decorator configuration has changed.
68 public static final String DECORATORS_CHANGED
= "org.eclipse.egit.ui.DECORATORS_CHANGED"; //$NON-NLS-1$
71 * @return the {@link Activator} singleton.
73 public static Activator
getDefault() {
78 * @return the id of the egit ui plugin
80 public static String
getPluginId() {
81 return getDefault().getBundle().getSymbolicName();
85 * Returns the standard display to be used. The method first checks, if the
86 * thread calling this method has an associated display. If so, this display
87 * is returned. Otherwise the method returns the default display.
89 * @return the display to use
91 public static Display
getStandardDisplay() {
92 Display display
= Display
.getCurrent();
93 if (display
== null) {
94 display
= Display
.getDefault();
100 * Instantiate an error exception.
103 * description of the error
105 * cause of the error or null
106 * @return an initialized {@link CoreException}
108 public static CoreException
error(final String message
, final Throwable thr
) {
109 return new CoreException(new Status(IStatus
.ERROR
, getPluginId(), 0,
114 * Log an error via the Eclipse logging routines.
120 public static void logError(final String message
, final Throwable thr
) {
121 getDefault().getLog().log(
122 new Status(IStatus
.ERROR
, getPluginId(), 0, message
, thr
));
126 * Get the theme used by this plugin.
130 public static ITheme
getTheme() {
131 return plugin
.getWorkbench().getThemeManager().getCurrentTheme();
135 * Get a font known to this plugin.
138 * one of our THEME_* font preference ids (see
139 * {@link UIPreferences});
140 * @return the configured font, borrowed from the registry.
142 public static Font
getFont(final String id
) {
143 return getTheme().getFontRegistry().get(id
);
147 * Get a font known to this plugin, but with bold style applied over top.
150 * one of our THEME_* font preference ids (see
151 * {@link UIPreferences});
152 * @return the configured font, borrowed from the registry.
154 public static Font
getBoldFont(final String id
) {
155 return getTheme().getFontRegistry().getBold(id
);
159 private RIRefresh refreshJob
;
162 * Constructor for the egit ui plugin singleton
168 public void start(final BundleContext context
) throws Exception
{
169 super.start(context
);
172 setupRepoChangeScanner();
173 setupRepoIndexRefresh();
176 private void setupRepoIndexRefresh() {
177 refreshJob
= new RIRefresh();
178 Repository
.addAnyRepositoryChangedListener(refreshJob
);
182 * Register for changes made to Team properties.
185 * The listener to register
187 public static synchronized void addPropertyChangeListener(
188 IPropertyChangeListener listener
) {
189 propertyChangeListeners
.add(listener
);
193 * Remove a Team property changes.
196 * The listener to remove
198 public static synchronized void removePropertyChangeListener(
199 IPropertyChangeListener listener
) {
200 propertyChangeListeners
.remove(listener
);
204 * Broadcast a Team property change.
207 * The event to broadcast
209 public static synchronized void broadcastPropertyChange(PropertyChangeEvent event
) {
210 for (IPropertyChangeListener listener
: propertyChangeListeners
)
211 listener
.propertyChange(event
);
214 static class RIRefresh
extends Job
implements RepositoryListener
{
217 super("Git index refresh Job");
220 private Set
<IProject
> projectsToScan
= new LinkedHashSet
<IProject
>();
223 protected IStatus
run(IProgressMonitor monitor
) {
224 IProject
[] projects
= ResourcesPlugin
.getWorkspace().getRoot().getProjects();
225 monitor
.beginTask("Refreshing git managed projects", projects
.length
);
227 while (projectsToScan
.size() > 0) {
229 synchronized (projectsToScan
) {
230 if (projectsToScan
.size() == 0)
232 Iterator
<IProject
> i
= projectsToScan
.iterator();
236 ISchedulingRule rule
= p
.getWorkspace().getRuleFactory().refreshRule(p
);
238 getJobManager().beginRule(rule
, monitor
);
239 p
.refreshLocal(IResource
.DEPTH_INFINITE
, new SubProgressMonitor(monitor
, 1));
240 } catch (CoreException e
) {
241 logError("Failed to refresh projects from index changes", e
);
242 return new Status(IStatus
.ERROR
, getPluginId(), e
.getMessage());
244 getJobManager().endRule(rule
);
248 return Status
.OK_STATUS
;
251 public void indexChanged(IndexChangedEvent e
) {
252 // Check the workspace setting "refresh automatically" setting first
253 if (!ResourcesPlugin
.getPlugin().getPluginPreferences().getBoolean(
254 ResourcesPlugin
.PREF_AUTO_REFRESH
))
257 IProject
[] projects
= ResourcesPlugin
.getWorkspace().getRoot().getProjects();
258 Set
<IProject
> toRefresh
= new HashSet
<IProject
>();
259 for (IProject p
: projects
) {
260 RepositoryMapping mapping
= RepositoryMapping
.getMapping(p
);
261 if (mapping
!= null && mapping
.getRepository() == e
.getRepository()) {
265 synchronized (projectsToScan
) {
266 projectsToScan
.addAll(toRefresh
);
268 if (projectsToScan
.size() > 0)
272 public void refsChanged(RefsChangedEvent e
) {
278 static class RCS
extends Job
{
280 super("Repository Change Scanner");
283 // FIXME, need to be more intelligent about this to avoid too much work
284 private static final long REPO_SCAN_INTERVAL
= 10000L;
287 protected IStatus
run(IProgressMonitor monitor
) {
289 // A repository can contain many projects, only scan once
290 // (a project could in theory be distributed among many
291 // repositories. We discard that as being ugly and stupid for
293 IProject
[] projects
= ResourcesPlugin
.getWorkspace().getRoot().getProjects();
294 monitor
.beginTask("Scanning Git repositories for changes", projects
.length
);
295 Set
<Repository
> scanned
= new HashSet
<Repository
>();
296 for (IProject p
: projects
) {
297 RepositoryMapping mapping
= RepositoryMapping
.getMapping(p
);
298 if (mapping
!= null) {
299 Repository r
= mapping
.getRepository();
300 if (!scanned
.contains(r
)) {
301 if (monitor
.isCanceled())
303 // TODO is this the right location?
304 if (GitTraceLocation
.UI
.isActive())
305 GitTraceLocation
.getTrace().trace(
306 GitTraceLocation
.UI
.getLocation(),
307 "Scanning " + r
+ " for changes"); //$NON-NLS-1$ //$NON-NLS-2$
309 ISchedulingRule rule
= p
.getWorkspace().getRuleFactory().modifyRule(p
);
310 getJobManager().beginRule(rule
, monitor
);
312 r
.scanForRepoChanges();
314 getJobManager().endRule(rule
);
321 // TODO is this the right location?
322 if (GitTraceLocation
.UI
.isActive())
323 GitTraceLocation
.getTrace().trace(
324 GitTraceLocation
.UI
.getLocation(),
325 "Rescheduling " + getName() + " job"); //$NON-NLS-1$ //$NON-NLS-2$
326 schedule(REPO_SCAN_INTERVAL
);
327 } catch (Exception e
) {
328 // TODO is this the right location?
329 if (GitTraceLocation
.UI
.isActive())
330 GitTraceLocation
.getTrace().trace(
331 GitTraceLocation
.UI
.getLocation(),
332 "Stopped rescheduling " + getName() + "job"); //$NON-NLS-1$ //$NON-NLS-2$
337 "An error occurred while scanning for changes. Scanning aborted",
340 return Status
.OK_STATUS
;
344 private void setupRepoChangeScanner() {
346 rcs
.schedule(RCS
.REPO_SCAN_INTERVAL
);
349 private void setupSSH(final BundleContext context
) {
350 final ServiceReference ssh
;
352 ssh
= context
.getServiceReference(IJSchService
.class.getName());
354 SshSessionFactory
.setInstance(new EclipseSshSessionFactory(
355 (IJSchService
) context
.getService(ssh
)));
359 private void setupProxy(final BundleContext context
) {
360 final ServiceReference proxy
;
362 proxy
= context
.getServiceReference(IProxyService
.class.getName());
364 ProxySelector
.setDefault(new EclipseProxySelector(
365 (IProxyService
) context
.getService(proxy
)));
366 Authenticator
.setDefault(new EclipseAuthenticator(
367 (IProxyService
) context
.getService(proxy
)));
371 public void stop(final BundleContext context
) throws Exception
{
372 if (GitTraceLocation
.UI
.isActive())
373 GitTraceLocation
.getTrace().trace(
374 GitTraceLocation
.UI
.getLocation(),
375 "Trying to cancel " + rcs
.getName() + " job"); //$NON-NLS-1$ //$NON-NLS-2$
377 if (GitTraceLocation
.UI
.isActive())
378 GitTraceLocation
.getTrace().trace(
379 GitTraceLocation
.UI
.getLocation(),
380 "Trying to cancel " + refreshJob
.getName() + " job"); //$NON-NLS-1$ //$NON-NLS-2$
386 if (GitTraceLocation
.UI
.isActive())
387 GitTraceLocation
.getTrace().trace(
388 GitTraceLocation
.UI
.getLocation(), "Jobs terminated"); //$NON-NLS-1$