/* * 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 com.intellij.ide.util.projectWizard; import com.intellij.ide.IdeBundle; import com.intellij.ide.util.BrowseFilesListener; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.FieldPanel; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; import java.awt.*; import java.awt.event.ActionEvent; import java.io.File; /** * @author Eugene Zhuravlev * Date: Dec 30, 2003 */ public class NamePathComponent extends JPanel{ private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.projectWizard.NamePathComponent"); private JTextField myTfName; private JTextField myTfPath; private boolean myIsNameChangedByUser = false; private boolean myIsPathChangedByUser = false; private boolean myIsPathNameSyncEnabled = true; private boolean myIsNamePathSyncEnabled = true; private boolean myIsSyncEnabled = true; private FieldPanel myPathPanel; private JLabel myNameLabel; private JLabel myPathLabel; private boolean myForceSync; public NamePathComponent(String nameLabelText, String pathLabelText, char nameMnemonic, char locationMnemonic, final String pathChooserTitle, final String pathChooserDescription) { this(nameLabelText, pathLabelText, pathChooserTitle, pathChooserDescription, true); } public NamePathComponent(String nameLabelText, String pathLabelText, final String pathChooserTitle, final String pathChooserDescription, boolean hideIgnored) { this(nameLabelText, pathLabelText, pathChooserTitle, pathChooserDescription, hideIgnored, true); } public NamePathComponent(String nameLabelText, String pathLabelText, final String pathChooserTitle, final String pathChooserDescription, boolean hideIgnored, boolean bold) { super(new GridBagLayout()); myTfName = new JTextField(); myTfName.setDocument(new NameFieldDocument()); myTfName.setPreferredSize(new Dimension(200, myTfName.getPreferredSize().height)); myTfPath = new JTextField(); myTfPath.setDocument(new PathFieldDocument()); myTfPath.setPreferredSize(new Dimension(200, myTfPath.getPreferredSize().height)); myNameLabel = new JLabel(nameLabelText); if (bold) myNameLabel.setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD)); myNameLabel.setLabelFor(myTfName); Insets insets = new Insets(0, 0, 5, 4); this.add(myNameLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0)); insets = new Insets(0, 0, 5, 0); this.add(myTfName, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, insets, 0, 0)); // todo: review texts final FileChooserDescriptor chooserDescriptor = (FileChooserDescriptor)BrowseFilesListener.SINGLE_DIRECTORY_DESCRIPTOR.clone(); chooserDescriptor.setHideIgnored(hideIgnored); final BrowseFilesListener browseButtonActionListener = new BrowseFilesListener(myTfPath, pathChooserTitle, pathChooserDescription, chooserDescriptor) { @Override public void actionPerformed(ActionEvent e) { super.actionPerformed(e); myIsPathChangedByUser = true; } }; myPathPanel = new FieldPanel(myTfPath, null, null, browseButtonActionListener, null); myPathLabel = new JLabel(pathLabelText); myPathLabel.setLabelFor(myTfPath); if (bold) myPathLabel.setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD)); insets = new Insets(0, 0, 5, 4); this.add(myPathLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0)); insets = new Insets(0, 0, 5, 0); this.add(myPathPanel, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, insets, 0, 0)); } public boolean validateNameAndPath(WizardContext context) throws ConfigurationException { final String name = getNameValue(); if (name.length() == 0) { final ApplicationInfo info = ApplicationManager.getApplication().getComponent(ApplicationInfo.class); throw new ConfigurationException( IdeBundle.message("prompt.new.project.file.name", info.getVersionName(), context.getPresentationName())); } final String projectFileDirectory = getPath(); if (projectFileDirectory.length() == 0) { throw new ConfigurationException(IdeBundle.message("prompt.enter.project.file.location", context.getPresentationName())); } final boolean shouldPromptCreation = isPathChangedByUser(); if (!ProjectWizardUtil .createDirectoryIfNotExists(IdeBundle.message("directory.project.file.directory", context.getPresentationName()), projectFileDirectory, shouldPromptCreation)) { return false; } final File file = new File(projectFileDirectory); if (file.exists() && !file.canWrite()) { throw new ConfigurationException(String.format("Directory '%s' is not writable!\nPlease choose another project location.", projectFileDirectory)); } boolean shouldContinue = true; final File projectDir = new File(getPath(), Project.DIRECTORY_STORE_FOLDER); if (projectDir.exists()) { int answer = Messages.showYesNoDialog( IdeBundle.message("prompt.overwrite.project.folder", projectDir.getAbsolutePath(), context.getPresentationName()), IdeBundle.message("title.file.already.exists"), Messages.getQuestionIcon()); shouldContinue = (answer == Messages.YES); } return shouldContinue; } public String getNameValue() { return myTfName.getText().trim(); } public void setNameValue(String name) { final boolean isNameChangedByUser = myIsNameChangedByUser; setNamePathSyncEnabled(false); try { myTfName.setText(name); } finally { myIsNameChangedByUser = isNameChangedByUser; setNamePathSyncEnabled(true); } } public String getPath() { return myTfPath.getText().trim().replace(File.separatorChar, '/'); } public void setPath(String path) { final boolean isPathChangedByUser = myIsPathChangedByUser; setPathNameSyncEnabled(false); try { myTfPath.setText(path); } finally { myIsPathChangedByUser = isPathChangedByUser; setPathNameSyncEnabled(true); } } public JTextField getNameComponent() { return myTfName; } @NotNull public JLabel getPathLabel() { return myPathLabel; } public JTextField getPathComponent() { return myTfPath; } @NotNull public FieldPanel getPathPanel() { return myPathPanel; } public void setPathComponentVisible(boolean visible) { myPathPanel.setVisible(visible); } public void setNameComponentVisible(boolean visible) { myTfName.setVisible(visible); myNameLabel.setVisible(visible); } public boolean isNameChangedByUser() { return myIsNameChangedByUser; } public boolean isPathChangedByUser() { return myIsPathChangedByUser; } public boolean isSyncEnabled() { return myIsSyncEnabled; } public void setSyncEnabled(boolean isSyncEnabled) { myIsSyncEnabled = isSyncEnabled; } private boolean isPathNameSyncEnabled() { if (!isSyncEnabled()) { return false; } return myIsPathNameSyncEnabled; } private void setPathNameSyncEnabled(boolean isPathNameSyncEnabled) { myIsPathNameSyncEnabled = isPathNameSyncEnabled; } private boolean isNamePathSyncEnabled() { if (!isSyncEnabled()) { return false; } return myIsNamePathSyncEnabled; } private void setNamePathSyncEnabled(boolean isNamePathSyncEnabled) { myIsNamePathSyncEnabled = isNamePathSyncEnabled; } public void syncNameToPath(boolean b) { myForceSync = b; if (b) ((PathFieldDocument)myTfPath.getDocument()).syncPathAndName(); } public void addChangeListener(final Runnable callback) { DocumentAdapter adapter = new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { callback.run(); } }; myTfName.getDocument().addDocumentListener(adapter); myTfPath.getDocument().addDocumentListener(adapter); } private class NameFieldDocument extends PlainDocument { public NameFieldDocument() { addDocumentListener(new DocumentAdapter() { @Override public void textChanged(DocumentEvent event) { myIsNameChangedByUser = true; syncNameAndPath(); } }); } @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { boolean ok = true; for (int idx = 0; idx < str.length() && ok; idx++) { char ch = str.charAt(idx); ok = ch != File.separatorChar && ch != '\\' && ch != '/' && ch != '|' && ch != ':'; } if (ok) { super.insertString(offs, str, a); } } private void syncNameAndPath() { if (isNamePathSyncEnabled() && (myForceSync || !myIsPathChangedByUser)) { try { setPathNameSyncEnabled(false); final String name = getText(0, getLength()); final String path = myTfPath.getText().trim(); final int lastSeparatorIndex = path.lastIndexOf(File.separator); if (lastSeparatorIndex >= 0) { setPath(path.substring(0, lastSeparatorIndex + 1) + name); } } catch (BadLocationException e) { LOG.error(e); } finally { setPathNameSyncEnabled(true); } } } } private class PathFieldDocument extends PlainDocument { public PathFieldDocument() { addDocumentListener(new DocumentAdapter() { @Override public void textChanged(DocumentEvent event) { myIsPathChangedByUser = true; syncPathAndName(); } }); } private void syncPathAndName() { if (isPathNameSyncEnabled() && (myForceSync || !myIsNameChangedByUser)) { try { setNamePathSyncEnabled(false); final String path = getText(0, getLength()); final int lastSeparatorIndex = path.lastIndexOf(File.separator); if (lastSeparatorIndex >= 0 && (lastSeparatorIndex + 1) < path.length()) { setNameValue(path.substring(lastSeparatorIndex + 1)); } } catch (BadLocationException e) { LOG.error(e); } finally { setNamePathSyncEnabled(true); } } } } }