summaryrefslogtreecommitdiff
path: root/platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java
diff options
context:
space:
mode:
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.java332
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;
+ }
+}