org.community.intellij.plugins.communitycase.checkout.CloneDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.community.intellij.plugins.communitycase.checkout.CloneDialog.java

Source

/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.community.intellij.plugins.communitycase.checkout;

import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.*;
import com.intellij.openapi.vfs.VirtualFile;
import org.community.intellij.plugins.communitycase.commands.Command;
import org.community.intellij.plugins.communitycase.commands.HandlerUtil;
import org.community.intellij.plugins.communitycase.commands.SimpleHandler;
import org.community.intellij.plugins.communitycase.i18n.Bundle;
import org.community.intellij.plugins.communitycase.validators.BranchNameValidator;
import org.jetbrains.annotations.NonNls;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.regex.Pattern;

/**
 * A dialog for the git clone options
 *
 * @author Constantine.Plotnikov
 */
public class CloneDialog extends DialogWrapper {
    /**
     * The pattern for SSH URL-s in form [user@]host:path
     */
    private static final Pattern SSH_URL_PATTERN;

    static {
        // TODO make real URL pattern
        @NonNls
        final String ch = "[\\p{ASCII}&&[\\p{Graph}]&&[^@:/]]";
        @NonNls
        final String host = ch + "+(?:\\." + ch + "+)*";
        @NonNls
        final String path = "/?" + ch + "+(?:/" + ch + "+)*/?";
        @NonNls
        final String all = "(?:" + ch + "+@)?" + host + ":" + path;
        SSH_URL_PATTERN = Pattern.compile(all);
    }

    private JPanel myRootPanel;
    private JTextField myRepositoryURL;
    private TextFieldWithBrowseButton myParentDirectory;
    private JButton myTestButton; // test repository
    private JTextField myDirectoryName;

    private JTextField myOriginName; // origin name for cloned repository (-o option)
    private String myTestURL; // the repository URL at the time of the last test
    private Boolean myTestResult; // the test result of the last test or null if not tested
    private String myDefaultDirectoryName = "";
    private final Project myProject;

    public CloneDialog(Project project) {
        super(project, true);
        myProject = project;
        init();
        initListeners();
        setTitle(Bundle.getString("clone.title"));
        setOKButtonText(Bundle.getString("clone.button"));
    }

    public String getSourceRepositoryURL() {
        return myRepositoryURL.getText();
    }

    public String getParentDirectory() {
        return myParentDirectory.getText();
    }

    public String getDirectoryName() {
        return myDirectoryName.getText();
    }

    public String getOriginName() {
        return myOriginName.getText();
    }

    /**
     * Init components
     */
    private void initListeners() {
        FileChooserDescriptor fcd = new FileChooserDescriptor(false, true, false, false, false, false);
        fcd.setShowFileSystemRoots(true);
        fcd.setTitle(Bundle.getString("clone.destination.directory.title"));
        fcd.setDescription(Bundle.getString("clone.destination.directory.description"));
        fcd.setHideIgnored(false);
        myParentDirectory.addActionListener(new ComponentWithBrowseButton.BrowseFolderActionListener<JTextField>(
                fcd.getTitle(), fcd.getDescription(), myParentDirectory, myProject, fcd,
                TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) {
            @Override
            protected VirtualFile getInitialFile() {
                // suggest project base directory only if nothing is typed in the component.
                String text = getComponentText();
                if (text.length() == 0) {
                    VirtualFile file = myProject.getBaseDir();
                    if (file != null) {
                        return file;
                    }
                }
                return super.getInitialFile();
            }
        });
        final DocumentListener updateOkButtonListener = new DocumentListener() {
            // update Ok button state depending on the current state of the fields
            public void insertUpdate(final DocumentEvent e) {
                updateOkButton();
            }

            public void removeUpdate(final DocumentEvent e) {
                updateOkButton();
            }

            public void changedUpdate(final DocumentEvent e) {
                updateOkButton();
            }
        };
        myParentDirectory.getChildComponent().getDocument().addDocumentListener(updateOkButtonListener);
        myDirectoryName.getDocument().addDocumentListener(updateOkButtonListener);
        myOriginName.getDocument().addDocumentListener(updateOkButtonListener);
        myRepositoryURL.getDocument().addDocumentListener(new DocumentListener() {
            // enable test button only if something is entered in repository URL
            public void insertUpdate(final DocumentEvent e) {
                changed();
            }

            public void removeUpdate(final DocumentEvent e) {
                changed();
            }

            public void changedUpdate(final DocumentEvent e) {
                changed();
            }

            private void changed() {
                final String url = myRepositoryURL.getText();
                myTestButton.setEnabled(url.length() != 0);
                if (myDefaultDirectoryName.equals(myDirectoryName.getText())
                        || myDirectoryName.getText().length() == 0) {
                    // modify field if it was unmodified or blank
                    myDefaultDirectoryName = defaultDirectoryName(url);
                    myDirectoryName.setText(myDefaultDirectoryName);
                }
                updateOkButton();
            }
        });
        myTestButton.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                myTestURL = myRepositoryURL.getText();
                String output = HandlerUtil.doSynchronously(checkRepository(myProject, myTestURL),
                        Bundle.message("clone.testing", myTestURL), "connection test");
                if (output != null) {
                    Messages.showInfoMessage(myTestButton, Bundle.message("clone.test.success.message", myTestURL),
                            Bundle.getString("clone.test.success"));
                    myTestResult = Boolean.TRUE;
                } else {
                    myTestResult = Boolean.FALSE;
                }
                updateOkButton();
            }
        });
        setOKActionEnabled(false);
    }

    /**
     * Check fields and display error in the wrapper if there is a problem
     */
    private void updateOkButton() {
        if (!checkRepositoryURL()) {
            return;
        }
        if (!checkDestination()) {
            return;
        }
        if (!checkOrigin()) {
            return;
        }
        setErrorText(null);
        setOKActionEnabled(true);
    }

    /**
     * Check origin and set appropriate error text if there are problems
     *
     * @return true if origin name is OK.
     */
    private boolean checkOrigin() {
        String origin = myOriginName.getText();
        if (origin.length() != 0 && !BranchNameValidator.INSTANCE.checkInput(origin)) {
            setErrorText(Bundle.getString("clone.invalid.origin"));
            setOKActionEnabled(false);
            return false;
        }
        return true;
    }

    /**
     * Check destination directory and set appropriate error text if there are problems
     *
     * @return true if destination components are OK.
     */
    private boolean checkDestination() {
        if (myParentDirectory.getText().length() == 0 || myDirectoryName.getText().length() == 0) {
            setErrorText(null);
            setOKActionEnabled(false);
            return false;
        }
        File file = new File(myParentDirectory.getText(), myDirectoryName.getText());
        if (file.exists()) {
            setErrorText(Bundle.message("clone.destination.exists.error", file));
            setOKActionEnabled(false);
            return false;
        } else if (!file.getParentFile().exists()) {
            setErrorText(Bundle.message("clone.parent.missing.error", file.getParent()));
            setOKActionEnabled(false);
            return false;
        }
        return true;
    }

    /**
     * Check repository URL and set appropriate error text if there are problems
     *
     * @return true if repository URL is OK.
     */
    private boolean checkRepositoryURL() {
        String repository = myRepositoryURL.getText();
        if (repository.length() == 0) {
            setErrorText(null);
            setOKActionEnabled(false);
            return false;
        }
        if (myTestResult != null && repository.equals(myTestURL)) {
            if (!myTestResult.booleanValue()) {
                setErrorText(Bundle.getString("clone.test.failed.error"));
                setOKActionEnabled(false);
                return false;
            } else {
                return true;
            }
        }
        try {
            if (new URI(repository).isAbsolute()) {
                return true;
            }
        } catch (URISyntaxException urlExp) {
            // do nothing
        }
        // check if ssh url pattern
        if (SSH_URL_PATTERN.matcher(repository).matches()) {
            return true;
        }
        try {
            File file = new File(repository);
            if (file.exists()) {
                if (!file.isDirectory()) {
                    setErrorText(Bundle.getString("clone.url.is.not.directory.error"));
                    setOKActionEnabled(false);
                }
                return true;
            }
        } catch (Exception fileExp) {
            // do nothing
        }
        setErrorText(Bundle.getString("clone.invalid.url"));
        setOKActionEnabled(false);
        return false;
    }

    /**
     * Get default name for checked out directory
     *
     * @param url an URL to checkout
     * @return a default repository name
     */
    private static String defaultDirectoryName(final String url) {
        String nonSystemName;
        //noinspection HardCodedStringLiteral
        if (url.endsWith("/.git") || url.endsWith(File.separator + ".git")) {
            nonSystemName = url.substring(0, url.length() - 5);
        } else {
            //noinspection HardCodedStringLiteral
            if (url.endsWith(".git")) {
                nonSystemName = url.substring(0, url.length() - 4);
            } else {
                nonSystemName = url;
            }
        }
        int i = nonSystemName.lastIndexOf('/');
        if (i == -1 && File.separatorChar != '/') {
            i = nonSystemName.lastIndexOf(File.separatorChar);
        }
        return i >= 0 ? nonSystemName.substring(i + 1) : "";
    }

    /**
     * {@inheritDoc}
     */
    protected JComponent createCenterPanel() {
        return myRootPanel;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected String getDimensionServiceKey() {
        return "CloneDialog";
    }

    @Override
    public JComponent getPreferredFocusedComponent() {
        return myRepositoryURL;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected String getHelpId() {
        return "reference.VersionControl.Git.CloneRepository";
    }

    /**
     * Prepare check repository handler. To do this ls-remote command is executed and attempts to match
     * master tag. This will likely return only single entry or none, if there is no master
     * branch. Stdout output is ignored. Stderr is used to construct exception message and shown
     * in error message box if exit is negative.
     *
     * @param project the project
     * @param url     the url to check
     * @return a simple handler that does the task
     */
    private static SimpleHandler checkRepository(Project project, final String url) {
        SimpleHandler handler = new SimpleHandler(project, new File("."), Command.LS_REMOTE);
        handler.addParameters(url, "master");
        return handler;
    }
}