/* * 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 consulo.roots.ui.configuration; import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModel; import com.intellij.openapi.projectRoots.SdkTypeId; import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.roots.ui.configuration.projectRoot.SdkListConfigurable; import com.intellij.openapi.ui.ComboBoxWithWidePopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; import com.intellij.ui.ColoredListCellRendererWrapper; import com.intellij.ui.ScreenUtil; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.Consumer; import com.intellij.util.NullableFunction; import com.intellij.util.ObjectUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.EmptyIcon; import consulo.module.extension.ModuleExtension; import consulo.module.extension.MutableModuleExtension; import consulo.module.extension.MutableModuleInheritableNamedPointer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import consulo.annotations.DeprecationInfo; import consulo.annotations.Exported; import consulo.annotations.RequiredDispatchThread; import consulo.annotations.RequiredReadAction; import consulo.bundle.SdkUtil; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.*; import java.util.List; /** * @author Eugene Zhuravlev * @author VISTALL * @since May 18, 2005 */ public class SdkComboBox extends ComboBoxWithWidePopup { @Nullable private final Condition<SdkTypeId> myFilter; @Nullable private final Condition<SdkTypeId> myCreationFilter; public SdkComboBox(@NotNull final ProjectSdksModel sdksModel) { this(sdksModel, null, false); } public SdkComboBox(@NotNull ProjectSdksModel sdksModel, @Nullable Condition<SdkTypeId> filter, boolean withNoneItem) { this(sdksModel, filter, filter, withNoneItem); } public SdkComboBox(@NotNull ProjectSdksModel sdksModel, @Nullable Condition<SdkTypeId> filter, @Nullable String nullItemName) { this(sdksModel, filter, filter, nullItemName, null); } public SdkComboBox(@NotNull ProjectSdksModel sdksModel, @Nullable Condition<SdkTypeId> filter, @Nullable Condition<SdkTypeId> creationFilter, boolean withNoneItem) { this(sdksModel, filter, creationFilter, withNoneItem ? ProjectBundle.message("sdk.combo.box.item") : null, null); } public SdkComboBox(@NotNull ProjectSdksModel sdksModel, @Nullable Condition<SdkTypeId> filter, @Nullable Condition<SdkTypeId> creationFilter, @Nullable String nullItemName) { this(sdksModel, filter, creationFilter, nullItemName, null); } public SdkComboBox(@NotNull ProjectSdksModel sdksModel, @Nullable Condition<SdkTypeId> filter, @Nullable Condition<SdkTypeId> creationFilter, @Nullable final String nullItemName, @Nullable final Icon nullIcon) { super(new SdkComboBoxModel(sdksModel, getSdkFilter(filter), nullItemName)); myFilter = filter; myCreationFilter = creationFilter; setRenderer(new ColoredListCellRendererWrapper<SdkComboBoxItem>() { @Override public void doCustomize(JList list, SdkComboBoxItem value, int index, boolean selected, boolean hasFocus) { if (SdkComboBox.this.isEnabled()) { setIcon(EmptyIcon.ICON_16); // to fix vertical size if (value instanceof InvalidSdkComboBoxItem) { setIcon(AllIcons.Toolbar.Unknown); append(value.getSdkName(), SimpleTextAttributes.ERROR_ATTRIBUTES); } else if(value instanceof CustomSdkComboBoxItem) { setIcon(((CustomSdkComboBoxItem)value).getIcon()); append(((CustomSdkComboBoxItem)value).getPresentableName()); } else if (value instanceof ModuleExtensionSdkComboBoxItem) { ModuleExtensionSdkComboBoxItem extensionSdkComboBoxItem = (ModuleExtensionSdkComboBoxItem)value; setIcon(AllIcons.Nodes.Module); append(extensionSdkComboBoxItem.getModule().getName(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); final String sdkName = extensionSdkComboBoxItem.getSdkName(); if (sdkName != null) { append(" (" + extensionSdkComboBoxItem.getSdkName() + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES); } } else if (value instanceof InvalidModuleComboBoxItem) { setIcon(AllIcons.Nodes.Module); append(((InvalidModuleComboBoxItem)value).getModuleName(), SimpleTextAttributes.ERROR_BOLD_ATTRIBUTES); } else if (value == null || value instanceof NullSdkComboBoxItem) { setIcon(ObjectUtil.notNull(nullIcon, AllIcons.Ide.EmptyFatalError)); String name = ObjectUtil.notNull(nullItemName, ProjectBundle.message("sdk.combo.box.item")); append(name, SimpleTextAttributes.REGULAR_ATTRIBUTES); } else { Sdk sdk = value.getSdk(); String sdkName = value.getSdkName(); assert sdkName != null; setIcon(sdk == null ? AllIcons.Toolbar.Unknown : SdkUtil.getIcon(sdk)); append(sdkName, sdk == null ? SimpleTextAttributes.ERROR_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES); String version = sdk == null ? null : sdk.getVersionString(); if(version != null) { append(" (", SimpleTextAttributes.GRAY_ATTRIBUTES); append(version, SimpleTextAttributes.GRAY_ATTRIBUTES); append(")", SimpleTextAttributes.GRAY_ATTRIBUTES); } } } } }); } @Override public Dimension getPreferredSize() { final Rectangle rec = ScreenUtil.getScreenRectangle(0, 0); final Dimension size = super.getPreferredSize(); final int maxWidth = rec.width / 4; if (size.width > maxWidth) { size.width = maxWidth; } return size; } @Override public Dimension getMinimumSize() { final Dimension minSize = super.getMinimumSize(); final Dimension prefSize = getPreferredSize(); if (minSize.width > prefSize.width) { minSize.width = prefSize.width; } return minSize; } @Deprecated @DeprecationInfo(value = "Use #setSetupButton() without 'moduleJdkSetup' parameter", until = "1.0") public void setSetupButton(final JButton setUpButton, @Nullable final Project project, final ProjectSdksModel sdksModel, final SdkComboBoxItem firstItem, @Nullable final Condition<Sdk> additionalSetup, final boolean moduleJdkSetup) { setSetupButton(setUpButton, project, sdksModel, firstItem, additionalSetup); } @Deprecated @DeprecationInfo(value = "Use #setSetupButton() without 'actionGroupTitle' parameter", until = "1.0") public void setSetupButton(final JButton setUpButton, @Nullable final Project project, final ProjectSdksModel sdksModel, final SdkComboBoxItem firstItem, @Nullable final Condition<Sdk> additionalSetup, final String actionGroupTitle) { setSetupButton(setUpButton, project, sdksModel, firstItem, additionalSetup); } public void setSetupButton(@NotNull final JButton setUpButton, @Nullable final Project project, @NotNull final ProjectSdksModel sdksModel, @Nullable final SdkComboBoxItem firstItem, @Nullable final Condition<Sdk> additionalSetup) { setUpButton.addActionListener(new ActionListener() { @Override @RequiredDispatchThread public void actionPerformed(ActionEvent e) { DefaultActionGroup group = new DefaultActionGroup(); sdksModel.createAddActions(group, SdkComboBox.this, new Consumer<Sdk>() { @Override public void consume(final Sdk sdk) { if (project != null) { final SdkListConfigurable configurable = SdkListConfigurable.getInstance(project); configurable.addSdkNode(sdk, false); } reloadModel(new SdkComboBoxItem(sdk), project); setSelectedSdk(sdk); //restore selection if (additionalSetup != null) { if (additionalSetup.value(sdk)) { //leave old selection setSelectedSdk(firstItem.getSdk()); } } } }, myCreationFilter); final DataContext dataContext = DataManager.getInstance().getDataContext(SdkComboBox.this); if (group.getChildrenCount() > 1) { JBPopupFactory.getInstance().createActionGroupPopup(ProjectBundle.message("set.up.jdk.title"), group, dataContext, JBPopupFactory.ActionSelectionAid.MNEMONICS, false) .showUnderneathOf(setUpButton); } else { final AnActionEvent event = new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, new Presentation(""), ActionManager.getInstance(), 0); group.getChildren(event)[0].actionPerformed(event); } } }); } public void setEditButton(final JButton editButton, final Project project, @NotNull final Computable<Sdk> retrieveSdk) { editButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final Sdk sdk = retrieveSdk.compute(); if (sdk != null) { ProjectStructureConfigurable.getInstance(project).select(sdk, true); } } }); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final SdkComboBoxItem selectedItem = getSelectedItem(); editButton.setEnabled(!(selectedItem instanceof InvalidSdkComboBoxItem) && selectedItem != null && selectedItem.getSdk() != null); } }); } @Override public SdkComboBoxItem getSelectedItem() { return (SdkComboBoxItem)super.getSelectedItem(); } @Exported public void insertCustomSdkItem(@NotNull String key, @NotNull String presentableName, @NotNull Icon icon) { CustomSdkComboBoxItem sdkComboBoxItem = new CustomSdkComboBoxItem(key, presentableName, icon); int itemCount = getItemCount(); if(itemCount > 0) { int index = 0; for (int i = 0; i < itemCount; i++) { Object itemAt = getItemAt(i); if(itemAt instanceof NullSdkComboBoxItem || itemAt instanceof CustomSdkComboBoxItem) { index ++; } } SdkComboBoxModel model = (SdkComboBoxModel)getModel(); model.insertElementAt(sdkComboBoxItem, index); } else { addItem(sdkComboBoxItem); } } @RequiredReadAction @SuppressWarnings("unchecked") public <T extends MutableModuleExtension<?>> void insertModuleItems(@NotNull T moduleExtension, @NotNull NullableFunction<T, MutableModuleInheritableNamedPointer<Sdk>> sdkPointerFunction) { for (Module module : ModuleManager.getInstance(moduleExtension.getModule().getProject()).getModules()) { // dont add self module if (module == moduleExtension.getModule()) { continue; } ModuleExtension extension = ModuleUtilCore.getExtension(module, moduleExtension.getId()); if (extension == null) { continue; } MutableModuleInheritableNamedPointer<Sdk> sdkPointer = sdkPointerFunction.fun((T)extension); if (sdkPointer != null) { // recursive depend if (sdkPointer.getModule() == moduleExtension.getModule()) { continue; } addItem(new ModuleExtensionSdkComboBoxItem(extension, sdkPointer)); } } } @Nullable public Sdk getSelectedSdk() { final SdkComboBoxItem selectedItem = (SdkComboBoxItem)super.getSelectedItem(); return selectedItem != null ? selectedItem.getSdk() : null; } @Nullable public String getSelectedSdkName() { final SdkComboBoxItem selectedItem = (SdkComboBoxItem)super.getSelectedItem(); if (selectedItem != null) { return selectedItem.getSdkName(); } return null; } @Nullable public String getSelectedModuleName() { final SdkComboBoxItem selectedItem = (SdkComboBoxItem)super.getSelectedItem(); if (selectedItem instanceof ModuleExtensionSdkComboBoxItem) { return ((ModuleExtensionSdkComboBoxItem)selectedItem).getModule().getName(); } else if (selectedItem instanceof InvalidModuleComboBoxItem) { return ((InvalidModuleComboBoxItem)selectedItem).getModuleName(); } return null; } public void setSelectedSdk(Sdk sdk) { final int index = indexOf(sdk); if (index >= 0) { setSelectedIndex(index); } } public void setSelectedModule(@NotNull String name) { final int index = indexOfModuleItems(name); if (index >= 0) { setSelectedIndex(index); } } public void setInvalidSdk(String name) { removeInvalidElement(); addItem(new InvalidSdkComboBoxItem(name)); setSelectedIndex(getModel().getSize() - 1); } public void addInvalidModuleItem(String name) { addItem(new InvalidModuleComboBoxItem(name)); } public void setSelectedNoneSdk() { if (getItemCount() > 0 && getItemAt(0) instanceof NullSdkComboBoxItem) { setSelectedIndex(0); } } public void setSelectedSdk(@Nullable String name) { if (name != null) { final SdkComboBoxModel model = (SdkComboBoxModel)getModel(); int itemCount = getItemCount(); for (int i = 0; i < itemCount; i++) { SdkComboBoxItem itemAt = model.getElementAt(i); String sdkName = itemAt.getSdkName(); if(name.equals(sdkName)) { setSelectedItem(itemAt); return; } } setInvalidSdk(name); } else { if (getItemCount() > 0 && getItemAt(0) instanceof NullSdkComboBoxItem) { setSelectedIndex(0); } else { setInvalidSdk("null"); } } } private int indexOf(Sdk sdk) { final SdkComboBoxModel model = (SdkComboBoxModel)getModel(); final int count = model.getSize(); for (int idx = 0; idx < count; idx++) { final SdkComboBoxItem elementAt = model.getElementAt(idx); if (sdk == null) { if (elementAt instanceof NullSdkComboBoxItem || elementAt instanceof ModuleExtensionSdkComboBoxItem) { return idx; } } else { Sdk elementAtSdk = elementAt.getSdk(); if (elementAtSdk != null && sdk.getName().equals(elementAtSdk.getName())) { return idx; } } } return -1; } private int indexOfModuleItems(String moduleName) { final SdkComboBoxModel model = (SdkComboBoxModel)getModel(); final int count = model.getSize(); for (int idx = 0; idx < count; idx++) { final SdkComboBoxItem elementAt = model.getElementAt(idx); if (elementAt instanceof ModuleExtensionSdkComboBoxItem) { final String name = ((ModuleExtensionSdkComboBoxItem)elementAt).getModule().getName(); if (name.equals(moduleName)) { return idx; } } else if (elementAt instanceof InvalidModuleComboBoxItem) { if (((InvalidModuleComboBoxItem)elementAt).getModuleName().equals(moduleName)) { return idx; } } } return -1; } private void removeInvalidElement() { final SdkComboBoxModel model = (SdkComboBoxModel)getModel(); final int count = model.getSize(); for (int idx = 0; idx < count; idx++) { final SdkComboBoxItem elementAt = model.getElementAt(idx); if (elementAt instanceof InvalidSdkComboBoxItem) { removeItemAt(idx); break; } } } public void reloadModel(SdkComboBoxItem firstItem, @Nullable Project project) { final DefaultComboBoxModel model = ((DefaultComboBoxModel)getModel()); if (project == null) { model.addElement(firstItem); return; } model.removeAllElements(); model.addElement(firstItem); final ProjectSdksModel projectSdksModel = ProjectStructureConfigurable.getInstance(project).getProjectSdksModel(); List<Sdk> sdks = new ArrayList<Sdk>(projectSdksModel.getProjectSdks().values()); if (myFilter != null) { sdks = ContainerUtil.filter(sdks, getSdkFilter(myFilter)); } Collections.sort(sdks, new Comparator<Sdk>() { @Override public int compare(final Sdk o1, final Sdk o2) { return o1.getName().compareToIgnoreCase(o2.getName()); } }); for (Sdk sdk : sdks) { model.addElement(new SdkComboBoxItem(sdk)); } } private static class SdkComboBoxModel extends DefaultComboBoxModel { public SdkComboBoxModel(@NotNull SdkModel sdksModel, @Nullable Condition<Sdk> sdkFilter, @Nullable String noneItemName) { Sdk[] sdks = sdksModel.getSdks(); if (sdkFilter != null) { final List<Sdk> filtered = ContainerUtil.filter(sdks, sdkFilter); sdks = filtered.toArray(new Sdk[filtered.size()]); } Arrays.sort(sdks, new Comparator<Sdk>() { @Override public int compare(final Sdk s1, final Sdk s2) { return s1.getName().compareToIgnoreCase(s2.getName()); } }); if (noneItemName != null) { addElement(new NullSdkComboBoxItem()); } for (Sdk sdk : sdks) { addElement(new SdkComboBoxItem(sdk)); } } // implements javax.swing.ListModel @Override public SdkComboBoxItem getElementAt(int index) { return (SdkComboBoxItem)super.getElementAt(index); } } private static Condition<Sdk> getSdkFilter(@Nullable final Condition<SdkTypeId> filter) { return filter == null ? Conditions.<Sdk>alwaysTrue() : new Condition<Sdk>() { @Override public boolean value(Sdk sdk) { return filter.value(sdk.getSdkType()); } }; } public static class SdkComboBoxItem { private final Sdk mySdk; public SdkComboBoxItem(@Nullable Sdk sdk) { mySdk = sdk; } public Sdk getSdk() { return mySdk; } @Nullable public String getSdkName() { return mySdk != null ? mySdk.getName() : null; } } public static class ModuleExtensionSdkComboBoxItem extends SdkComboBoxItem { private final ModuleExtension<?> myModuleExtension; private final MutableModuleInheritableNamedPointer<Sdk> mySdkPointer; public ModuleExtensionSdkComboBoxItem(ModuleExtension<?> moduleExtension, MutableModuleInheritableNamedPointer<Sdk> sdkPointer) { super(null); myModuleExtension = moduleExtension; mySdkPointer = sdkPointer; } @Override public Sdk getSdk() { return mySdkPointer.get(); } @Nullable @Override public String getSdkName() { return mySdkPointer.getName(); } @NotNull public Module getModule() { return myModuleExtension.getModule(); } } public static class CustomSdkComboBoxItem extends SdkComboBoxItem { private final String myKey; private final String myPresentableName; private final Icon myIcon; public CustomSdkComboBoxItem(String key, String presentableName, Icon icon) { super(null); myKey = key; myPresentableName = presentableName; myIcon = icon; } @NotNull public Icon getIcon() { return myIcon; } @NotNull public String getPresentableName() { return myPresentableName; } @Nullable @Override public String getSdkName() { return myKey; } } public static class InvalidModuleComboBoxItem extends SdkComboBoxItem { private final String myModuleName; public InvalidModuleComboBoxItem(String moduleName) { super(null); myModuleName = moduleName; } @NotNull public String getModuleName() { return myModuleName; } } public static class NullSdkComboBoxItem extends SdkComboBoxItem { public NullSdkComboBoxItem() { super(null); } } private static class InvalidSdkComboBoxItem extends SdkComboBoxItem { private final String mySdkName; public InvalidSdkComboBoxItem(String name) { super(null); mySdkName = name; } @Override public String getSdkName() { return mySdkName; } } }