/* * Copyright 2000-2015 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.projectRoots; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import com.intellij.util.IconUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.*; public abstract class SdkType implements SdkTypeId { public static final ExtensionPointName<SdkType> EP_NAME = ExtensionPointName.create("com.intellij.sdkType"); public static final Comparator<Sdk> ALPHABETICAL_COMPARATOR = (sdk1, sdk2) -> StringUtil.compare(sdk1.getName(), sdk2.getName(), true); private final String myName; public SdkType(@NotNull String name) { myName = name; } /** * Returns a recommended starting path for a file chooser (where SDKs of this type are usually may be found), * or {@code null} if not applicable/no SDKs found. * <p/> * E.g. for Python SDK on Unix the method may return either {@code "/usr/bin"} or {@code "/usr/bin/python"} * (if there is only one Python interpreter installed on a host). */ @Nullable public abstract String suggestHomePath(); /** * Returns a list of all valid SDKs found on this host. * <p/> * E.g. for Python SDK on Unix the method may return {@code ["/usr/bin/python2", "/usr/bin/python3"]}. */ @NotNull public Collection<String> suggestHomePaths() { String home = suggestHomePath(); return home != null ? Collections.singletonList(home) : Collections.emptyList(); } /** * If a path selected in the file chooser is not a valid SDK home path, returns an adjusted version of the path that is again * checked for validity. * * @param homePath the path selected in the file chooser. * @return the path to be used as the SDK home. */ @NotNull public String adjustSelectedSdkHome(@NotNull String homePath) { return homePath; } public abstract boolean isValidSdkHome(String path); @Override @Nullable public String getVersionString(@NotNull Sdk sdk) { return getVersionString(sdk.getHomePath()); } @Nullable public String getVersionString(String sdkHome){ return null; } public abstract String suggestSdkName(String currentSdkName, String sdkHome); public void setupSdkPaths(@NotNull Sdk sdk) {} /** * Returns comparator which is used to order sdks in project or module settings combo boxes. * If different sdk types return the same comparator instance then they are sorted together. */ @NotNull public Comparator<Sdk> getComparator() { return ALPHABETICAL_COMPARATOR; } public boolean setupSdkPaths(@NotNull Sdk sdk, @NotNull SdkModel sdkModel) { setupSdkPaths(sdk); return true; } /** * @return Configurable object for the sdk's additional data or null if not applicable */ @Nullable public abstract AdditionalDataConfigurable createAdditionalDataConfigurable(@NotNull SdkModel sdkModel, @NotNull SdkModificator sdkModificator); @Nullable public SdkAdditionalData loadAdditionalData(Element additional) { return null; } @Override @Nullable public SdkAdditionalData loadAdditionalData(@NotNull Sdk currentSdk, Element additional) { return loadAdditionalData(additional); } @NotNull @Override public String getName() { return myName; } @NotNull public abstract String getPresentableName(); public Icon getIcon() { return null; } @NotNull public String getHelpTopic() { return "preferences.jdks"; } @NotNull public Icon getIconForAddAction() { return IconUtil.getAddIcon(); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof SdkType)) return false; final SdkType sdkType = (SdkType)o; if (!myName.equals(sdkType.myName)) return false; return true; } @Override public int hashCode() { return myName.hashCode(); } @Override public String toString() { return getName(); } @NotNull public FileChooserDescriptor getHomeChooserDescriptor() { final FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false) { @Override public void validateSelectedFiles(VirtualFile[] files) throws Exception { if (files.length != 0){ final String selectedPath = files[0].getPath(); boolean valid = isValidSdkHome(selectedPath); if (!valid){ valid = isValidSdkHome(adjustSelectedSdkHome(selectedPath)); if (!valid) { String message = files[0].isDirectory() ? ProjectBundle.message("sdk.configure.home.invalid.error", getPresentableName()) : ProjectBundle.message("sdk.configure.home.file.invalid.error", getPresentableName()); throw new Exception(message); } } } } }; descriptor.setTitle(ProjectBundle.message("sdk.configure.home.title", getPresentableName())); return descriptor; } @NotNull public String getHomeFieldLabel() { return ProjectBundle.message("sdk.configure.type.home.path", getPresentableName()); } @Nullable public String getDefaultDocumentationUrl(@NotNull final Sdk sdk) { return null; } @Nullable public String getDownloadSdkUrl() { return null; } @NotNull public static SdkType[] getAllTypes() { List<SdkType> allTypes = new ArrayList<>(); Collections.addAll(allTypes, ApplicationManager.getApplication().getComponents(SdkType.class)); Collections.addAll(allTypes, Extensions.getExtensions(EP_NAME)); return allTypes.toArray(new SdkType[allTypes.size()]); } @NotNull public static <T extends SdkType> T findInstance(@NotNull Class<T> sdkTypeClass) { for (SdkType sdkType : Extensions.getExtensions(EP_NAME)) { if (sdkTypeClass.equals(sdkType.getClass())) { //noinspection unchecked return (T)sdkType; } } assert false; return null; } public boolean isRootTypeApplicable(@NotNull OrderRootType type) { return true; } /** * If this method returns true, instead of showing the standard file path chooser when a new SDK of the type is created, * the {@link #showCustomCreateUI} method is called. * * @return true if the custom create UI is supported, false otherwise. * @since 12.0 */ public boolean supportsCustomCreateUI() { return false; } /** * Shows the custom SDK create UI based on selected SDK in parent component. The returned SDK needs to have the correct name and home path; * the framework will call setupSdkPaths() on the returned SDK. * * @param sdkModel the list of SDKs currently displayed in the configuration dialog. * @param parentComponent the parent component for showing the dialog. * @param selectedSdk current selected sdk in parentComponent * @param sdkCreatedCallback the callback to which the created SDK is passed. * @since 2017.1 */ public void showCustomCreateUI(@NotNull SdkModel sdkModel, @NotNull JComponent parentComponent, @Nullable Sdk selectedSdk, @NotNull Consumer<Sdk> sdkCreatedCallback) { showCustomCreateUI(sdkModel, parentComponent, sdkCreatedCallback); } /** * @deprecated Use {@link #showCustomCreateUI(SdkModel, JComponent, Sdk, Consumer)} method instead */ public void showCustomCreateUI(@NotNull SdkModel sdkModel, @NotNull JComponent parentComponent, @NotNull Consumer<Sdk> sdkCreatedCallback) { } /** * Checks if the home directory of the specified SDK is valid. By default, checks that the directory points to a valid local * path. Can be overridden for remote SDKs. * * @param sdk the SDK to validate the path for. * @return true if the home path is valid, false otherwise. * @since 12.1 */ public boolean sdkHasValidPath(@NotNull Sdk sdk) { VirtualFile homeDir = sdk.getHomeDirectory(); return homeDir != null && homeDir.isValid(); } public String sdkPath(@NotNull VirtualFile homePath) { return homePath.getPath(); } }