com.microsoft.alm.plugin.idea.ui.checkout.CheckoutPageModelImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.alm.plugin.idea.ui.checkout.CheckoutPageModelImpl.java

Source

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

package com.microsoft.alm.plugin.idea.ui.checkout;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.microsoft.alm.plugin.authentication.AuthenticationInfo;
import com.microsoft.alm.plugin.context.ServerContext;
import com.microsoft.alm.plugin.idea.resources.TfPluginBundle;
import com.microsoft.alm.plugin.idea.ui.common.LoginPageModelImpl;
import com.microsoft.alm.plugin.idea.ui.common.ModelValidationInfo;
import com.microsoft.alm.plugin.idea.ui.common.ServerContextLookupListener;
import com.microsoft.alm.plugin.idea.ui.common.ServerContextLookupPageModel;
import com.microsoft.alm.plugin.idea.ui.common.ServerContextTableModel;
import com.microsoft.alm.plugin.services.PluginServiceProvider;
import com.microsoft.alm.plugin.services.PropertyService;
import com.microsoft.alm.plugin.telemetry.TfsTelemetryHelper;
import git4idea.commands.Git;
import org.apache.commons.lang.StringUtils;

import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.io.File;
import java.util.Collections;
import java.util.List;

/**
 * This class is provided as a base for the VSO and TFS models. It provides the majority of the
 * functionality with a few abstract methods that must be overridden.
 */
public abstract class CheckoutPageModelImpl extends LoginPageModelImpl
        implements CheckoutPageModel, ServerContextLookupPageModel {
    private CheckoutModel parentModel;
    private boolean loading = false;
    private boolean cloneEnabled = false;
    //default values for Strings should be "" rather than null.
    private String parentDirectory = "";
    private String directoryName = "";
    private String repositoryFilter = "";
    private final ServerContextTableModel repositoryTableModel;
    private final ServerContextLookupListener repositoryProvider;

    public CheckoutPageModelImpl(final CheckoutModel checkoutModel,
            final ServerContextTableModel.Column[] columns) {
        super(checkoutModel);
        parentModel = checkoutModel;

        // Create table model (subclasses should modify the table model as needed)
        repositoryTableModel = new ServerContextTableModel(columns);

        // Attach listeners
        setupSelectionListener();

        // Default the parent directory
        parentDirectory = PluginServiceProvider.getInstance().getPropertyService()
                .getProperty(PropertyService.PROP_REPO_ROOT);
        if (StringUtils.isEmpty(parentDirectory)) {
            parentDirectory = DEFAULT_SOURCE_PATH;
        }

        // Create the default repository provider
        repositoryProvider = new ServerContextLookupListener(this);
    }

    /**
     * This getter allows the derived classes to access the CheckoutModel that owns them.
     */
    protected CheckoutModel getParentModel() {
        return parentModel;
    }

    /**
     * This setter allows the tests to set the parent model.
     */
    protected void setParentModel(CheckoutModel parentModel) {
        this.parentModel = parentModel;
    }

    protected ServerContextLookupListener getRepositoryProvider() {
        return this.repositoryProvider;
    }

    /**
     * Subclasses must override this to return the authentication info object.
     * Return null if authentication is not complete.
     */
    protected abstract AuthenticationInfo getAuthenticationInfo();

    /**
     * Overriding SignOut to do a couple additional things.
     */
    @Override
    public void signOut() {
        super.signOut();
        setConnected(false);
        setLoading(false);
        clearContexts();
    }

    @Override
    public String getParentDirectory() {
        return parentDirectory;
    }

    @Override
    public void setParentDirectory(final String parentDirectory) {
        if (!StringUtils.equals(this.parentDirectory, parentDirectory)) {
            this.parentDirectory = parentDirectory;
            setChangedAndNotify(PROP_PARENT_DIR);
        }
    }

    @Override
    public String getDirectoryName() {
        return directoryName;
    }

    @Override
    public void setDirectoryName(final String directoryName) {
        if (!StringUtils.equals(this.directoryName, directoryName)) {
            this.directoryName = directoryName;
            setChangedAndNotify(PROP_DIRECTORY_NAME);
        }
    }

    @Override
    public String getRepositoryFilter() {
        return repositoryFilter;
    }

    @Override
    public void setRepositoryFilter(final String repositoryFilter) {
        if (!StringUtils.equals(this.repositoryFilter, repositoryFilter)) {
            this.repositoryFilter = repositoryFilter;
            setChangedAndNotify(PROP_REPO_FILTER);
            repositoryTableModel.setFilter(repositoryFilter);
        }
    }

    @Override
    public boolean isLoading() {
        return loading;
    }

    @Override
    public void setLoading(final boolean loading) {
        if (this.loading != loading) {
            this.loading = loading;
            setChangedAndNotify(PROP_LOADING);
        }
    }

    @Override
    public void setCloneEnabled(final boolean cloneEnabled) {
        if (this.cloneEnabled != cloneEnabled) {
            this.cloneEnabled = cloneEnabled;
            if (getParentModel() != null) {
                getParentModel().updateCloneEnabled();
            }
        }
    }

    @Override
    public void setConnected(boolean connected) {
        super.setConnected(connected);
        setCloneEnabled(connected);
    }

    @Override
    public ServerContextTableModel getTableModel() {
        return repositoryTableModel;
    }

    @Override
    public ListSelectionModel getTableSelectionModel() {
        return repositoryTableModel.getSelectionModel();
    }

    @Override
    public ModelValidationInfo validate() {
        ModelValidationInfo result = super.validate();

        if (result == ModelValidationInfo.NO_ERRORS) {
            final String parentDirectory = getParentDirectory();
            if (parentDirectory == null || parentDirectory.isEmpty()) {
                return ModelValidationInfo.createWithResource(PROP_PARENT_DIR,
                        TfPluginBundle.KEY_CHECKOUT_DIALOG_ERRORS_PARENT_DIR_EMPTY);
            }

            final File parentDirectoryOnDisk = new File(parentDirectory);
            if (!parentDirectoryOnDisk.exists()) {
                return ModelValidationInfo.createWithResource(PROP_PARENT_DIR,
                        TfPluginBundle.KEY_CHECKOUT_DIALOG_ERRORS_PARENT_DIR_NOT_FOUND);
            }

            // We test this method and so we need to check to see if we are in IntelliJ before using VirtualFileManager
            // ApplicationManager is null if we are not in IntelliJ
            if (ApplicationManager.getApplication() != null) {
                final VirtualFile destinationParent = LocalFileSystem.getInstance().findFileByPath(parentDirectory);
                if (destinationParent == null) {
                    return ModelValidationInfo.createWithResource(PROP_PARENT_DIR,
                            TfPluginBundle.KEY_CHECKOUT_DIALOG_ERRORS_PARENT_DIR_NOT_FOUND);
                }
            }

            if (getSelectedContext() == null) {
                return ModelValidationInfo.createWithResource(PROP_REPO_TABLE,
                        TfPluginBundle.KEY_CHECKOUT_DIALOG_ERRORS_REPO_NOT_SELECTED);
            }

            final String directoryName = getDirectoryName();
            if (directoryName == null || directoryName.isEmpty()) {
                return ModelValidationInfo.createWithResource(PROP_DIRECTORY_NAME,
                        TfPluginBundle.KEY_CHECKOUT_DIALOG_ERRORS_DIR_NAME_EMPTY);
            }

            final File destDirectoryOnDisk = new File(parentDirectory, directoryName);
            //verify the destination directory does not exist
            if (destDirectoryOnDisk.exists() && destDirectoryOnDisk.isDirectory()) {
                return ModelValidationInfo.createWithResource(PROP_DIRECTORY_NAME,
                        TfPluginBundle.KEY_CHECKOUT_DIALOG_ERRORS_DESTINATION_EXISTS, directoryName);
            }
            //verify destination directory parent exists, we can reach this condition if user specifies a path for directory name
            if (destDirectoryOnDisk.getParentFile() == null || !destDirectoryOnDisk.getParentFile().exists()) {
                return ModelValidationInfo.createWithResource(PROP_DIRECTORY_NAME,
                        TfPluginBundle.KEY_CHECKOUT_DIALOG_ERRORS_DIR_NAME_INVALID, directoryName,
                        destDirectoryOnDisk.getParent());
            }

        } else {
            return result;
        }

        return ModelValidationInfo.NO_ERRORS;
    }

    @Override
    public abstract void loadRepositories();

    @Override
    public void cloneSelectedRepo() {
        final ModelValidationInfo validationInfo = validate();
        if (validationInfo == null) {
            final ServerContext context = getSelectedContext();
            final String gitRepositoryStr = context.getUsableGitUrl();

            // The base LoginPageModel manages the context for us
            super.completeSignIn(context);

            final VirtualFile destinationParent = LocalFileSystem.getInstance()
                    .findFileByIoFile(new File(getParentDirectory()));

            final Git git = ServiceManager.getService(Git.class);
            git4idea.checkout.GitCheckoutProvider.clone(getParentModel().getProject(), git,
                    getParentModel().getListener(), destinationParent, gitRepositoryStr, getDirectoryName(),
                    getParentDirectory());

            // Save parent directory for next time
            PluginServiceProvider.getInstance().getPropertyService().setProperty(PropertyService.PROP_REPO_ROOT,
                    getParentDirectory());

            // TODO: need a way to tell if/when the clone actually succeeded or failed
            // Add Telemetry for a successful clone
            final String action = "clone";
            TfsTelemetryHelper.getInstance().sendEvent(action, new TfsTelemetryHelper.PropertyMapBuilder()
                    .currentOrActiveContext(context).actionName(action).success(true).build());
        }
    }

    /**
     * This method is provided to allow the derived classes an easy way to get the selected repository instance.
     */
    protected ServerContext getSelectedContext() {
        return repositoryTableModel.getSelectedContext();
    }

    /**
     * This method is provided to allow the listener to update the list of contexts.
     */
    @Override
    public void clearContexts() {
        repositoryTableModel.clearRows();
    }

    /**
     * This method is provided to allow the listener to update the list of contexts.
     */
    public void appendContexts(final List<ServerContext> serverContexts) {
        repositoryTableModel.addServerContexts(serverContexts);
    }

    /**
     * This method is provided to allow the derived classes an easy way to add to the list of repositories.
     */
    protected void addContext(ServerContext serverContext) {
        appendContexts(Collections.singletonList(serverContext));
    }

    private void setupSelectionListener() {
        // Set up event listener to set the Directory name when the selection changes
        repositoryTableModel.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                // No need to change things while the list is adjusting
                if (!e.getValueIsAdjusting()) {
                    final ServerContext row = repositoryTableModel.getSelectedContext();
                    // Get the repository name and set the directory name to match
                    final String repositoryName = (row != null && row.getGitRepository() != null)
                            ? row.getGitRepository().getName()
                            : "";
                    setDirectoryName(repositoryName);
                }
            }
        });
    }

    @Override
    public void dispose() {
        repositoryProvider.terminateActiveOperation();
    }
}