diff options
Diffstat (limited to 'platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java')
-rw-r--r-- | platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java b/platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java new file mode 100644 index 000000000000..8e06c99775e2 --- /dev/null +++ b/platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java @@ -0,0 +1,332 @@ +/* + * Copyright 2000-2013 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 com.intellij.dvcs.ui; + +import com.intellij.dvcs.DvcsRememberedInputs; +import com.intellij.ide.impl.ProjectUtil; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.*; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.EditorComboBox; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +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; + +/** + * @author Nadya Zabrodina + */ +public abstract class CloneDvcsDialog 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 EditorComboBox myRepositoryURL; + private TextFieldWithBrowseButton myParentDirectory; + private JButton myTestButton; // test repository + private JTextField myDirectoryName; + private JLabel myRepositoryUrlLabel; + + @NotNull private String myTestURL; // the repository URL at the time of the last test + @Nullable private Boolean myTestResult; // the test result of the last test or null if not tested + @NotNull private String myDefaultDirectoryName = ""; + @NotNull protected final Project myProject; + @NotNull protected final String myVcsDirectoryName; + + public CloneDvcsDialog(@NotNull Project project, @NotNull String displayName, @NotNull String vcsDirectoryName) { + super(project, true); + myProject = project; + myVcsDirectoryName = vcsDirectoryName; + init(); + initListeners(); + setTitle(DvcsBundle.getString("clone.title")); + myRepositoryUrlLabel.setText(DvcsBundle.message("clone.repository.url", displayName)); + setOKButtonText(DvcsBundle.getString("clone.button")); + } + + @NotNull + public String getSourceRepositoryURL() { + return getCurrentUrlText(); + } + + public String getParentDirectory() { + return myParentDirectory.getText(); + } + + public String getDirectoryName() { + return myDirectoryName.getText(); + } + + /** + * Init components + */ + private void initListeners() { + FileChooserDescriptor fcd = FileChooserDescriptorFactory.createSingleFolderDescriptor(); + fcd.setShowFileSystemRoots(true); + fcd.setTitle(DvcsBundle.getString("clone.destination.directory.title")); + fcd.setDescription(DvcsBundle.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 DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + updateButtons(); + } + }; + myParentDirectory.getChildComponent().getDocument().addDocumentListener(updateOkButtonListener); + String parentDir = getRememberedInputs().getCloneParentDir(); + if (StringUtil.isEmptyOrSpaces(parentDir)) { + parentDir = ProjectUtil.getBaseDir(); + } + myParentDirectory.setText(parentDir); + + myDirectoryName.getDocument().addDocumentListener(updateOkButtonListener); + + myTestButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + test(); + } + }); + + setOKActionEnabled(false); + myTestButton.setEnabled(false); + } + + private void test() { + myTestURL = getCurrentUrlText(); + boolean testResult = test(myTestURL); + + if (testResult) { + Messages.showInfoMessage(myTestButton, DvcsBundle.message("clone.test.success.message", myTestURL), + DvcsBundle.getString("clone.test.connection.title")); + myTestResult = Boolean.TRUE; + } + else { + myTestResult = Boolean.FALSE; + } + updateButtons(); + } + + protected abstract boolean test(@NotNull String url); + + @NotNull + protected abstract DvcsRememberedInputs getRememberedInputs(); + + /** + * Check fields and display error in the wrapper if there is a problem + */ + private void updateButtons() { + if (!checkRepositoryURL()) { + return; + } + if (!checkDestination()) { + return; + } + setErrorText(null); + setOKActionEnabled(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(DvcsBundle.message("clone.destination.exists.error", file)); + setOKActionEnabled(false); + return false; + } + else if (!file.getParentFile().exists()) { + setErrorText(DvcsBundle.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 = getCurrentUrlText(); + if (repository.length() == 0) { + setErrorText(null); + setOKActionEnabled(false); + return false; + } + if (myTestResult != null && repository.equals(myTestURL)) { + if (!myTestResult.booleanValue()) { + setErrorText(DvcsBundle.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(DvcsBundle.getString("clone.url.is.not.directory.error")); + setOKActionEnabled(false); + } + return true; + } + } + catch (Exception fileExp) { + // do nothing + } + setErrorText(DvcsBundle.getString("clone.invalid.url")); + setOKActionEnabled(false); + return false; + } + + @NotNull + private String getCurrentUrlText() { + return myRepositoryURL.getText().trim(); + } + + private void createUIComponents() { + myRepositoryURL = new EditorComboBox(""); + final DvcsRememberedInputs rememberedInputs = getRememberedInputs(); + myRepositoryURL.setHistory(ArrayUtil.toObjectArray(rememberedInputs.getVisitedUrls(), String.class)); + myRepositoryURL.addDocumentListener(new com.intellij.openapi.editor.event.DocumentAdapter() { + @Override + public void documentChanged(com.intellij.openapi.editor.event.DocumentEvent e) { + // enable test button only if something is entered in repository URL + final String url = getCurrentUrlText(); + 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, myVcsDirectoryName); + myDirectoryName.setText(myDefaultDirectoryName); + } + updateButtons(); + } + }); + } + + public void prependToHistory(@NotNull final String item) { + myRepositoryURL.prependItem(item); + } + + public void rememberSettings() { + final DvcsRememberedInputs rememberedInputs = getRememberedInputs(); + rememberedInputs.addUrl(getSourceRepositoryURL()); + rememberedInputs.setCloneParentDir(getParentDirectory()); + } + + /** + * Get default name for checked out directory + * + * @param url an URL to checkout + * @return a default repository name + */ + @NotNull + private static String defaultDirectoryName(@NotNull final String url, @NotNull final String vcsDirName) { + String nonSystemName; + if (url.endsWith("/" + vcsDirName) || url.endsWith(File.separator + vcsDirName)) { + nonSystemName = url.substring(0, url.length() - vcsDirName.length() - 1); + } + else { + if (url.endsWith(vcsDirName)) { + nonSystemName = url.substring(0, url.length() - vcsDirName.length()); + } + else { + nonSystemName = url; + } + } + int i = nonSystemName.lastIndexOf('/'); + if (i == -1 && File.separatorChar != '/') { + i = nonSystemName.lastIndexOf(File.separatorChar); + } + return i >= 0 ? nonSystemName.substring(i + 1) : ""; + } + + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return myRepositoryURL; + } + + protected JComponent createCenterPanel() { + return myRootPanel; + } +} |