/* * 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.openapi.projectRoots.impl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkAdditionalData; import com.intellij.openapi.projectRoots.SdkTable; import com.intellij.openapi.projectRoots.SdkType; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; /** * @author yole */ public class SdkConfigurationUtil { public static final String PREDEFINED_PREFIX = " (predefined)"; private SdkConfigurationUtil() { } private static FileChooserDescriptor createCompositeDescriptor(final SdkType... sdkTypes) { FileChooserDescriptor descriptor0 = sdkTypes[0].getHomeChooserDescriptor(); FileChooserDescriptor descriptor = new FileChooserDescriptor(descriptor0.isChooseFiles(), descriptor0.isChooseFolders(), descriptor0.isChooseJars(), descriptor0.isChooseJarsAsFiles(), descriptor0.isChooseJarContents(), descriptor0.isChooseMultiple()) { @Override public void validateSelectedFiles(final VirtualFile[] files) throws Exception { if (files.length > 0) { for (SdkType type : sdkTypes) { if (type.isValidSdkHome(files[0].getPath())) { return; } } } String message = files.length > 0 && files[0].isDirectory() ? ProjectBundle.message("sdk.configure.home.invalid.error", sdkTypes[0].getPresentableName()) : ProjectBundle.message("sdk.configure.home.file.invalid.error", sdkTypes[0].getPresentableName()); throw new Exception(message); } }; descriptor.setTitle(descriptor0.getTitle()); return descriptor; } public static void addSdk(@NotNull final Sdk sdk) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { SdkTable.getInstance().addSdk(sdk); } }); } public static void removeSdk(final Sdk sdk) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { SdkTable.getInstance().removeSdk(sdk); } }); } @Nullable public static Sdk setupSdk(final Sdk[] allSdks, final VirtualFile homeDir, final SdkType sdkType, final boolean silent, boolean predefined, @Nullable final SdkAdditionalData additionalData, @Nullable final String customSdkSuggestedName) { final SdkImpl sdk; try { String sdkPath = sdkType.sdkPath(homeDir); String sdkName = null; if (predefined) { sdkName = sdkType.getName() + PREDEFINED_PREFIX; } else { sdkName = customSdkSuggestedName == null ? createUniqueSdkName(sdkType, sdkPath, allSdks) : createUniqueSdkName(customSdkSuggestedName, allSdks); } sdk = new SdkImpl(sdkName, sdkType); sdk.setPredefined(predefined); if (additionalData != null) { // additional initialization. // E.g. some ruby sdks must be initialized before // setupSdkPaths() method invocation sdk.setSdkAdditionalData(additionalData); } sdk.setHomePath(sdkPath); sdkType.setupSdkPaths(sdk); } catch (Exception e) { if (!silent) { Messages.showErrorDialog("Error configuring SDK: " + e.getMessage() + ".\nPlease make sure that " + FileUtil.toSystemDependentName(homeDir.getPath()) + " is a valid home path for this SDK type.", "Error Configuring SDK"); } return null; } return sdk; } /** * Tries to create an SDK identified by path; if successful, add the SDK to the global SDK table. * * @param path identifies the SDK * @param sdkType * @param predefined * @return newly created SDK, or null. */ @Nullable public static Sdk createAndAddSDK(final String path, SdkType sdkType, boolean predefined) { VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() { @Override public VirtualFile compute() { return LocalFileSystem.getInstance().refreshAndFindFileByPath(path); } }); if (sdkHome != null) { final Sdk newSdk = setupSdk(SdkTable.getInstance().getAllSdks(), sdkHome, sdkType, true, predefined, null, null); if (newSdk != null) { addSdk(newSdk); } return newSdk; } return null; } public static String createUniqueSdkName(SdkType type, String home, final Sdk[] sdks) { return createUniqueSdkName(type.suggestSdkName(null, home), sdks); } public static String createUniqueSdkName(final String suggestedName, final Sdk[] sdks) { final Set<String> names = new HashSet<String>(); for (Sdk jdk : sdks) { names.add(jdk.getName()); } String newSdkName = suggestedName; int i = 0; while (names.contains(newSdkName)) { newSdkName = suggestedName + " (" + (++i) + ")"; } return newSdkName; } public static void selectSdkHome(final SdkType sdkType, @NotNull final Consumer<String> consumer) { final FileChooserDescriptor descriptor = sdkType.getHomeChooserDescriptor(); if (ApplicationManager.getApplication().isUnitTestMode()) { Sdk sdk = SdkTable.getInstance().findMostRecentSdkOfType(sdkType); if (sdk == null) throw new RuntimeException("No SDK of type " + sdkType + " found"); consumer.consume(sdk.getHomePath()); return; } FileChooser.chooseFiles(descriptor, null, getSuggestedSdkPath(sdkType), new Consumer<List<VirtualFile>>() { @Override public void consume(final List<VirtualFile> chosen) { final String path = chosen.get(0).getPath(); if (sdkType.isValidSdkHome(path)) { consumer.consume(path); return; } final String adjustedPath = sdkType.adjustSelectedSdkHome(path); if (sdkType.isValidSdkHome(adjustedPath)) { consumer.consume(adjustedPath); } } }); } @Nullable public static VirtualFile getSuggestedSdkPath(SdkType sdkType) { Collection<String> paths = sdkType.suggestHomePaths(); if(paths.isEmpty()) { return null; } for (String path : paths) { VirtualFile maybeSdkHomePath = LocalFileSystem.getInstance().findFileByPath(path); if(maybeSdkHomePath != null) { return maybeSdkHomePath; } } return null; } }