org.tigris.subversion.subclipse.ui.SVNUIPlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.tigris.subversion.subclipse.ui.SVNUIPlugin.java

Source

/*******************************************************************************
 * Copyright (c) 2003, 2006 Subclipse project and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Subclipse project committers - initial API and implementation
 ******************************************************************************/
package org.tigris.subversion.subclipse.ui;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.core.TeamException;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.osgi.service.prefs.BackingStoreException;
import org.tigris.subversion.subclipse.core.ISVNRemoteFile;
import org.tigris.subversion.subclipse.core.ISVNRemoteFolder;
import org.tigris.subversion.subclipse.core.ISVNRepositoryLocation;
import org.tigris.subversion.subclipse.core.SVNClientManager;
import org.tigris.subversion.subclipse.core.SVNProviderPlugin;
import org.tigris.subversion.subclipse.core.SVNStatus;
import org.tigris.subversion.subclipse.core.resources.BaseResourceStorageFactory;
import org.tigris.subversion.subclipse.ui.actions.SVNPluginAction;
import org.tigris.subversion.subclipse.ui.actions.ShowOutOfDateFoldersAction;
import org.tigris.subversion.subclipse.ui.actions.WorkspaceAction;
import org.tigris.subversion.subclipse.ui.authentication.SVNPromptUserPassword;
import org.tigris.subversion.subclipse.ui.compare.UIBaseResourceStorageFactory;
import org.tigris.subversion.subclipse.ui.conflicts.MergeFileAssociation;
import org.tigris.subversion.subclipse.ui.console.SVNOutputConsole;
import org.tigris.subversion.subclipse.ui.repository.RepositoryManager;
import org.tigris.subversion.subclipse.ui.repository.model.SVNAdapterFactory;
import org.tigris.subversion.subclipse.ui.util.SimpleDialogsHelper;
import org.tigris.subversion.svnclientadapter.ISVNClientAdapter;

/**
 * UI Plugin for Subversion provider-specific workbench functionality.
 */
public class SVNUIPlugin extends AbstractUIPlugin {
    /**
     * The id of the SVN plug-in
     */
    public static final String ID = "org.tigris.subversion.subclipse.ui"; //$NON-NLS-1$
    public static final String DECORATOR_ID = "org.tigris.subversion.subclipse.ui.decorator"; //$NON-NLS-1$
    public static final String PROVIDER_ID = "org.tigris.subversion.subclipse.core.svnnature"; //$NON-NLS-1$

    // Merge provider extension point ID
    public static final String MERGE_PROVIDERS = "org.tigris.subversion.subclipse.ui.mergeProviders"; //$NON-NLS-1$   

    // Commit Dialog extension points
    public static final String COMMIT_DIALOG_TOOLBAR_ACTIONS = "org.tigris.subversion.subclipse.ui.commitDialogToolBarActions"; //$NON-NLS-1$
    public static final String COMMIT_DIALOG_COMPARE_ACTIONS = "org.tigris.subversion.subclipse.ui.commitDialogCompareActions"; //$NON-NLS-1$

    // Repository source provider extension point ID
    public static final String REPOSITORY_SOURCE_PROVIDERS = "org.tigris.subversion.subclipse.ui.svnRepositorySourceProviders"; //$NON-NLS-1$   

    /**
     * Property constant indicating the decorator configuration has changed. 
     */
    public static final String P_DECORATORS_CHANGED = SVNUIPlugin.ID + ".P_DECORATORS_CHANGED"; //$NON-NLS-1$
    /**
     * The singleton plug-in instance
     */
    private static SVNUIPlugin plugin;

    private static boolean loadErrorHandled = false;

    /**
     * The repository manager
     */
    private RepositoryManager repositoryManager;

    private ImageDescriptors imageDescriptors;

    private Preferences preferences;

    private static WorkspaceAction[] mergeProviders;
    private static SVNPluginAction[] commitDialogToolBarActions;
    private static SVNPluginAction[] commitDialogCompareActions;
    private static ISVNRepositorySourceProvider[] repositorySourceProviders;

    //   // Property change listener
    //   IPropertyChangeListener teamUIListener = new IPropertyChangeListener() {
    //      public void propertyChange(PropertyChangeEvent event) {
    //         if (event.getProperty().equals(TeamUI.GLOBAL_IGNORES_CHANGED)) {
    //            SVNLightweightDecorator.refresh();
    //         }
    //      }
    //   };

    private SVNMarkerListener markerListener;

    private ShowOutOfDateFoldersAction showOutOfDateFoldersAction;

    public static final boolean TEST_MODE;

    static {
        String application = System.getProperty("eclipse.application", "");
        if (application.length() > 0) {
            TEST_MODE = application.endsWith("testapplication") || application.endsWith("uitest");
        } else {
            String commands = System.getProperty("eclipse.commands", "");
            TEST_MODE = commands.contains("testapplication\n");
        }
    }

    public static void log(CoreException e) {
        log(e.getStatus().getSeverity(), Policy.bind("simpleInternal"), e); //$NON-NLS-1$
    }

    public static void log(int severity, String message, Throwable e) {
        log(new Status(severity, ID, 0, message, e));
    }

    public SVNUIPlugin() {
        super();
        plugin = this;

    }

    /**
     * Convenience method to get the currently active workbench page. Note that
     * the active page may not be the one that the usr perceives as active in
     * some situations so this method of obtaining the activae page should only
     * be used if no other method is available.
     * 
     * @return the active workbench page
     */
    public static IWorkbenchPage getActivePage() {
        IWorkbenchWindow window = getPlugin().getWorkbench().getActiveWorkbenchWindow();
        if (window == null)
            return null;
        return window.getActivePage();
    }

    /**
     * Creates a busy cursor and runs the specified runnable.
     * May be called from a non-UI thread.
     * 
     * @param parent the parent Shell for the dialog
     * @param cancelable if true, the dialog will support cancelation
     * @param runnable the runnable
     * 
     * @exception InvocationTargetException when an exception is thrown from the runnable
     * @exception InterruptedException when the progress monitor is cancelled
     */

    public static void runWithProgress(Shell parent, boolean cancelable, final IRunnableWithProgress runnable)
            throws InvocationTargetException, InterruptedException {

        boolean createdShell = false;
        try {
            if (parent == null || parent.isDisposed()) {
                Display display = Display.getCurrent();
                if (display == null) {
                    // cannot provide progress (not in UI thread)
                    runnable.run(new NullProgressMonitor());
                    return;
                }
                // get the active shell or a suitable top-level shell
                parent = display.getActiveShell();
                if (parent == null) {
                    parent = new Shell(display);
                    createdShell = true;
                }
            }
            // pop up progress dialog after a short delay
            final Exception[] holder = new Exception[1];
            BusyIndicator.showWhile(parent.getDisplay(), new Runnable() {
                public void run() {
                    try {
                        runnable.run(new NullProgressMonitor());
                    } catch (InvocationTargetException e) {
                        holder[0] = e;
                    } catch (InterruptedException e) {
                        holder[0] = e;
                    }
                }
            });
            if (holder[0] != null) {
                if (holder[0] instanceof InvocationTargetException) {
                    throw (InvocationTargetException) holder[0];
                } else {
                    throw (InterruptedException) holder[0];
                }
            }
            //new TimeoutProgressMonitorDialog(parent, TIMEOUT).run(true /*fork*/, cancelable, runnable);
        } finally {
            if (createdShell)
                parent.dispose();
        }
    }

    /**
     * Returns the singleton plug-in instance.
     * 
     * @return the plugin instance
     */
    public static SVNUIPlugin getPlugin() {
        return plugin;
    }

    /**
     * Returns the repository manager
     * 
     * @return the repository manager
     */
    public synchronized RepositoryManager getRepositoryManager() {
        if (repositoryManager == null) {
            repositoryManager = new RepositoryManager();
            repositoryManager.startup();
        }
        return repositoryManager;
    }

    /**
     * Convenience method for logging statuses to the plugin log
     * 
     * @param status  the status to log
     */
    public static void log(IStatus status) {
        getPlugin().getLog().log(status);
    }

    public static void log(String msg) {
        getPlugin().getLog().log(new Status(IStatus.INFO, SVNUIPlugin.ID, 0, msg, null));
    }

    public static void log(TeamException e) {
        getPlugin().getLog()
                .log(new Status(e.getStatus().getSeverity(), SVNUIPlugin.ID, 0, Policy.bind("simpleInternal"), e)); //$NON-NLS-1$
    }

    // flags to tailor error reporting
    public static final int PERFORM_SYNC_EXEC = 1;
    public static final int LOG_TEAM_EXCEPTIONS = 2;
    public static final int LOG_CORE_EXCEPTIONS = 4;
    public static final int LOG_OTHER_EXCEPTIONS = 8;
    public static final int LOG_NONTEAM_EXCEPTIONS = LOG_CORE_EXCEPTIONS | LOG_OTHER_EXCEPTIONS;
    private SVNOutputConsole console;
    private URL baseURL;

    /**
     * Convenience method for showing an error dialog 
     * @param shell a valid shell or null
     * @param exception the exception to be report
     * @param title the title to be displayed
     * @return IStatus the status that was displayed to the user
     */
    public static IStatus openError(Shell shell, String title, String message, Throwable exception) {
        return openError(shell, title, message, exception, LOG_OTHER_EXCEPTIONS);
    }

    /**
     * Convenience method for showing an error dialog 
     * @param shell a valid shell or null
     * @param exception the exception to be report
     * @param title the title to be displayed
     * @param flags customizing attributes for the error handling
     * @return IStatus the status that was displayed to the user
     */
    public static IStatus openError(Shell providedShell, String title, String message, Throwable exception,
            int flags) {
        // Unwrap InvocationTargetExceptions
        if (exception instanceof InvocationTargetException) {
            Throwable target = ((InvocationTargetException) exception).getTargetException();
            // re-throw any runtime exceptions or errors so they can be handled by the workbench
            if (target instanceof RuntimeException) {
                throw (RuntimeException) target;
            }
            if (target instanceof Error) {
                throw (Error) target;
            }
            return openError(providedShell, title, message, target, flags);
        }

        // Determine the status to be displayed (and possibly logged)
        IStatus status = null;
        boolean log = false;
        if (exception instanceof CoreException) {
            status = ((CoreException) exception).getStatus();
            log = ((flags & LOG_CORE_EXCEPTIONS) > 0);
        } else if (exception instanceof TeamException) {
            status = ((TeamException) exception).getStatus();
            log = ((flags & LOG_TEAM_EXCEPTIONS) > 0);
        } else if (exception instanceof InterruptedException) {
            return new SVNStatus(IStatus.OK, Policy.bind("ok")); //$NON-NLS-1$
        } else if (exception != null) {
            status = new SVNStatus(IStatus.ERROR, Policy.bind("internal"), exception); //$NON-NLS-1$
            log = ((flags & LOG_OTHER_EXCEPTIONS) > 0);
            if (title == null)
                title = Policy.bind("SimpleInternal"); //$NON-NLS-1$
        }

        // Check for a build error and report it differently
        if (status.getCode() == IResourceStatus.BUILD_FAILED) {
            message = Policy.bind("buildError"); //$NON-NLS-1$
            log = true;
        }

        // Check for multi-status with only one child
        if (status.isMultiStatus() && status.getChildren().length == 1) {
            status = status.getChildren()[0];
        }
        if (status.isOK())
            return status;

        // Log if the user requested it
        if (log)
            SVNUIPlugin.log(status);
        // Create a runnable that will display the error status

        String svnInterface = SVNUIPlugin.getPlugin().getPreferenceStore()
                .getString(ISVNUIConstants.PREF_SVNINTERFACE);
        boolean loadError = svnInterface.equals("javahl") && status != null && status.getMessage() != null
                && status.getMessage().equals(SVNClientManager.UNABLE_TO_LOAD_DEFAULT_CLIENT);

        if (!loadError || loadErrorHandled) {
            final String displayTitle = title;
            final String displayMessage = message;
            final IStatus displayStatus = status;
            final IOpenableInShell openable = new IOpenableInShell() {
                public void open(Shell shell) {
                    if (displayStatus.getSeverity() == IStatus.INFO && !displayStatus.isMultiStatus()) {
                        MessageDialog.openInformation(shell, Policy.bind("information"), //$NON-NLS-1$
                                displayStatus.getMessage());
                    } else {
                        ErrorDialog.openError(shell, displayTitle, displayMessage, displayStatus);
                    }
                }
            };
            openDialog(providedShell, openable, flags);
        }

        if (loadError)
            loadErrorHandled = true;

        // return the status we display
        return status;
    }

    /**
     * Interface that allows a shell to be passed to an open method. The
     * provided shell can be used without sync-execing, etc.
     */
    public interface IOpenableInShell {
        public void open(Shell shell);
    }

    /**
     * Open the dialog code provided in the IOpenableInShell, ensuring that 
     * the provided whll is valid. This method will provide a shell to the
     * IOpenableInShell if one is not provided to the method.
     * 
     * @param providedShell
     * @param openable
     * @param flags
     */
    public static void openDialog(Shell providedShell, final IOpenableInShell openable, int flags) {
        // If no shell was provided, try to get one from the active window
        if (providedShell == null) {
            IWorkbenchWindow window = SVNUIPlugin.getPlugin().getWorkbench().getActiveWorkbenchWindow();
            if (window != null) {
                providedShell = window.getShell();
                // sync-exec when we do this just in case
                flags = flags | PERFORM_SYNC_EXEC;
            }
        }

        // Create a runnable that will display the error status
        final Shell shell = providedShell;
        Runnable outerRunnable = new Runnable() {
            public void run() {
                Shell displayShell;
                if (shell == null) {
                    Display display = Display.getCurrent();
                    displayShell = new Shell(display);
                } else {
                    displayShell = shell;
                }
                openable.open(displayShell);
                if (shell == null) {
                    displayShell.dispose();
                }
            }
        };

        // Execute the above runnable as determined by the parameters
        if (shell == null || (flags & PERFORM_SYNC_EXEC) > 0) {
            Display display;
            if (shell == null) {
                display = Display.getCurrent();
                if (display == null) {
                    display = Display.getDefault();
                }
            } else {
                display = shell.getDisplay();
            }
            display.syncExec(outerRunnable);
        } else {
            outerRunnable.run();
        }
    }

    public void start(BundleContext ctxt) throws Exception {
        super.start(ctxt);

        mergeProviders = getMergeProviders();

        BaseResourceStorageFactory.setCurrent(new UIBaseResourceStorageFactory());

        SVNAdapterFactory factory = new SVNAdapterFactory();

        Platform.getAdapterManager().registerAdapters(factory, ISVNRemoteFile.class);
        Platform.getAdapterManager().registerAdapters(factory, ISVNRemoteFolder.class);
        Platform.getAdapterManager().registerAdapters(factory, ISVNRepositoryLocation.class);
        //      Platform.getAdapterManager().registerAdapters(factory, RepositoryRoot.class);

        baseURL = ctxt.getBundle().getEntry("/"); //$NON-NLS-1$

        preferences = new Preferences(getPreferenceStore());
        preferences.initializeFromSettings();

        markerListener = new SVNMarkerListener();
        SVNProviderPlugin.addResourceStateChangeListener(markerListener);

        //      // if the global ignores list is changed then update decorators.
        //TeamUI.getSynchronizeManager().addSynchronizeParticipants(new ISynchronizeParticipant[]{new SVNWorkspaceSynchronizeParticipant()});
        try {
            console = new SVNOutputConsole();
        } catch (RuntimeException e) {
            // Don't let the console bring down the SVN UI
            log(IStatus.ERROR, "Errors occurred starting the SVN console", e); //$NON-NLS-1$
        }
        SVNProviderPlugin.getPlugin().setSvnPromptUserPassword(new SVNPromptUserPassword());
        SVNProviderPlugin.getPlugin().setSimpleDialogsHelper(new SimpleDialogsHelper());
        SVNProviderPlugin.getPlugin()
                .setSvnFileModificationValidatorPrompt(new SVNFileModificationValidatorPrompt());

        showOutOfDateFoldersAction = new ShowOutOfDateFoldersAction();
    }

    /**
     * @see Plugin#shutdown()
     */
    public void stop(BundleContext ctxt) throws Exception {
        super.stop(ctxt);
        //      TeamUI.removePropertyChangeListener(listener);
        try {
            if (repositoryManager != null)
                repositoryManager.shutdown();
        } catch (TeamException e) {
            throw new CoreException(e.getStatus());
        }

        console.shutdown();
    }

    public void clearPasswordStoresFromConfiguration(boolean restart) throws Exception {
        Exception exception = null;
        File configFile = getConfigFile();
        if (configFile.exists()) {
            File temp = null;
            boolean written = false;
            String newLine = System.getProperty("line.separator");
            BufferedReader input = null;
            BufferedWriter output = null;
            try {
                temp = File.createTempFile("config", null, configFile.getParentFile());
                input = new BufferedReader(new FileReader(configFile));
                output = new BufferedWriter(new FileWriter(temp));
                String line = null;
                boolean authSectionFound = false;
                boolean passwordStoresFound = false;
                boolean inAuthSection = false;
                while ((line = input.readLine()) != null) {
                    if (line.startsWith("[auth]")) {
                        authSectionFound = true;
                        inAuthSection = true;
                    } else {
                        if (line.startsWith("[")) {
                            if (inAuthSection && !passwordStoresFound) {
                                output.write("password-stores =" + newLine);
                            }
                            inAuthSection = false;
                        }
                    }
                    if (line.startsWith("password-stores =")) {
                        passwordStoresFound = true;
                        if (!line.trim().endsWith("password-stores =")) {
                            line = "password-stores =";
                        }
                    }
                    if (line.startsWith("password-stores=")) {
                        passwordStoresFound = true;
                        if (!line.trim().endsWith("password-stores=")) {
                            line = "password-stores=";
                        }
                    }
                    output.write(line + newLine);
                }
                if (!authSectionFound) {
                    output.write("[auth]" + newLine + "password-stores =");
                } else {
                    if (inAuthSection && !passwordStoresFound) {
                        output.write("password-stores =" + newLine);
                    }
                }
                written = true;
            } catch (Exception e) {
                exception = e;
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (IOException e) {
                    }
                }
                if (output != null) {
                    try {
                        output.close();
                    } catch (IOException e) {
                    }
                }
            }
            if (exception != null) {
                throw exception;
            }
            if (written) {
                configFile.renameTo(new File(configFile.getParentFile(), "config_backup"));
                temp.renameTo(configFile);
                if (restart) {
                    PlatformUI.getWorkbench().restart();
                }
            } else {
                if (temp != null && temp.exists()) {
                    temp.deleteOnExit();
                }
            }
        }
    }

    public File getConfigFile() {
        File configDir;
        String configDirPath = getPreferenceStore().getString(ISVNUIConstants.PREF_SVNCONFIGDIR);
        if (configDirPath == null || configDirPath.trim().length() == 0) {
            File homeDirectory = new File(System.getProperty("user.home"));
            configDir = new File(homeDirectory, ".subversion");
        } else {
            configDir = new File(configDirPath);
        }
        File configFile = new File(configDir, "config");
        return configFile;
    }

    public String getPasswordStores() {
        String passwordStores = null;
        File configFile = getConfigFile();
        if (configFile.exists()) {
            BufferedReader input = null;
            try {
                input = new BufferedReader(new FileReader(configFile));
                String line = null;
                while ((line = input.readLine()) != null) {
                    if (line.startsWith("password-stores =") || line.startsWith("password-stores=")) {
                        if (!line.trim().endsWith("=")) {
                            int index = line.indexOf("=");
                            passwordStores = line.substring(index + 1);
                        }
                        break;
                    }
                }
            } catch (Exception e) {
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (IOException e) {
                    }
                }
            }
        }
        return passwordStores;
    }

    public boolean passwordStoresConfiguredOnLinux() {
        if (System.getProperty("os.name").toLowerCase().indexOf("linux") == -1) {
            return false;
        }
        String svnInterface = getPreferenceStore().getString(ISVNUIConstants.PREF_SVNINTERFACE);
        if (svnInterface != null && !svnInterface.equals("javahl")) {
            return false;
        }
        boolean passwordStoresFound = false;
        boolean valueIsGnomeKeyring = false;
        File configFile = getConfigFile();
        if (!configFile.exists()) {
            ISVNClientAdapter client = null;
            try {
                // This is ja hack to cause the config file to be created so that we
                // can offer to fix it.  We are using a non-existant path so that it will
                // just end quickly.
                client = SVNProviderPlugin.getPlugin().getSVNClientManager().getSVNClient();
                client.cleanup(new File("/This/is/just/a/dummy/file"));
            } catch (Exception e) {
            } finally {
                SVNProviderPlugin.getPlugin().getSVNClientManager().returnSVNClient(client);
            }
        }
        if (!configFile.exists())
            return false;
        BufferedReader input = null;
        try {
            input = new BufferedReader(new FileReader(configFile));
            String line = null;
            while ((line = input.readLine()) != null) {
                if (line.startsWith("password-stores =")) {
                    passwordStoresFound = true;
                    if (!line.trim().endsWith("password-stores =")) {
                        valueIsGnomeKeyring = line.indexOf("gnome-keyring") != -1;
                    }
                    break;
                }
                if (line.startsWith("password-stores=")) {
                    passwordStoresFound = true;
                    if (!line.trim().endsWith("password-stores=")) {
                        valueIsGnomeKeyring = line.indexOf("gnome-keyring") != -1;
                    }
                    break;
                }
            }
        } catch (Exception e) {
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                }
            }
        }
        return valueIsGnomeKeyring || !passwordStoresFound;
    }

    /** Returns all the commit dialog toolbar actions that were found from the extension point. */
    public static SVNPluginAction[] getCommitDialogToolBarActions() {
        if (commitDialogToolBarActions == null) {
            ArrayList actionsList = new ArrayList();
            IConfigurationElement[] elements = Platform.getExtensionRegistry()
                    .getConfigurationElementsFor(COMMIT_DIALOG_TOOLBAR_ACTIONS);
            for (int i = 0; i < elements.length; i++) {
                SVNPluginAction action = new SVNPluginAction(elements[i]);
                if (action.getDelegate() != null) {
                    actionsList.add(action);
                }
            }
            commitDialogToolBarActions = new SVNPluginAction[actionsList.size()];
            actionsList.toArray(commitDialogToolBarActions);
        }
        return commitDialogToolBarActions;
    }

    /** Returns the commit dialog compare actions found from the extension point. */
    public static SVNPluginAction[] getCommitDialogCompareActions() {
        if (commitDialogCompareActions == null) {
            ArrayList actionsList = new ArrayList();
            IConfigurationElement[] elements = Platform.getExtensionRegistry()
                    .getConfigurationElementsFor(COMMIT_DIALOG_COMPARE_ACTIONS);
            for (int i = 0; i < elements.length; i++) {
                SVNPluginAction action = new SVNPluginAction(elements[i]);
                if (action.getDelegate() != null) {
                    actionsList.add(action);
                }
            }
            commitDialogCompareActions = new SVNPluginAction[actionsList.size()];
            actionsList.toArray(commitDialogCompareActions);
        }
        return commitDialogCompareActions;
    }

    // Initialize the merge providers by searching the registry for users of the
    // mergeProviders extension point.
    public static WorkspaceAction[] getMergeProviders() throws Exception {
        if (mergeProviders == null) {
            ArrayList mergeProviderList = new ArrayList();
            IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
            IConfigurationElement[] configurationElements = extensionRegistry
                    .getConfigurationElementsFor(MERGE_PROVIDERS);
            for (int i = 0; i < configurationElements.length; i++) {
                IConfigurationElement configurationElement = configurationElements[i];
                WorkspaceAction mergeProvider = (WorkspaceAction) configurationElement
                        .createExecutableExtension("class"); //$NON-NLS-1$
                mergeProvider.setName(configurationElement.getAttribute("name")); //$NON-NLS-1$
                mergeProviderList.add(mergeProvider);
            }
            mergeProviders = new WorkspaceAction[mergeProviderList.size()];
            mergeProviderList.toArray(mergeProviders);
        }
        return mergeProviders;
    }

    // Initialize the repository source providers by searching the registry for users of the
    // svnRepositorySourceProviders extension point.
    public static ISVNRepositorySourceProvider[] getRepositorySourceProviders() throws Exception {
        if (repositorySourceProviders == null) {
            List<ISVNRepositorySourceProvider> repositorySourceProviderList = new ArrayList<ISVNRepositorySourceProvider>();
            IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
            IConfigurationElement[] configurationElements = extensionRegistry
                    .getConfigurationElementsFor(REPOSITORY_SOURCE_PROVIDERS);
            for (int i = 0; i < configurationElements.length; i++) {
                IConfigurationElement configurationElement = configurationElements[i];
                ISVNRepositorySourceProvider repositorySourceProvider = (ISVNRepositorySourceProvider) configurationElement
                        .createExecutableExtension("class"); //$NON-NLS-1$
                repositorySourceProvider.setId(configurationElement.getAttribute("id")); //$NON-NLS-1$
                repositorySourceProviderList.add(repositorySourceProvider);
            }
            repositorySourceProviders = new ISVNRepositorySourceProvider[repositorySourceProviderList.size()];
            repositorySourceProviderList.toArray(repositorySourceProviders);
            Arrays.sort(repositorySourceProviders, new Comparator<ISVNRepositorySourceProvider>() {
                public int compare(ISVNRepositorySourceProvider o1, ISVNRepositorySourceProvider o2) {
                    return o1.getName().compareTo(o2.getName());
                }
            });
        }
        return repositorySourceProviders;
    }

    public static WorkspaceAction getDefaultMergeProvider() {
        String mergeProvider = plugin.getPreferenceStore().getString(ISVNUIConstants.PREF_MERGE_PROVIDER);
        if (mergeProvider != null) {
            for (int i = 0; i < mergeProviders.length; i++) {
                if (mergeProviders[i].getName().equals(mergeProvider)) {
                    return mergeProviders[i];
                }
            }
        }
        return mergeProviders[0];
    }

    /**
     * Returns the standard display to be used. The method first checks, if
     * the thread calling this method has an associated display. If so, this
     * display is returned. Otherwise the method returns the default display.
     */
    public static Display getStandardDisplay() {
        Display display = Display.getCurrent();
        if (display == null) {
            display = Display.getDefault();
        }
        return display;
    }

    /**
     * Returns the image descriptor for the given image ID.
     * Returns null if there is no such image.
     */
    public ImageDescriptor getImageDescriptor(String id) {
        if (imageDescriptors == null) {
            imageDescriptors = new ImageDescriptors();
            imageDescriptors.initializeImages(baseURL,
                    getPreferenceStore().getInt(ISVNUIConstants.PREF_MENU_ICON_SET));
        }
        return imageDescriptors.getImageDescriptor(id);
    }

    /**
     * Temporarily detach the console from the message source
     */
    public void disableConsoleListener() {
        SVNProviderPlugin.getPlugin().setConsoleListener(null);
    }

    /**
     * Reconnect the console view to the message source
     */
    public void enableConsoleListener() {
        SVNProviderPlugin.getPlugin().setConsoleListener(console);
    }

    public static String getCharset(String name, InputStream stream) throws IOException {
        IContentDescription description = getContentDescription(name, stream);
        return description == null ? null : description.getCharset();

    }

    public static IContentDescription getContentDescription(String name, InputStream stream) throws IOException {
        // tries to obtain a description for this file contents
        IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
        try {
            return contentTypeManager.getDescriptionFor(stream, name, IContentDescription.ALL);
        } finally {
            if (stream != null)
                try {
                    stream.close();
                } catch (IOException e) {
                    // Ignore exceptions on close
                }
        }
    }

    /**
     * Gets the one and only SVN console managed by this plugin
     * @return the SVN console
     */
    public SVNOutputConsole getConsole() {
        return console;
    }

    public ShowOutOfDateFoldersAction getShowOutOfDateFoldersAction() {
        return showOutOfDateFoldersAction;
    }

    public org.osgi.service.prefs.Preferences getInstancePreferences() {
        return new InstanceScope().getNode(getBundle().getSymbolicName());
    }

    public MergeFileAssociation[] getMergeFileAssociations() throws BackingStoreException {
        ArrayList associations = new ArrayList();
        String[] childrenNames = MergeFileAssociation.getParentPreferences().childrenNames();
        for (int i = 0; i < childrenNames.length; i++) {
            org.osgi.service.prefs.Preferences node = MergeFileAssociation.getParentPreferences()
                    .node(childrenNames[i]);
            MergeFileAssociation association = new MergeFileAssociation();
            association.setFileType(childrenNames[i]);
            association.setMergeProgram(node.get("mergeProgram", "")); //,  //$NON-NLS-1$
            association.setParameters(node.get("parameters", "")); //,  //$NON-NLS-1$
            association.setType(node.getInt("type", MergeFileAssociation.BUILT_IN));
            associations.add(association);
        }
        MergeFileAssociation[] associationArray = new MergeFileAssociation[associations.size()];
        associations.toArray(associationArray);
        Arrays.sort(associationArray);
        return associationArray;
    }

    public MergeFileAssociation getMergeFileAssociation(String fileName) throws BackingStoreException {
        MergeFileAssociation[] mergeFileAssociations = getMergeFileAssociations();
        for (int i = 0; i < mergeFileAssociations.length; i++) {
            if (mergeFileAssociations[i].getFileType().equals(fileName))
                return mergeFileAssociations[i];
        }
        for (int i = 0; i < mergeFileAssociations.length; i++) {
            if (mergeFileAssociations[i].matches(fileName))
                return mergeFileAssociations[i];
        }
        MergeFileAssociation mergeFileAssociation = new MergeFileAssociation();
        IPreferenceStore preferenceStore = getPreferenceStore();
        if (preferenceStore.getBoolean(ISVNUIConstants.PREF_MERGE_USE_EXTERNAL))
            mergeFileAssociation.setType(MergeFileAssociation.DEFAULT_EXTERNAL);
        else
            mergeFileAssociation.setType(MergeFileAssociation.BUILT_IN);
        return mergeFileAssociation;
    }

    public static Image getImage(String key) {
        return getPlugin().getImageRegistry().get(key);
    }

    protected void initializeImageRegistry(ImageRegistry reg) {
        super.initializeImageRegistry(reg);
        reg.put(ISVNUIConstants.IMG_PROPERTIES, getImageDescriptor(ISVNUIConstants.IMG_PROPERTIES));
        reg.put(ISVNUIConstants.IMG_FILEADD_PENDING, getImageDescriptor(ISVNUIConstants.IMG_FILEADD_PENDING));
        reg.put(ISVNUIConstants.IMG_SYNCPANE, getImageDescriptor(ISVNUIConstants.IMG_SYNCPANE));
        reg.put(ISVNUIConstants.IMG_FILEDELETE_PENDING, getImageDescriptor(ISVNUIConstants.IMG_FILEDELETE_PENDING));
        reg.put(ISVNUIConstants.IMG_FILEMODIFIED_PENDING,
                getImageDescriptor(ISVNUIConstants.IMG_FILEMODIFIED_PENDING));
        reg.put(ISVNUIConstants.IMG_FOLDERADD_PENDING, getImageDescriptor(ISVNUIConstants.IMG_FOLDERADD_PENDING));
        reg.put(ISVNUIConstants.IMG_FOLDERDELETE_PENDING,
                getImageDescriptor(ISVNUIConstants.IMG_FOLDERDELETE_PENDING));
        reg.put(ISVNUIConstants.IMG_FOLDERMODIFIED_PENDING,
                getImageDescriptor(ISVNUIConstants.IMG_FOLDERMODIFIED_PENDING));
        reg.put(ISVNUIConstants.IMG_FOLDER, getImageDescriptor(ISVNUIConstants.IMG_FOLDER));
        reg.put(ISVNUIConstants.IMG_AFFECTED_PATHS_COMPRESSED_MODE,
                getImageDescriptor(ISVNUIConstants.IMG_AFFECTED_PATHS_COMPRESSED_MODE));
        reg.put(ISVNUIConstants.IMG_AFFECTED_PATHS_FLAT_MODE,
                getImageDescriptor(ISVNUIConstants.IMG_AFFECTED_PATHS_FLAT_MODE));
        reg.put(ISVNUIConstants.IMG_AFFECTED_PATHS_TREE_MODE,
                getImageDescriptor(ISVNUIConstants.IMG_AFFECTED_PATHS_TREE_MODE));
        reg.put(ISVNUIConstants.IMG_UPDATE_ALL, getImageDescriptor(ISVNUIConstants.IMG_UPDATE_ALL));
        reg.put(ISVNUIConstants.IMG_COMMIT_ALL, getImageDescriptor(ISVNUIConstants.IMG_COMMIT_ALL));
        reg.put(ISVNUIConstants.IMG_PROPERTY_CONFLICTED,
                getImageDescriptor(ISVNUIConstants.IMG_PROPERTY_CONFLICTED));
    }

    // Deletes all files and subdirectories under dir.
    // Returns true if all delete was successful.
    private boolean deleteFolder(File folder) {
        if (folder.isDirectory()) {
            String[] children = folder.list();
            for (int i = 0; i < children.length; i++) {
                if (!deleteFolder(new File(folder, children[i]))) {
                    return false;
                }
            }
        }

        // The folder should be empty so delete it
        return folder.delete();
    }

}