blob: 2bc8499e6c01d0c77869424a3574c0a9f4228faf [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.openapi.roots.ui.configuration;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.BrowseFilesListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.StorageScheme;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.roots.CompilerProjectExtension;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectStructureElementConfigurable;
import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureDaemonAnalyzer;
import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
import com.intellij.openapi.ui.DetailsComponent;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.FieldPanel;
import com.intellij.ui.InsertPathAction;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.io.IOException;
/**
* @author Eugene Zhuravlev
* Date: Dec 15, 2003
*/
public class ProjectConfigurable extends ProjectStructureElementConfigurable<Project> implements DetailsComponent.Facade {
private final Project myProject;
private LanguageLevelCombo myLanguageLevelCombo;
private ProjectJdkConfigurable myProjectJdkConfigurable;
private FieldPanel myProjectCompilerOutput;
private JTextField myProjectName;
private JPanel myPanel;
private final StructureConfigurableContext myContext;
private final ModulesConfigurator myModulesConfigurator;
private JPanel myWholePanel;
private boolean myFreeze = false;
private DetailsComponent myDetailsComponent;
private final GeneralProjectSettingsElement mySettingsElement;
public ProjectConfigurable(Project project,
final StructureConfigurableContext context,
ModulesConfigurator configurator,
ProjectSdksModel model) {
myProject = project;
myContext = context;
myModulesConfigurator = configurator;
mySettingsElement = new GeneralProjectSettingsElement(context);
final ProjectStructureDaemonAnalyzer daemonAnalyzer = context.getDaemonAnalyzer();
myModulesConfigurator.addAllModuleChangeListener(new ModuleEditor.ChangeListener() {
@Override
public void moduleStateChanged(ModifiableRootModel moduleRootModel) {
daemonAnalyzer.queueUpdate(mySettingsElement);
}
});
init(model);
}
@Override
public ProjectStructureElement getProjectStructureElement() {
return mySettingsElement;
}
@Override
public DetailsComponent getDetailsComponent() {
return myDetailsComponent;
}
@Override
public JComponent createOptionsPanel() {
myDetailsComponent = new DetailsComponent(!Registry.is("ide.new.project.settings"), !Registry.is("ide.new.project.settings"));
myDetailsComponent.setContent(myPanel);
myDetailsComponent.setText(getBannerSlogan());
myProjectJdkConfigurable.createComponent(); //reload changed jdks
return myDetailsComponent.getComponent();
}
private void init(final ProjectSdksModel model) {
myPanel = new JPanel(new GridBagLayout());
myPanel.setPreferredSize(new Dimension(700, 500));
if (((ProjectEx)myProject).getStateStore().getStorageScheme().equals(StorageScheme.DIRECTORY_BASED)) {
final JPanel namePanel = new JPanel(new BorderLayout());
final JLabel label =
new JLabel("<html><body><b>Project name:</b></body></html>", SwingConstants.LEFT);
namePanel.add(label, BorderLayout.NORTH);
myProjectName = new JTextField();
myProjectName.setColumns(40);
final JPanel nameFieldPanel = new JPanel();
nameFieldPanel.setLayout(new BoxLayout(nameFieldPanel, BoxLayout.X_AXIS));
nameFieldPanel.add(Box.createHorizontalStrut(4));
nameFieldPanel.add(myProjectName);
namePanel.add(nameFieldPanel, BorderLayout.CENTER);
final JPanel wrapper = new JPanel(new FlowLayout(FlowLayout.LEFT));
wrapper.add(namePanel);
wrapper.setAlignmentX(0);
myPanel.add(wrapper, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(4, 0, 10, 0), 0, 0));
}
myProjectJdkConfigurable = new ProjectJdkConfigurable(myProject, model);
myPanel.add(myProjectJdkConfigurable.createComponent(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(4, 4, 0, 0), 0, 0));
myPanel.add(myWholePanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST,
GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
myPanel.setBorder(new EmptyBorder(0, 10, 0, 10));
myProjectCompilerOutput.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
if (myFreeze) return;
myModulesConfigurator.processModuleCompilerOutputChanged(getCompilerOutputUrl());
}
});
}
@Override
public void disposeUIResources() {
if (myProjectJdkConfigurable != null) {
myProjectJdkConfigurable.disposeUIResources();
}
}
@Override
public void reset() {
myFreeze = true;
try {
myProjectJdkConfigurable.reset();
final String compilerOutput = getOriginalCompilerOutputUrl();
if (compilerOutput != null) {
myProjectCompilerOutput.setText(FileUtil.toSystemDependentName(VfsUtil.urlToPath(compilerOutput)));
}
myLanguageLevelCombo.reset(myProject);
if (myProjectName != null) {
myProjectName.setText(myProject.getName());
}
}
finally {
myFreeze = false;
}
myContext.getDaemonAnalyzer().queueUpdate(mySettingsElement);
}
@Override
public void apply() throws ConfigurationException {
final CompilerProjectExtension compilerProjectExtension = CompilerProjectExtension.getInstance(myProject);
assert compilerProjectExtension != null : myProject;
if (myProjectName != null && StringUtil.isEmptyOrSpaces(myProjectName.getText())) {
throw new ConfigurationException("Please, specify project name!");
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
// set the output path first so that handlers of RootsChanged event sent after JDK is set
// would see the updated path
String canonicalPath = myProjectCompilerOutput.getText();
if (canonicalPath != null && canonicalPath.length() > 0) {
try {
canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath);
}
catch (IOException e) {
//file doesn't exist yet
}
canonicalPath = FileUtil.toSystemIndependentName(canonicalPath);
compilerProjectExtension.setCompilerOutputUrl(VfsUtil.pathToUrl(canonicalPath));
}
else {
compilerProjectExtension.setCompilerOutputPointer(null);
}
final LanguageLevel newLevel = (LanguageLevel)myLanguageLevelCombo.getSelectedItem();
LanguageLevelProjectExtension.getInstance(myProject).setLanguageLevel(newLevel);
myProjectJdkConfigurable.apply();
if (myProjectName != null) {
((ProjectEx)myProject).setProjectName(myProjectName.getText().trim());
if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan());
}
}
});
}
@Override
public void setDisplayName(final String name) {
//do nothing
}
@Override
public Project getEditableObject() {
return myProject;
}
@Override
public String getBannerSlogan() {
return ProjectBundle.message("project.roots.project.banner.text", myProject.getName());
}
@Override
public String getDisplayName() {
return ProjectBundle.message("project.roots.project.display.name");
}
@Override
public Icon getIcon(boolean open) {
return AllIcons.Nodes.Project;
}
@Override
@Nullable
@NonNls
public String getHelpTopic() {
return "reference.settingsdialog.project.structure.general";
}
@Override
@SuppressWarnings({"SimplifiableIfStatement"})
public boolean isModified() {
if (!LanguageLevelProjectExtension.getInstance(myProject).getLanguageLevel().equals(myLanguageLevelCombo.getSelectedItem())) {
return true;
}
final String compilerOutput = getOriginalCompilerOutputUrl();
if (!Comparing.strEqual(FileUtil.toSystemIndependentName(VfsUtil.urlToPath(compilerOutput)),
FileUtil.toSystemIndependentName(myProjectCompilerOutput.getText()))) return true;
if (myProjectJdkConfigurable.isModified()) return true;
if (myProjectName != null) {
if (!myProjectName.getText().trim().equals(myProject.getName())) return true;
}
return false;
}
@Nullable
private String getOriginalCompilerOutputUrl() {
final CompilerProjectExtension extension = CompilerProjectExtension.getInstance(myProject);
return extension != null ? extension.getCompilerOutputUrl() : null;
}
private void createUIComponents() {
myLanguageLevelCombo = new LanguageLevelCombo();
final JTextField textField = new JTextField();
final FileChooserDescriptor outputPathsChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
InsertPathAction.addTo(textField, outputPathsChooserDescriptor);
outputPathsChooserDescriptor.setHideIgnored(false);
BrowseFilesListener listener = new BrowseFilesListener(textField, "", ProjectBundle.message("project.compiler.output"), outputPathsChooserDescriptor);
myProjectCompilerOutput = new FieldPanel(textField, null, null, listener, EmptyRunnable.getInstance());
FileChooserFactory.getInstance().installFileCompletion(myProjectCompilerOutput.getTextField(), outputPathsChooserDescriptor, true, null);
}
public String getCompilerOutputUrl() {
return VfsUtil.pathToUrl(myProjectCompilerOutput.getText().trim());
}
}