Make tracing 3.4 compatible and plug-in local
[egit/spearce.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / Activator.java
blobd06b33d23c625030a4742033684a9e847b988959
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;
19 import java.util.Set;
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.project.RepositoryMapping;
33 import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
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.osgi.service.debug.DebugOptions;
43 import org.eclipse.swt.graphics.Font;
44 import org.eclipse.swt.widgets.Display;
45 import org.eclipse.ui.plugin.AbstractUIPlugin;
46 import org.eclipse.ui.themes.ITheme;
47 import org.osgi.framework.BundleContext;
48 import org.osgi.framework.ServiceReference;
49 import org.osgi.util.tracker.ServiceTracker;
51 /**
52 * This is a plugin singleton mostly controlling logging.
54 public class Activator extends AbstractUIPlugin {
56 /**
57 * The one and only instance
59 private static Activator plugin;
61 /**
62 * Property listeners for plugin specific events
64 private static List<IPropertyChangeListener> propertyChangeListeners =
65 new ArrayList<IPropertyChangeListener>(5);
67 /**
68 * Property constant indicating the decorator configuration has changed.
70 public static final String DECORATORS_CHANGED = "org.eclipse.egit.ui.DECORATORS_CHANGED"; //$NON-NLS-1$
72 /**
73 * @return the {@link Activator} singleton.
75 public static Activator getDefault() {
76 return plugin;
79 /**
80 * @return the id of the egit ui plugin
82 public static String getPluginId() {
83 return getDefault().getBundle().getSymbolicName();
86 /**
87 * Returns the standard display to be used. The method first checks, if the
88 * thread calling this method has an associated display. If so, this display
89 * is returned. Otherwise the method returns the default display.
91 * @return the display to use
93 public static Display getStandardDisplay() {
94 Display display = Display.getCurrent();
95 if (display == null) {
96 display = Display.getDefault();
98 return display;
102 * Instantiate an error exception.
104 * @param message
105 * description of the error
106 * @param thr
107 * cause of the error or null
108 * @return an initialized {@link CoreException}
110 public static CoreException error(final String message, final Throwable thr) {
111 return new CoreException(new Status(IStatus.ERROR, getPluginId(), 0,
112 message, thr));
116 * Log an error via the Eclipse logging routines.
118 * @param message
119 * @param thr
120 * cause of error
122 public static void logError(final String message, final Throwable thr) {
123 getDefault().getLog().log(
124 new Status(IStatus.ERROR, getPluginId(), 0, message, thr));
128 * Get the theme used by this plugin.
130 * @return our theme.
132 public static ITheme getTheme() {
133 return plugin.getWorkbench().getThemeManager().getCurrentTheme();
137 * Get a font known to this plugin.
139 * @param id
140 * one of our THEME_* font preference ids (see
141 * {@link UIPreferences});
142 * @return the configured font, borrowed from the registry.
144 public static Font getFont(final String id) {
145 return getTheme().getFontRegistry().get(id);
149 * Get a font known to this plugin, but with bold style applied over top.
151 * @param id
152 * one of our THEME_* font preference ids (see
153 * {@link UIPreferences});
154 * @return the configured font, borrowed from the registry.
156 public static Font getBoldFont(final String id) {
157 return getTheme().getFontRegistry().getBold(id);
160 private RCS rcs;
161 private RIRefresh refreshJob;
164 * Constructor for the egit ui plugin singleton
166 public Activator() {
167 plugin = this;
170 public void start(final BundleContext context) throws Exception {
171 super.start(context);
173 if (isDebugging()) {
174 ServiceTracker debugTracker = new ServiceTracker(context,
175 DebugOptions.class.getName(), null);
176 debugTracker.open();
178 DebugOptions opts = (DebugOptions) debugTracker.getService();
179 GitTraceLocation.initializeFromOptions(opts, true);
182 setupSSH(context);
183 setupProxy(context);
184 setupRepoChangeScanner();
185 setupRepoIndexRefresh();
188 private void setupRepoIndexRefresh() {
189 refreshJob = new RIRefresh();
190 Repository.addAnyRepositoryChangedListener(refreshJob);
194 * Register for changes made to Team properties.
196 * @param listener
197 * The listener to register
199 public static synchronized void addPropertyChangeListener(
200 IPropertyChangeListener listener) {
201 propertyChangeListeners.add(listener);
205 * Remove a Team property changes.
207 * @param listener
208 * The listener to remove
210 public static synchronized void removePropertyChangeListener(
211 IPropertyChangeListener listener) {
212 propertyChangeListeners.remove(listener);
216 * Broadcast a Team property change.
218 * @param event
219 * The event to broadcast
221 public static synchronized void broadcastPropertyChange(PropertyChangeEvent event) {
222 for (IPropertyChangeListener listener : propertyChangeListeners)
223 listener.propertyChange(event);
226 static class RIRefresh extends Job implements RepositoryListener {
228 RIRefresh() {
229 super(UIText.Activator_refreshJobName);
232 private Set<IProject> projectsToScan = new LinkedHashSet<IProject>();
234 @Override
235 protected IStatus run(IProgressMonitor monitor) {
236 IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
237 monitor.beginTask(UIText.Activator_refreshingProjects, projects.length);
239 while (projectsToScan.size() > 0) {
240 IProject p;
241 synchronized (projectsToScan) {
242 if (projectsToScan.size() == 0)
243 break;
244 Iterator<IProject> i = projectsToScan.iterator();
245 p = i.next();
246 i.remove();
248 ISchedulingRule rule = p.getWorkspace().getRuleFactory().refreshRule(p);
249 try {
250 getJobManager().beginRule(rule, monitor);
251 p.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 1));
252 } catch (CoreException e) {
253 logError(UIText.Activator_refreshFailed, e);
254 return new Status(IStatus.ERROR, getPluginId(), e.getMessage());
255 } finally {
256 getJobManager().endRule(rule);
259 monitor.done();
260 return Status.OK_STATUS;
263 public void indexChanged(IndexChangedEvent e) {
264 // Check the workspace setting "refresh automatically" setting first
265 if (!ResourcesPlugin.getPlugin().getPluginPreferences().getBoolean(
266 ResourcesPlugin.PREF_AUTO_REFRESH))
267 return;
269 IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
270 Set<IProject> toRefresh= new HashSet<IProject>();
271 for (IProject p : projects) {
272 RepositoryMapping mapping = RepositoryMapping.getMapping(p);
273 if (mapping != null && mapping.getRepository() == e.getRepository()) {
274 toRefresh.add(p);
277 synchronized (projectsToScan) {
278 projectsToScan.addAll(toRefresh);
280 if (projectsToScan.size() > 0)
281 schedule();
284 public void refsChanged(RefsChangedEvent e) {
285 // Do not react here
290 static class RCS extends Job {
291 RCS() {
292 super(UIText.Activator_repoScanJobName);
295 // FIXME, need to be more intelligent about this to avoid too much work
296 private static final long REPO_SCAN_INTERVAL = 10000L;
297 // volatile in order to ensure thread synchronization
298 private volatile boolean doReschedule = true;
300 void setReschedule(boolean reschedule){
301 doReschedule = reschedule;
304 @Override
305 protected IStatus run(IProgressMonitor monitor) {
306 try {
307 // A repository can contain many projects, only scan once
308 // (a project could in theory be distributed among many
309 // repositories. We discard that as being ugly and stupid for
310 // the moment.
311 IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
312 monitor.beginTask(UIText.Activator_scanningRepositories, projects.length);
313 Set<Repository> scanned = new HashSet<Repository>();
314 for (IProject p : projects) {
315 RepositoryMapping mapping = RepositoryMapping.getMapping(p);
316 if (mapping != null) {
317 Repository r = mapping.getRepository();
318 if (!scanned.contains(r)) {
319 if (monitor.isCanceled())
320 break;
321 // TODO is this the right location?
322 if (GitTraceLocation.UI.isActive())
323 GitTraceLocation.getTrace().trace(
324 GitTraceLocation.UI.getLocation(),
325 "Scanning " + r + " for changes"); //$NON-NLS-1$ //$NON-NLS-2$
326 scanned.add(r);
327 ISchedulingRule rule = p.getWorkspace().getRuleFactory().modifyRule(p);
328 getJobManager().beginRule(rule, monitor);
329 try {
330 r.scanForRepoChanges();
331 } finally {
332 getJobManager().endRule(rule);
336 monitor.worked(1);
338 monitor.done();
339 // TODO is this the right location?
340 if (GitTraceLocation.UI.isActive())
341 GitTraceLocation.getTrace().trace(
342 GitTraceLocation.UI.getLocation(),
343 "Rescheduling " + getName() + " job"); //$NON-NLS-1$ //$NON-NLS-2$
344 if (doReschedule)
345 schedule(REPO_SCAN_INTERVAL);
346 } catch (Exception e) {
347 // TODO is this the right location?
348 if (GitTraceLocation.UI.isActive())
349 GitTraceLocation.getTrace().trace(
350 GitTraceLocation.UI.getLocation(),
351 "Stopped rescheduling " + getName() + "job"); //$NON-NLS-1$ //$NON-NLS-2$
352 return new Status(
353 IStatus.ERROR,
354 getPluginId(),
356 UIText.Activator_scanError,
359 return Status.OK_STATUS;
363 private void setupRepoChangeScanner() {
364 rcs = new RCS();
365 rcs.setSystem(true);
366 rcs.schedule(RCS.REPO_SCAN_INTERVAL);
369 private void setupSSH(final BundleContext context) {
370 final ServiceReference ssh;
372 ssh = context.getServiceReference(IJSchService.class.getName());
373 if (ssh != null) {
374 SshSessionFactory.setInstance(new EclipseSshSessionFactory(
375 (IJSchService) context.getService(ssh)));
379 private void setupProxy(final BundleContext context) {
380 final ServiceReference proxy;
382 proxy = context.getServiceReference(IProxyService.class.getName());
383 if (proxy != null) {
384 ProxySelector.setDefault(new EclipseProxySelector(
385 (IProxyService) context.getService(proxy)));
386 Authenticator.setDefault(new EclipseAuthenticator(
387 (IProxyService) context.getService(proxy)));
391 public void stop(final BundleContext context) throws Exception {
393 if (GitTraceLocation.UI.isActive())
394 GitTraceLocation.getTrace().trace(
395 GitTraceLocation.UI.getLocation(),
396 "Trying to cancel " + rcs.getName() + " job"); //$NON-NLS-1$ //$NON-NLS-2$
398 rcs.setReschedule(false);
400 rcs.cancel();
401 if (GitTraceLocation.UI.isActive())
402 GitTraceLocation.getTrace().trace(
403 GitTraceLocation.UI.getLocation(),
404 "Trying to cancel " + refreshJob.getName() + " job"); //$NON-NLS-1$ //$NON-NLS-2$
405 refreshJob.cancel();
407 rcs.join();
408 refreshJob.join();
410 if (GitTraceLocation.UI.isActive())
411 GitTraceLocation.getTrace().trace(
412 GitTraceLocation.UI.getLocation(), "Jobs terminated"); //$NON-NLS-1$
414 super.stop(context);
415 plugin = null;