blob: f11e89daa4700bdc6b54b6c877667fccdf9b9c5f [file] [log] [blame]
/*
* Copyright 2000-2012 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.facet.impl.ui.libraries;
import com.intellij.framework.library.DownloadableLibraryDescription;
import com.intellij.framework.library.DownloadableLibraryType;
import com.intellij.framework.library.FrameworkLibraryVersion;
import com.intellij.framework.library.FrameworkLibraryVersionFilter;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.util.frameworkSupport.OldCustomLibraryDescription;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.NewLibraryConfiguration;
import com.intellij.openapi.roots.ui.OrderEntryAppearanceService;
import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription;
import com.intellij.openapi.roots.ui.configuration.libraries.LibraryPresentationManager;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.ExistingLibraryEditor;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor;
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.SortedComboBoxModel;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.PathUtil;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.download.DownloadableFileSetVersions;
import com.intellij.util.ui.RadioButtonEnumModel;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* @author Dmitry Avdeev
*/
public class LibraryOptionsPanel implements Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.facet.impl.ui.libraries.LibraryOptionsPanel");
private JBLabel myMessageLabel;
private JPanel myPanel;
private JButton myConfigureButton;
private JComboBox myExistingLibraryComboBox;
private JRadioButton myDoNotCreateRadioButton;
private JPanel myConfigurationPanel;
private JButton myCreateButton;
private JRadioButton myDownloadRadioButton;
private JRadioButton myUseLibraryRadioButton;
private JLabel myUseLibraryLabel;
private JLabel myHiddenLabel;
private JPanel myRootPanel;
private JRadioButton myUseFromProviderRadioButton;
private ButtonGroup myButtonGroup;
private LibraryCompositionSettings mySettings;
private final CustomLibraryDescription myLibraryDescription;
private final LibrariesContainer myLibrariesContainer;
private SortedComboBoxModel<LibraryEditor> myLibraryComboBoxModel;
private FrameworkLibraryProvider myLibraryProvider;
private boolean myDisposed;
private enum Choice {
USE_LIBRARY,
DOWNLOAD,
SETUP_LIBRARY_LATER,
USE_FROM_PROVIDER
}
private RadioButtonEnumModel<Choice> myButtonEnumModel;
public LibraryOptionsPanel(@NotNull final CustomLibraryDescription libraryDescription,
@NotNull final String baseDirectoryPath,
@NotNull final FrameworkLibraryVersionFilter versionFilter,
@NotNull final LibrariesContainer librariesContainer,
final boolean showDoNotCreateOption) {
myLibraryDescription = libraryDescription;
myLibrariesContainer = librariesContainer;
final DownloadableLibraryDescription description = getDownloadableDescription(libraryDescription);
if (description != null) {
showCard("loading");
description.fetchVersions(new DownloadableFileSetVersions.FileSetVersionsCallback<FrameworkLibraryVersion>() {
@Override
public void onSuccess(@NotNull final List<? extends FrameworkLibraryVersion> versions) {
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (!myDisposed) {
showSettingsPanel(libraryDescription, baseDirectoryPath, versionFilter, showDoNotCreateOption, versions);
}
}
});
}
});
}
else {
showSettingsPanel(libraryDescription, baseDirectoryPath, versionFilter, showDoNotCreateOption,
new ArrayList<FrameworkLibraryVersion>());
}
}
@Nullable
private static DownloadableLibraryDescription getDownloadableDescription(CustomLibraryDescription libraryDescription) {
final DownloadableLibraryType type = libraryDescription.getDownloadableLibraryType();
if (type != null) return type.getLibraryDescription();
if (libraryDescription instanceof OldCustomLibraryDescription) {
return ((OldCustomLibraryDescription)libraryDescription).getDownloadableDescription();
}
return null;
}
private void showCard(final String editing) {
((CardLayout)myRootPanel.getLayout()).show(myRootPanel, editing);
}
private void showSettingsPanel(CustomLibraryDescription libraryDescription,
String baseDirectoryPath,
FrameworkLibraryVersionFilter versionFilter,
boolean showDoNotCreateOption, final List<? extends FrameworkLibraryVersion> versions) {
//todo[nik] create mySettings only in apply() method
mySettings = new LibraryCompositionSettings(libraryDescription, baseDirectoryPath, versionFilter, versions);
Disposer.register(this, mySettings);
List<Library> libraries = calculateSuitableLibraries();
myButtonEnumModel = RadioButtonEnumModel.bindEnum(Choice.class, myButtonGroup);
myButtonEnumModel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateState();
}
});
myDoNotCreateRadioButton.setVisible(showDoNotCreateOption);
myLibraryComboBoxModel = new SortedComboBoxModel<LibraryEditor>(new Comparator<LibraryEditor>() {
@Override
public int compare(LibraryEditor o1, LibraryEditor o2) {
final String name1 = o1.getName();
final String name2 = o2.getName();
return -StringUtil.notNullize(name1).compareToIgnoreCase(StringUtil.notNullize(name2));
}
});
for (Library library : libraries) {
ExistingLibraryEditor libraryEditor = myLibrariesContainer.getLibraryEditor(library);
if (libraryEditor == null) {
libraryEditor = mySettings.getOrCreateEditor(library);
}
myLibraryComboBoxModel.add(libraryEditor);
}
myExistingLibraryComboBox.setModel(myLibraryComboBoxModel);
if (libraries.isEmpty()) {
myLibraryComboBoxModel.add(null);
}
myExistingLibraryComboBox.setSelectedIndex(0);
myExistingLibraryComboBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED && e.getItem() != null) {
myButtonEnumModel.setSelected(Choice.USE_LIBRARY);
}
updateState();
}
});
myExistingLibraryComboBox.setRenderer(new ColoredListCellRenderer() {
@Override
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
if (value == null) {
append("[No library selected]");
}
else if (value instanceof ExistingLibraryEditor) {
final Library library = ((ExistingLibraryEditor)value).getLibrary();
final boolean invalid = !((LibraryEx)library).getInvalidRootUrls(OrderRootType.CLASSES).isEmpty();
OrderEntryAppearanceService.getInstance().forLibrary(getProject(), library, invalid).customize(this);
}
else if (value instanceof NewLibraryEditor) {
setIcon(PlatformIcons.LIBRARY_ICON);
final String name = ((NewLibraryEditor)value).getName();
append(name != null ? name : "<unnamed>");
}
}
});
boolean canDownload = mySettings.getDownloadSettings() != null;
boolean canUseFromProvider = myLibraryProvider != null;
myDownloadRadioButton.setVisible(canDownload);
myUseFromProviderRadioButton.setVisible(canUseFromProvider);
Choice selectedOption;
if (canUseFromProvider) {
selectedOption = Choice.USE_FROM_PROVIDER;
}
else if (libraries.isEmpty() && canDownload) {
selectedOption = Choice.DOWNLOAD;
}
else {
selectedOption = Choice.USE_LIBRARY;
}
myButtonEnumModel.setSelected(selectedOption);
if (!canDownload && !canUseFromProvider && !showDoNotCreateOption) {
myUseLibraryRadioButton.setVisible(false);
myUseLibraryLabel.setVisible(true);
}
final Dimension minimumSize = new Dimension(-1, myMessageLabel.getFontMetrics(myMessageLabel.getFont()).getHeight() * 2);
myHiddenLabel.setMinimumSize(minimumSize);
myCreateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doCreate();
}
});
myConfigureButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
doConfigure();
}
});
updateState();
showCard("editing");
}
private Project getProject() {
Project project = myLibrariesContainer.getProject();
if (project == null) {
project = ProjectManager.getInstance().getDefaultProject();
}
return project;
}
private void doConfigure() {
switch (myButtonEnumModel.getSelected()) {
case DOWNLOAD:
final LibraryDownloadSettings oldDownloadSettings = mySettings.getDownloadSettings();
LOG.assertTrue(oldDownloadSettings != null);
final LibraryDownloadSettings newDownloadSettings = DownloadingOptionsDialog.showDialog(myPanel, oldDownloadSettings,
mySettings.getCompatibleVersions(), true);
if (newDownloadSettings != null) {
mySettings.setDownloadSettings(newDownloadSettings);
}
break;
case USE_LIBRARY:
final Object item = myExistingLibraryComboBox.getSelectedItem();
if (item instanceof LibraryEditor) {
EditLibraryDialog dialog = new EditLibraryDialog(myPanel, mySettings, (LibraryEditor)item);
dialog.show();
if (item instanceof ExistingLibraryEditor) {
new WriteAction() {
protected void run(final Result result) {
((ExistingLibraryEditor)item).commit();
}
}.execute();
}
}
break;
case USE_FROM_PROVIDER:
case SETUP_LIBRARY_LATER:
break;
}
updateState();
}
public void setLibraryProvider(@Nullable FrameworkLibraryProvider provider) {
if (provider != null && !ContainerUtil.intersects(provider.getAvailableLibraryKinds(), myLibraryDescription.getSuitableLibraryKinds())) {
provider = null;
}
if (!Comparing.equal(myLibraryProvider, provider)) {
myLibraryProvider = provider;
if (mySettings != null) {
if (provider != null && !myUseFromProviderRadioButton.isVisible()) {
myUseFromProviderRadioButton.setSelected(true);
}
myUseFromProviderRadioButton.setVisible(provider != null);
updateState();
}
}
}
public void changeBaseDirectoryPath(@NotNull String directoryForLibrariesPath) {
if (mySettings != null) {
mySettings.changeBaseDirectoryPath(directoryForLibrariesPath);
updateState();
}
}
public void setVersionFilter(@NotNull FrameworkLibraryVersionFilter versionFilter) {
if (mySettings != null) {
mySettings.setVersionFilter(versionFilter);
updateState();
}
}
private void doCreate() {
final NewLibraryConfiguration libraryConfiguration = myLibraryDescription.createNewLibrary(myPanel, getBaseDirectory());
if (libraryConfiguration != null) {
final NewLibraryEditor libraryEditor = new NewLibraryEditor(libraryConfiguration.getLibraryType(), libraryConfiguration.getProperties());
libraryEditor.setName(myLibrariesContainer.suggestUniqueLibraryName(libraryConfiguration.getDefaultLibraryName()));
libraryConfiguration.addRoots(libraryEditor);
if (myLibraryComboBoxModel.get(0) == null) {
myLibraryComboBoxModel.remove(0);
}
myLibraryComboBoxModel.add(libraryEditor);
myLibraryComboBoxModel.setSelectedItem(libraryEditor);
myButtonEnumModel.setSelected(Choice.USE_LIBRARY);
}
}
private List<Library> calculateSuitableLibraries() {
List<Library> suitableLibraries = new ArrayList<Library>();
for (Library library : myLibrariesContainer.getAllLibraries()) {
if (myLibraryDescription instanceof OldCustomLibraryDescription &&
((OldCustomLibraryDescription)myLibraryDescription).isSuitableLibrary(library, myLibrariesContainer)
|| LibraryPresentationManager.getInstance().isLibraryOfKind(library, myLibrariesContainer, myLibraryDescription.getSuitableLibraryKinds())) {
suitableLibraries.add(library);
}
}
return suitableLibraries;
}
@Nullable
private VirtualFile getBaseDirectory() {
String path = mySettings.getBaseDirectoryPath();
VirtualFile dir = LocalFileSystem.getInstance().findFileByPath(path);
if (dir == null) {
path = path.substring(0, path.lastIndexOf('/'));
dir = LocalFileSystem.getInstance().findFileByPath(path);
}
return dir;
}
private void updateState() {
myMessageLabel.setIcon(null);
myConfigureButton.setVisible(true);
final LibraryDownloadSettings settings = mySettings.getDownloadSettings();
myDownloadRadioButton.setVisible(settings != null);
myUseFromProviderRadioButton.setVisible(myLibraryProvider != null);
if (!myUseFromProviderRadioButton.isVisible() && myUseFromProviderRadioButton.isSelected()) {
if (myDownloadRadioButton.isVisible()) {
myDownloadRadioButton.setSelected(true);
}
else {
myUseLibraryRadioButton.setSelected(true);
}
}
if (!myDownloadRadioButton.isVisible() && myDownloadRadioButton.isSelected() && myUseLibraryRadioButton.isVisible()) {
myUseLibraryRadioButton.setSelected(true);
}
String message = "";
boolean showConfigurePanel = true;
switch (myButtonEnumModel.getSelected()) {
case DOWNLOAD:
message = getDownloadFilesMessage();
break;
case USE_FROM_PROVIDER:
if (myLibraryProvider != null) {
message = "Library from " + myLibraryProvider.getPresentableName() + " will be used";
}
myConfigureButton.setVisible(false);
break;
case USE_LIBRARY:
final Object item = myExistingLibraryComboBox.getSelectedItem();
if (item == null) {
myMessageLabel.setIcon(AllIcons.RunConfigurations.ConfigurationWarning);
message = "<b>Error:</b> library is not specified";
myConfigureButton.setVisible(false);
}
else if (item instanceof NewLibraryEditor) {
final LibraryEditor libraryEditor = (LibraryEditor)item;
message = IdeBundle.message("label.library.will.be.created.description.text", mySettings.getNewLibraryLevel(),
libraryEditor.getName(), libraryEditor.getFiles(OrderRootType.CLASSES).length);
}
else {
message = MessageFormat.format("<b>{0}</b> library will be used", ((ExistingLibraryEditor)item).getName());
}
break;
default:
showConfigurePanel = false;
}
if (myLibraryProvider != null) {
myUseFromProviderRadioButton.setText("Use library from " + myLibraryProvider.getPresentableName());
}
//show the longest message on the hidden card to ensure that dialog won't jump if user selects another option
if (mySettings.getDownloadSettings() != null) {
myHiddenLabel.setText(getDownloadFilesMessage());
}
else {
myHiddenLabel.setText(IdeBundle.message("label.library.will.be.created.description.text", mySettings.getNewLibraryLevel(),
"name", 10));
}
((CardLayout)myConfigurationPanel.getLayout()).show(myConfigurationPanel, showConfigurePanel ? "configure" : "empty");
myMessageLabel.setText(XmlStringUtil.wrapInHtml(message));
}
private String getDownloadFilesMessage() {
final LibraryDownloadSettings downloadSettings = mySettings.getDownloadSettings();
if (downloadSettings == null) return "";
final String downloadPath = downloadSettings.getDirectoryForDownloadedLibrariesPath();
final String basePath = mySettings.getBaseDirectoryPath();
String path;
if (!StringUtil.isEmpty(basePath) && FileUtil.startsWith(downloadPath, basePath)) {
path = FileUtil.getRelativePath(basePath, downloadPath, '/');
}
else {
path = PathUtil.getFileName(downloadPath);
}
return MessageFormat.format("{0} {0, choice, 1#jar|2#jars} will be downloaded into <b>{1}</b> directory<br>" +
"{2} library <b>{3}</b> will be created",
downloadSettings.getSelectedDownloads().size(),
path,
downloadSettings.getLibraryLevel(),
downloadSettings.getLibraryName());
}
public LibraryCompositionSettings getSettings() {
return mySettings;
}
@Nullable
public LibraryCompositionSettings apply() {
if (mySettings == null) return null;
final Choice option = myButtonEnumModel.getSelected();
mySettings.setDownloadLibraries(option == Choice.DOWNLOAD);
final Object item = myExistingLibraryComboBox.getSelectedItem();
if (option == Choice.USE_LIBRARY && item instanceof ExistingLibraryEditor) {
mySettings.setSelectedExistingLibrary(((ExistingLibraryEditor)item).getLibrary());
}
else {
mySettings.setSelectedExistingLibrary(null);
}
if (option == Choice.USE_LIBRARY && item instanceof NewLibraryEditor) {
mySettings.setNewLibraryEditor((NewLibraryEditor)item);
}
else {
mySettings.setNewLibraryEditor(null);
}
mySettings.setLibraryProvider(option == Choice.USE_FROM_PROVIDER ? myLibraryProvider : null);
return mySettings;
}
public JComponent getMainPanel() {
return myRootPanel;
}
@Override
public void dispose() {
myDisposed = true;
}
}