com.microsoft.tfs.client.eclipse.ui.egit.importwizard.CrossCollectionRepositorySelectControl.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.client.eclipse.ui.egit.importwizard.CrossCollectionRepositorySelectControl.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the repository root.

package com.microsoft.tfs.client.eclipse.ui.egit.importwizard;

import java.io.File;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jgit.util.FS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import com.microsoft.tfs.client.common.ui.controls.generic.BaseControl;
import com.microsoft.tfs.client.common.ui.framework.helper.SWTUtil;
import com.microsoft.tfs.client.common.ui.framework.helper.UIHelpers;
import com.microsoft.tfs.client.common.ui.framework.layout.GridDataBuilder;
import com.microsoft.tfs.client.eclipse.ui.egit.Messages;
import com.microsoft.tfs.client.eclipse.ui.egit.importwizard.CrossCollectionRepositoryTable.CrossCollectionRepositoryInfo;
import com.microsoft.tfs.core.clients.versioncontrol.SourceControlCapabilityFlags;
import com.microsoft.tfs.core.clients.versioncontrol.path.LocalPath;
import com.microsoft.tfs.core.config.EnvironmentVariables;
import com.microsoft.tfs.jni.PlatformMiscUtils;
import com.microsoft.tfs.util.Check;
import com.microsoft.tfs.util.StringUtil;
import com.microsoft.tfs.util.listeners.SingleListenerFacade;

public class CrossCollectionRepositorySelectControl extends BaseControl {
    private static final Log log = LogFactory.getLog(CrossCollectionRepositorySelectControl.class);

    public static final String REPO_TABLE_ID = "CrossCollectionRepositorySelectControl.repoTable"; //$NON-NLS-1$

    private static final String DEFAULT_REPOSITORY_DIR_UI_KEY = "default_repository_dir"; //$NON-NLS-1$
    private static final String DEFAULT_REPOSITORY_DIR_CORE_KEY = "core_defaultRepositoryDir"; //$NON-NLS-1$

    private final Text filterBox;
    private final Timer filterTimer;
    private FilterTask filterTask;

    private final CrossCollectionRepositoryTable table;
    private final Text parentDirectoryBox;
    private final Button browseButton;
    private final Text folderNameBox;
    private boolean ignoreChanges = false;

    private final SingleListenerFacade listeners = new SingleListenerFacade(
            RepositorySelectionChangedListener.class);

    public CrossCollectionRepositorySelectControl(final Composite parent, final int style,
            final SourceControlCapabilityFlags sourceControlCapabilityFlags) {
        super(parent, style);

        final GridLayout layout = new GridLayout();
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        layout.horizontalSpacing = getHorizontalSpacing();
        layout.verticalSpacing = 0;
        setLayout(layout);

        // Create timer for filtering the list
        filterTimer = new Timer(false);

        // Create the filter text box
        filterBox = new Text(this, SWT.BORDER);
        filterBox.setMessage(Messages.getString("CrossCollectionRepositorySelectControl.FilterHintText")); //$NON-NLS-1$
        filterBox.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(final ModifyEvent e) {
                startTimer();
            }
        });
        GridDataBuilder.newInstance().hGrab().hFill().applyTo(filterBox);

        table = new CrossCollectionRepositoryTable(this, SWT.NONE);
        table.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(final SelectionChangedEvent event) {
                onSelectionChanged(true);
            }
        });
        GridDataBuilder.newInstance().grab().hHint(getVerticalSpacing() * 30).vIndent(getVerticalSpacing()).fill()
                .applyTo(table);

        final Label parentDirectoryLabel = SWTUtil.createLabel(this,
                Messages.getString("CrossCollectionRepositorySelectControl.ParentDirectoryLabelText")); //$NON-NLS-1$
        GridDataBuilder.newInstance().hGrab().vIndent(getVerticalSpacing()).hFill().applyTo(parentDirectoryLabel);

        final Composite container = new Composite(this, SWT.NONE);
        final GridLayout layout2 = SWTUtil.gridLayout(container, 2, false, 0, 0);
        layout2.marginWidth = 0;
        layout2.marginHeight = 0;
        layout2.horizontalSpacing = getHorizontalSpacing();
        layout2.verticalSpacing = getVerticalSpacing();
        container.setLayout(layout2);

        parentDirectoryBox = new Text(container, SWT.BORDER);
        parentDirectoryBox.setText(getDefaultGitRootFolder());
        GridDataBuilder.newInstance().hGrab().hFill().applyTo(parentDirectoryBox);
        parentDirectoryBox.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(final ModifyEvent e) {
                onSelectionChanged(false);
            }
        });

        browseButton = SWTUtil.createButton(container,
                Messages.getString("CrossCollectionRepositorySelectControl.BrowseButtonText")); //$NON-NLS-1$
        browseButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
                parentDirectoryBox.setText(browse(parentDirectoryBox.getText()));
            }
        });
        GridDataBuilder.newInstance().hGrab().hFill().applyTo(container);

        final Label folderNameLabel = SWTUtil.createLabel(this,
                Messages.getString("CrossCollectionRepositorySelectControl.RepositoryFolderLabelText")); //$NON-NLS-1$
        GridDataBuilder.newInstance().hGrab().vIndent(getVerticalSpacing()).hFill().applyTo(folderNameLabel);

        folderNameBox = new Text(this, SWT.BORDER);
        GridDataBuilder.newInstance().hGrab().hFill().applyTo(folderNameBox);
        folderNameBox.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(final ModifyEvent e) {
                onSelectionChanged(false);
            }
        });
    }

    private void onSelectionChanged(final boolean updateFolderName) {
        if (ignoreChanges) {
            return;
        }

        ignoreChanges = true;
        try {
            final CrossCollectionRepositoryInfo repo = table.getSelectedRepository();
            if (updateFolderName) {
                String newFolderName = ""; //$NON-NLS-1$
                if (repo != null) {
                    newFolderName = repo.getRepositoryName();
                }
                folderNameBox.setText(newFolderName);
            }

            // Fire event to let listeners know that something changed
            ((RepositorySelectionChangedListener) listeners.getListener())
                    .onRepositorySelectionChanged(new RepositorySelectionChangedEvent(repo));
        } finally {
            ignoreChanges = false;
        }
    }

    private void startTimer() {
        // Cancel any existing task
        if (filterTask != null) {
            filterTask.cancel();
        }
        // Create a new task
        filterTask = new FilterTask();
        // Schedule the task
        filterTimer.schedule(filterTask, 400);
    }

    // Call this when the owning control is going away
    public void stopTimer() {
        // Cancel any existing task
        if (filterTask != null) {
            filterTask.cancel();
        }
    }

    private class FilterTask extends TimerTask {
        @Override
        public void run() {
            UIHelpers.runOnUIThread(true, new Runnable() {
                @Override
                public void run() {
                    table.applyFilter(filterBox.getText());
                }
            });
        }
    }

    private String getDefaultGitRootFolder() {
        final String rootFolderPreference = getDefaultRootFolderPreference();
        Check.notNull(rootFolderPreference, "Default root folder preference"); //$NON-NLS-1$

        // The preference could contain variables. Let's expand all of them.
        final String rootDirectory = expandVariables(rootFolderPreference);
        if (!StringUtil.isNullOrEmpty(rootDirectory)) {
            return rootDirectory;
        }

        // We've got an empty path after variables substitution. Let's use the
        // current Eclipse workspace root.
        final IPath eclipseWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot().getRawLocation();

        // Convert path separators according to the hosting OS rules.
        return eclipseWorkspaceRoot.toOSString();

    }

    private String getDefaultRootFolderPreference() {
        String rootFolderPreference = null;

        // EGit 4.0 and earlier hosted default repository root directory
        // preference in the UI plugin.
        final IPreferenceStore uiPrefs = org.eclipse.egit.ui.Activator.getDefault().getPreferenceStore();
        if (uiPrefs != null) {
            rootFolderPreference = uiPrefs.getString(DEFAULT_REPOSITORY_DIR_UI_KEY);
            if (!StringUtil.isNullOrEmpty(rootFolderPreference)) {
                return rootFolderPreference;
            }
        }

        // Since EGit 4.1 default repository root directory preference is hosted
        // in the Core plugin.
        final IEclipsePreferences corePrefs = org.eclipse.egit.core.Activator.getDefault().getRepositoryUtil()
                .getPreferences();
        if (corePrefs != null) {
            rootFolderPreference = corePrefs.get(DEFAULT_REPOSITORY_DIR_CORE_KEY, null);
            if (!StringUtil.isNullOrEmpty(rootFolderPreference)) {
                return rootFolderPreference;
            }
        }

        // If the preference is not set, then use the home environment variable
        rootFolderPreference = PlatformMiscUtils.getInstance().getEnvironmentVariable(EnvironmentVariables.HOME);
        if (!StringUtil.isNullOrEmpty(rootFolderPreference)) {
            return rootFolderPreference;
        }

        // If the home environment variable is not set, then use the user home
        // directory. (The same logic as in eGit.)
        rootFolderPreference = LocalPath.combine(FS.DETECTED.userHome().getPath(), "git"); //$NON-NLS-1$

        return rootFolderPreference;
    }

    private String expandVariables(final String source) {
        final IStringVariableManager variableManager = VariablesPlugin.getDefault().getStringVariableManager();

        try {
            return variableManager.performStringSubstitution(source);
        } catch (final CoreException e) {
            log.error("The source string '" + source + "' contains undefined variables", e); //$NON-NLS-1$ //$NON-NLS-2$
        }

        return null;
    }

    private String browse(final String currentDirectory) {
        final DirectoryDialog dlg = new DirectoryDialog(this.getShell());
        dlg.setFilterPath(currentDirectory);
        dlg.setText(Messages.getString("CrossCollectionRepositorySelectControl.BrowseDialogTitle")); //$NON-NLS-1$
        dlg.setMessage(Messages.getString("CrossCollectionRepositorySelectControl.BrowseDialogMessage")); //$NON-NLS-1$
        final String newDirectory = dlg.open();
        return newDirectory != null ? newDirectory : currentDirectory;
    }

    public CrossCollectionRepositoryInfo getSelectedRepository() {
        return table.getSelectedRepository();
    }

    public void setSelectedRepository(final CrossCollectionRepositoryInfo repository) {
        table.setSelectedElement(repository);
        table.getTable().showSelection();
    }

    public String getWorkingDirectory() {
        final String parentDirectory = parentDirectoryBox.getText();
        final String folderName = folderNameBox.getText();
        if (!StringUtil.isNullOrEmpty(parentDirectory) && !StringUtil.isNullOrEmpty(folderName)) {
            final File parent = new File(parentDirectory.trim());
            final File workingDirectory = new File(parent, folderName.trim());
            return workingDirectory.getPath();
        }
        return null;
    }

    public void addListener(final RepositorySelectionChangedListener listener) {
        listeners.addListener(listener);
    }

    public void removeListener(final RepositorySelectionChangedListener listener) {
        listeners.removeListener(listener);
    }

    public void refresh(final List<CrossCollectionRepositoryInfo> repos) {
        if (repos == null) {
            table.setRepositories(null);
            return;
        }
        table.setRepositories(repos.toArray(new CrossCollectionRepositoryInfo[repos.size()]));
    }

    public interface RepositorySelectionChangedListener {
        public void onRepositorySelectionChanged(RepositorySelectionChangedEvent event);
    }

    public final class RepositorySelectionChangedEvent {
        private final CrossCollectionRepositoryInfo selectedRepository;

        private RepositorySelectionChangedEvent(final CrossCollectionRepositoryInfo selectedRepository) {
            this.selectedRepository = selectedRepository;
        }

        public CrossCollectionRepositoryInfo getSelectedRepository() {
            return selectedRepository;
        }
    }
}