Improve error reporting in the branch dialog
[egit/imyousuf.git] / org.spearce.egit.ui / src / org / spearce / egit / ui / Activator.java
blobb6aa51227c0beec22055bb0f0b290e543959cfa8
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 * See LICENSE for the full license text, also available.
8 *******************************************************************************/
9 package org.spearce.egit.ui;
11 import java.net.Authenticator;
12 import java.net.ProxySelector;
13 import java.util.ArrayList;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.LinkedHashSet;
17 import java.util.List;
18 import java.util.Set;
20 import org.eclipse.core.net.proxy.IProxyService;
21 import org.eclipse.core.resources.IProject;
22 import org.eclipse.core.resources.IResource;
23 import org.eclipse.core.resources.ResourcesPlugin;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.Platform;
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.jface.util.IPropertyChangeListener;
33 import org.eclipse.jface.util.PropertyChangeEvent;
34 import org.eclipse.jsch.core.IJSchService;
35 import org.eclipse.swt.graphics.Font;
36 import org.eclipse.swt.widgets.Display;
37 import org.eclipse.ui.plugin.AbstractUIPlugin;
38 import org.eclipse.ui.themes.ITheme;
39 import org.osgi.framework.BundleContext;
40 import org.osgi.framework.ServiceReference;
41 import org.spearce.egit.core.project.RepositoryMapping;
42 import org.spearce.jgit.lib.IndexChangedEvent;
43 import org.spearce.jgit.lib.RefsChangedEvent;
44 import org.spearce.jgit.lib.Repository;
45 import org.spearce.jgit.lib.RepositoryListener;
46 import org.spearce.jgit.transport.SshSessionFactory;
48 /**
49 * This is a plugin singleton mostly controlling logging.
51 public class Activator extends AbstractUIPlugin {
53 /**
54 * The one and only instance
56 private static Activator plugin;
58 /**
59 * Property listeners for plugin specific events
61 private static List<IPropertyChangeListener> propertyChangeListeners =
62 new ArrayList<IPropertyChangeListener>(5);
64 /**
65 * Property constant indicating the decorator configuration has changed.
67 public static final String DECORATORS_CHANGED = "org.spearce.egit.ui.DECORATORS_CHANGED"; //$NON-NLS-1$
69 /**
70 * @return the {@link Activator} singleton.
72 public static Activator getDefault() {
73 return plugin;
76 /**
77 * @return the id of the egit ui plugin
79 public static String getPluginId() {
80 return getDefault().getBundle().getSymbolicName();
83 /**
84 * Returns the standard display to be used. The method first checks, if the
85 * thread calling this method has an associated display. If so, this display
86 * is returned. Otherwise the method returns the default display.
88 * @return the display to use
90 public static Display getStandardDisplay() {
91 Display display = Display.getCurrent();
92 if (display == null) {
93 display = Display.getDefault();
95 return display;
98 /**
99 * Instantiate an error exception.
101 * @param message
102 * description of the error
103 * @param thr
104 * cause of the error or null
105 * @return an initialized {@link CoreException}
107 public static CoreException error(final String message, final Throwable thr) {
108 return new CoreException(new Status(IStatus.ERROR, getPluginId(), 0,
109 message, thr));
113 * Log an error via the Eclipse logging routines.
115 * @param message
116 * @param thr
117 * cause of error
119 public static void logError(final String message, final Throwable thr) {
120 getDefault().getLog().log(
121 new Status(IStatus.ERROR, getPluginId(), 0, message, thr));
125 * @param optionId
126 * name of debug option
127 * @return whether a named debug option is set
129 private static boolean isOptionSet(final String optionId) {
130 final String option = getPluginId() + optionId;
131 final String value = Platform.getDebugOption(option);
132 return value != null && value.equals("true");
136 * Log a debug message
138 * @param what
139 * message to log
141 public static void trace(final String what) {
142 if (getDefault().traceVerbose) {
143 System.out.println("[" + getPluginId() + "] " + what);
148 * Get the theme used by this plugin.
150 * @return our theme.
152 public static ITheme getTheme() {
153 return plugin.getWorkbench().getThemeManager().getCurrentTheme();
157 * Get a font known to this plugin.
159 * @param id
160 * one of our THEME_* font preference ids (see
161 * {@link UIPreferences});
162 * @return the configured font, borrowed from the registry.
164 public static Font getFont(final String id) {
165 return getTheme().getFontRegistry().get(id);
169 * Get a font known to this plugin, but with bold style applied over top.
171 * @param id
172 * one of our THEME_* font preference ids (see
173 * {@link UIPreferences});
174 * @return the configured font, borrowed from the registry.
176 public static Font getBoldFont(final String id) {
177 return getTheme().getFontRegistry().getBold(id);
180 private boolean traceVerbose;
181 private RCS rcs;
182 private RIRefresh refreshJob;
185 * Constructor for the egit ui plugin singleton
187 public Activator() {
188 plugin = this;
191 public void start(final BundleContext context) throws Exception {
192 super.start(context);
193 traceVerbose = isOptionSet("/trace/verbose");
194 setupSSH(context);
195 setupProxy(context);
196 setupRepoChangeScanner();
197 setupRepoIndexRefresh();
200 private void setupRepoIndexRefresh() {
201 refreshJob = new RIRefresh();
202 Repository.addAnyRepositoryChangedListener(refreshJob);
206 * Register for changes made to Team properties.
208 * @param listener
209 * The listener to register
211 public static synchronized void addPropertyChangeListener(
212 IPropertyChangeListener listener) {
213 propertyChangeListeners.add(listener);
217 * Remove a Team property changes.
219 * @param listener
220 * The listener to remove
222 public static synchronized void removePropertyChangeListener(
223 IPropertyChangeListener listener) {
224 propertyChangeListeners.remove(listener);
228 * Broadcast a Team property change.
230 * @param event
231 * The event to broadcast
233 public static synchronized void broadcastPropertyChange(PropertyChangeEvent event) {
234 for (IPropertyChangeListener listener : propertyChangeListeners)
235 listener.propertyChange(event);
238 static class RIRefresh extends Job implements RepositoryListener {
240 RIRefresh() {
241 super("Git index refresh Job");
244 private Set<IProject> projectsToScan = new LinkedHashSet<IProject>();
246 @Override
247 protected IStatus run(IProgressMonitor monitor) {
248 IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
249 monitor.beginTask("Refreshing git managed projects", projects.length);
251 while (projectsToScan.size() > 0) {
252 IProject p;
253 synchronized (projectsToScan) {
254 if (projectsToScan.size() == 0)
255 break;
256 Iterator<IProject> i = projectsToScan.iterator();
257 p = i.next();
258 i.remove();
260 ISchedulingRule rule = p.getWorkspace().getRuleFactory().refreshRule(p);
261 try {
262 getJobManager().beginRule(rule, monitor);
263 p.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 1));
264 } catch (CoreException e) {
265 logError("Failed to refresh projects from index changes", e);
266 return new Status(IStatus.ERROR, getPluginId(), e.getMessage());
267 } finally {
268 getJobManager().endRule(rule);
271 monitor.done();
272 return Status.OK_STATUS;
275 public void indexChanged(IndexChangedEvent e) {
276 // Check the workspace setting "refresh automatically" setting first
277 if (!ResourcesPlugin.getPlugin().getPluginPreferences().getBoolean(
278 ResourcesPlugin.PREF_AUTO_REFRESH))
279 return;
281 IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
282 Set<IProject> toRefresh= new HashSet<IProject>();
283 for (IProject p : projects) {
284 RepositoryMapping mapping = RepositoryMapping.getMapping(p);
285 if (mapping != null && mapping.getRepository() == e.getRepository()) {
286 toRefresh.add(p);
289 synchronized (projectsToScan) {
290 projectsToScan.addAll(toRefresh);
292 if (projectsToScan.size() > 0)
293 schedule();
296 public void refsChanged(RefsChangedEvent e) {
297 // Do not react here
302 static class RCS extends Job {
303 RCS() {
304 super("Repository Change Scanner");
307 // FIXME, need to be more intelligent about this to avoid too much work
308 private static final long REPO_SCAN_INTERVAL = 10000L;
310 @Override
311 protected IStatus run(IProgressMonitor monitor) {
312 try {
313 // A repository can contain many projects, only scan once
314 // (a project could in theory be distributed among many
315 // repositories. We discard that as being ugly and stupid for
316 // the moment.
317 IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
318 monitor.beginTask("Scanning Git repositories for changes", projects.length);
319 Set<Repository> scanned = new HashSet<Repository>();
320 for (IProject p : projects) {
321 RepositoryMapping mapping = RepositoryMapping.getMapping(p);
322 if (mapping != null) {
323 Repository r = mapping.getRepository();
324 if (!scanned.contains(r)) {
325 if (monitor.isCanceled())
326 break;
327 trace("Scanning " + r + " for changes");
328 scanned.add(r);
329 ISchedulingRule rule = p.getWorkspace().getRuleFactory().modifyRule(p);
330 getJobManager().beginRule(rule, monitor);
331 try {
332 r.scanForRepoChanges();
333 } finally {
334 getJobManager().endRule(rule);
338 monitor.worked(1);
340 monitor.done();
341 trace("Rescheduling " + getName() + " job");
342 schedule(REPO_SCAN_INTERVAL);
343 } catch (Exception e) {
344 trace("Stopped rescheduling " + getName() + "job");
345 return new Status(
346 IStatus.ERROR,
347 getPluginId(),
349 "An error occurred while scanning for changes. Scanning aborted",
352 return Status.OK_STATUS;
356 private void setupRepoChangeScanner() {
357 rcs = new RCS();
358 rcs.schedule(RCS.REPO_SCAN_INTERVAL);
361 private void setupSSH(final BundleContext context) {
362 final ServiceReference ssh;
364 ssh = context.getServiceReference(IJSchService.class.getName());
365 if (ssh != null) {
366 SshSessionFactory.setInstance(new EclipseSshSessionFactory(
367 (IJSchService) context.getService(ssh)));
371 private void setupProxy(final BundleContext context) {
372 final ServiceReference proxy;
374 proxy = context.getServiceReference(IProxyService.class.getName());
375 if (proxy != null) {
376 ProxySelector.setDefault(new EclipseProxySelector(
377 (IProxyService) context.getService(proxy)));
378 Authenticator.setDefault(new EclipseAuthenticator(
379 (IProxyService) context.getService(proxy)));
383 public void stop(final BundleContext context) throws Exception {
384 trace("Trying to cancel " + rcs.getName() + " job");
385 rcs.cancel();
386 trace("Trying to cancel " + refreshJob.getName() + " job");
387 refreshJob.cancel();
389 rcs.join();
390 refreshJob.join();
392 trace("Jobs terminated");
393 super.stop(context);
394 plugin = null;