/* * Copyright 2013-2016 consulo.io * * 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.classpath.dependencyTab; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.ex.FileSystemTreeImpl; import com.intellij.openapi.fileChooser.impl.FileChooserUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.impl.libraries.LibraryEx; import com.intellij.openapi.roots.impl.libraries.LibraryTableBase; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.roots.libraries.LibraryType; import com.intellij.openapi.roots.libraries.PersistentLibraryKind; import com.intellij.openapi.roots.libraries.ui.LibraryRootsComponentDescriptor; import com.intellij.openapi.roots.libraries.ui.OrderRoot; import com.intellij.openapi.roots.libraries.ui.impl.RootDetectionUtil; import com.intellij.openapi.roots.ui.configuration.classpath.ClasspathPanel; import com.intellij.openapi.roots.ui.configuration.libraries.LibraryEditingUtil; import com.intellij.openapi.roots.ui.configuration.libraryEditor.DefaultLibraryRootsComponentDescriptor; import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtil; import consulo.roots.ModifiableModuleRootLayer; import consulo.roots.types.BinariesOrderRootType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.*; /** * @author VISTALL * @since 27.09.14 */ public class FileOrDirectoryDependencyTabContext extends AddModuleDependencyTabContext { private final FileChooserDescriptor myFileChooserDescriptor; private FileSystemTreeImpl myFileSystemTree; private final HashMap<LibraryRootsComponentDescriptor, LibraryType> myLibraryTypes; private final DefaultLibraryRootsComponentDescriptor myDefaultDescriptor; public FileOrDirectoryDependencyTabContext(Disposable parent, ClasspathPanel panel, StructureConfigurableContext context) { super(panel, context); myLibraryTypes = new HashMap<LibraryRootsComponentDescriptor, LibraryType>(); myDefaultDescriptor = new DefaultLibraryRootsComponentDescriptor(); for (LibraryType<?> libraryType : LibraryEditingUtil.getSuitableTypes(myClasspathPanel)) { LibraryRootsComponentDescriptor descriptor = null; if (libraryType != null) { descriptor = libraryType.createLibraryRootsComponentDescriptor(); } if (descriptor == null) { descriptor = myDefaultDescriptor; } if (!myLibraryTypes.containsKey(descriptor)) { myLibraryTypes.put(descriptor, libraryType); } } Module module = myClasspathPanel.getRootModel().getModule(); myFileChooserDescriptor = createFileChooserDescriptor(); myFileSystemTree = new FileSystemTreeImpl(module.getProject(), myFileChooserDescriptor); Disposer.register(parent, myFileSystemTree); myFileSystemTree.showHiddens(true); final VirtualFile dirForSelect = ObjectUtil.chooseNotNull(module.getModuleDir(), module.getProject().getBaseDir()); if(dirForSelect != null) { myFileSystemTree.select(dirForSelect, new Runnable() { @Override public void run() { myFileSystemTree.expand(dirForSelect, null); } }); } } private FileChooserDescriptor createFileChooserDescriptor() { final FileChooserDescriptor chooserDescriptor; final List<Pair<LibraryRootsComponentDescriptor, FileChooserDescriptor>> descriptors = new ArrayList<Pair<LibraryRootsComponentDescriptor, FileChooserDescriptor>>(); for (LibraryRootsComponentDescriptor componentDescriptor : myLibraryTypes.keySet()) { descriptors.add(Pair.create(componentDescriptor, componentDescriptor.createAttachFilesChooserDescriptor(null))); } if (descriptors.size() == 1) { chooserDescriptor = descriptors.get(0).getSecond(); } else { chooserDescriptor = new FileChooserDescriptor(true, true, true, false, true, false) { @Override public boolean isFileSelectable(VirtualFile file) { for (Pair<LibraryRootsComponentDescriptor, FileChooserDescriptor> pair : descriptors) { if (pair.getSecond().isFileSelectable(file)) { return true; } } return false; } @Override public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) { for (Pair<LibraryRootsComponentDescriptor, FileChooserDescriptor> pair : descriptors) { if (pair.getSecond().isFileVisible(file, showHiddenFiles)) { return true; } } return false; } }; } chooserDescriptor.putUserData(LangDataKeys.MODULE_CONTEXT, myClasspathPanel.getRootModel().getModule()); return chooserDescriptor; } @Override public List<OrderEntry> createOrderEntries(@NotNull ModifiableModuleRootLayer layer, DialogWrapper dialogWrapper) { List<VirtualFile> chosenFiles = FileChooserUtil.getChosenFiles(myFileChooserDescriptor, Arrays.asList(myFileSystemTree.getSelectedFiles())); if (chosenFiles.isEmpty()) { return Collections.emptyList(); } final List<Pair<LibraryRootsComponentDescriptor, FileChooserDescriptor>> descriptors = new ArrayList<Pair<LibraryRootsComponentDescriptor, FileChooserDescriptor>>(); for (LibraryRootsComponentDescriptor componentDescriptor : myLibraryTypes.keySet()) { descriptors.add(Pair.create(componentDescriptor, componentDescriptor.createAttachFilesChooserDescriptor(null))); } List<LibraryRootsComponentDescriptor> suitableDescriptors = new ArrayList<LibraryRootsComponentDescriptor>(); for (Pair<LibraryRootsComponentDescriptor, FileChooserDescriptor> pair : descriptors) { if (acceptAll(pair.getSecond(), chosenFiles)) { suitableDescriptors.add(pair.getFirst()); } } final LibraryRootsComponentDescriptor rootsComponentDescriptor; LibraryType libraryType = null; if (suitableDescriptors.size() == 1) { rootsComponentDescriptor = suitableDescriptors.get(0); libraryType = myLibraryTypes.get(rootsComponentDescriptor); } else { rootsComponentDescriptor = myDefaultDescriptor; } List<OrderRoot> chosenRoots = RootDetectionUtil.detectRoots(chosenFiles, dialogWrapper.getRootPane(), layer.getProject(), rootsComponentDescriptor); final List<OrderRoot> roots = filterAlreadyAdded(layer, chosenRoots); if (roots.isEmpty()) { return Collections.emptyList(); } final List<Library> addedLibraries = new ArrayList<Library>(); boolean onlyClasses = true; for (OrderRoot root : roots) { onlyClasses &= root.getType() == BinariesOrderRootType.getInstance(); } if (onlyClasses) { for (OrderRoot root : roots) { addedLibraries.add(createLibraryFromRoots(layer, Collections.singletonList(root), libraryType)); } } else { addedLibraries.add(createLibraryFromRoots(layer, roots, libraryType)); } List<OrderEntry> orderEntries = new ArrayList<OrderEntry>(addedLibraries.size()); for (Library addedLibrary : addedLibraries) { LibraryOrderEntry libraryOrderEntry = layer.findLibraryOrderEntry(addedLibrary); if(libraryOrderEntry != null) { orderEntries.add(libraryOrderEntry); } } return orderEntries; } private Library createLibraryFromRoots(ModifiableModuleRootLayer layer, List<OrderRoot> roots, @Nullable final LibraryType libraryType) { final LibraryTable.ModifiableModel moduleLibraryModel = layer.getModuleLibraryTable().getModifiableModel(); final PersistentLibraryKind kind = libraryType == null ? null : libraryType.getKind(); final Library library = ((LibraryTableBase.ModifiableModelEx)moduleLibraryModel).createLibrary(null, kind); final LibraryEx.ModifiableModelEx libModel = (LibraryEx.ModifiableModelEx)library.getModifiableModel(); for (OrderRoot root : roots) { if (root.isJarDirectory()) { libModel.addJarDirectory(root.getFile(), false, root.getType()); } else { libModel.addRoot(root.getFile(), root.getType()); } } libModel.commit(); return library; } private List<OrderRoot> filterAlreadyAdded(ModifiableModuleRootLayer layer, final List<OrderRoot> roots) { if (roots == null || roots.isEmpty()) { return Collections.emptyList(); } final List<OrderRoot> result = new ArrayList<OrderRoot>(); final Library[] libraries = layer.getModuleLibraryTable().getLibraries(); for (OrderRoot root : roots) { if (!isIncluded(root, libraries)) { result.add(root); } } return result; } private static boolean isIncluded(OrderRoot root, Library[] libraries) { for (Library library : libraries) { if (ArrayUtil.contains(root.getFile(), library.getFiles(root.getType()))) { return true; } } return false; } private static boolean acceptAll(FileChooserDescriptor descriptor, Collection<VirtualFile> files) { for (VirtualFile file : files) { if (!descriptor.isFileSelectable(file) || !descriptor.isFileVisible(file, true)) { return false; } } return true; } @NotNull @Override public String getTabName() { return "File or directory"; } @NotNull @Override public JComponent getComponent() { return myFileSystemTree.getTree(); } }