Java tutorial
/* * 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; } }