blob: da18f37c2290e6ac5ad847a6ab7e66a87909dba7 [file] [log] [blame]
/*
* Copyright 2000-2014 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.highlighter.ProjectFileType;
import com.intellij.ide.util.BrowseFilesListener;
import com.intellij.openapi.application.ApplicationInfo;
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.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
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;
private boolean myShouldBeAbsolute;
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) {
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 static NamePathComponent initNamePathComponent(WizardContext context) {
NamePathComponent component = new NamePathComponent(
IdeBundle.message("label.project.name"),
IdeBundle.message("label.project.files.location"),
IdeBundle.message("title.select.project.file.directory", IdeBundle.message("project.new.wizard.project.identification")),
IdeBundle.message("description.select.project.file.directory", StringUtil
.capitalize(IdeBundle.message("project.new.wizard.project.identification"))),
true, false
);
final String baseDir = context.getProjectFileDirectory();
final String projectName = context.getProjectName();
final String initialProjectName = projectName != null ? projectName : ProjectWizardUtil.findNonExistingFileName(baseDir, "untitled", "");
component.setPath(projectName == null ? (baseDir + File.separator + initialProjectName) : baseDir);
component.setNameValue(initialProjectName);
component.getNameComponent().select(0, initialProjectName.length());
return component;
}
public boolean validateNameAndPath(WizardContext context, boolean defaultFormat) throws ConfigurationException {
String name = getNameValue();
if (StringUtil.isEmptyOrSpaces(name)) {
ApplicationInfo info = ApplicationInfo.getInstance();
throw new ConfigurationException(IdeBundle.message("prompt.new.project.file.name", info.getVersionName(), context.getPresentationName()));
}
String projectDirectory = getPath();
if (StringUtil.isEmptyOrSpaces(projectDirectory)) {
throw new ConfigurationException(IdeBundle.message("prompt.enter.project.file.location", context.getPresentationName()));
}
if (myShouldBeAbsolute && !new File(projectDirectory).isAbsolute()) {
throw new ConfigurationException(StringUtil.capitalize(IdeBundle.message("file.location.should.be.absolute", context.getPresentationName())));
}
boolean shouldPromptCreation = isPathChangedByUser();
String message = IdeBundle.message("directory.project.file.directory", context.getPresentationName());
if (!ProjectWizardUtil.createDirectoryIfNotExists(message, projectDirectory, shouldPromptCreation)) {
return false;
}
File file = new File(projectDirectory);
if (file.exists() && !file.canWrite()) {
throw new ConfigurationException(String.format("Directory '%s' is not writable!\nPlease choose another project location.", projectDirectory));
}
boolean shouldContinue = true;
String fileName = defaultFormat ? name + ProjectFileType.DOT_DEFAULT_EXTENSION : Project.DIRECTORY_STORE_FOLDER;
File projectFile = new File(file, fileName);
if (projectFile.exists()) {
message = IdeBundle.message("prompt.overwrite.project.file", projectFile.getAbsolutePath(), context.getPresentationName());
int answer = Messages.showYesNoDialog(message, 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() {
String text = myTfPath.getText().trim();
return FileUtil.expandUserHome(FileUtil.toSystemIndependentName(text));
}
public void setPath(String path) {
final boolean isPathChangedByUser = myIsPathChangedByUser;
setPathNameSyncEnabled(false);
try {
myTfPath.setText(FileUtil.getLocationRelativeToUserHome(FileUtil.toSystemDependentName(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);
}
public void setShouldBeAbsolute(boolean shouldBeAbsolute) {
myShouldBeAbsolute = shouldBeAbsolute;
}
private class NameFieldDocument extends PlainDocument {
public NameFieldDocument() {
addDocumentListener(new DocumentAdapter() {
public void textChanged(DocumentEvent event) {
myIsNameChangedByUser = true;
syncNameAndPath();
}
});
}
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() {
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);
}
}
}
}
}