Cleanup: NotNull/Nullable
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / libraryEditor / DefaultLibraryRootsComponentDescriptor.java
1 // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.roots.ui.configuration.libraryEditor;
3
4 import com.intellij.codeInsight.ExternalAnnotationsManager;
5 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
6 import com.intellij.openapi.fileChooser.FileElement;
7 import com.intellij.openapi.fileTypes.StdFileTypes;
8 import com.intellij.openapi.module.Module;
9 import com.intellij.openapi.progress.ProgressIndicator;
10 import com.intellij.openapi.project.ProjectBundle;
11 import com.intellij.openapi.projectRoots.ui.Util;
12 import com.intellij.openapi.roots.AnnotationOrderRootType;
13 import com.intellij.openapi.roots.JavadocOrderRootType;
14 import com.intellij.openapi.roots.NativeLibraryOrderRootType;
15 import com.intellij.openapi.roots.OrderRootType;
16 import com.intellij.openapi.roots.libraries.ui.*;
17 import com.intellij.openapi.roots.ui.OrderRootTypeUIFactory;
18 import com.intellij.openapi.roots.ui.configuration.LibrarySourceRootDetectorUtil;
19 import com.intellij.openapi.util.Condition;
20 import com.intellij.openapi.util.io.FileUtil;
21 import com.intellij.openapi.util.text.StringUtil;
22 import com.intellij.openapi.vfs.JarFileSystem;
23 import com.intellij.openapi.vfs.VfsUtilCore;
24 import com.intellij.openapi.vfs.VirtualFile;
25 import com.intellij.openapi.vfs.VirtualFileVisitor;
26 import com.intellij.util.IconUtil;
27 import com.intellij.util.containers.ContainerUtil;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
30
31 import javax.swing.*;
32 import java.util.*;
33
34 /**
35  * @author nik
36  */
37 public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponentDescriptor {
38   private static final Set<String> NATIVE_LIBRARY_EXTENSIONS = ContainerUtil.newTroveSet(FileUtil.PATH_HASHING_STRATEGY, "dll", "so", "dylib");
39
40   public static final Condition<VirtualFile> LIBRARY_ROOT_CONDITION = file -> FileElement.isArchive(file) || isNativeLibrary(file);
41
42   @Override
43   public OrderRootTypePresentation getRootTypePresentation(@NotNull OrderRootType type) {
44     return getDefaultPresentation(type);
45   }
46
47   @NotNull
48   @Override
49   public List<? extends AttachRootButtonDescriptor> createAttachButtons() {
50     return Collections.singletonList(new AttachUrlJavadocDescriptor());
51   }
52
53   @NotNull
54   @Override
55   public List<? extends RootDetector> getRootDetectors() {
56     List<RootDetector> results = new ArrayList<>();
57     results.add(new DescendentBasedRootFilter(OrderRootType.CLASSES, false, "classes",
58                                               file -> StdFileTypes.CLASS.equals(file.getFileType())
59                                                       //some libraries store native libraries inside their JAR files and unpack them dynamically so we should detect such JARs as classes roots
60                                                       || file.getFileSystem() instanceof JarFileSystem && isNativeLibrary(file)));
61     results.add(DescendentBasedRootFilter.createFileTypeBasedFilter(OrderRootType.CLASSES, true, StdFileTypes.CLASS, "jar directory"));
62     ContainerUtil.addAll(results, LibrarySourceRootDetectorUtil.JAVA_SOURCE_ROOT_DETECTOR.getExtensionList());
63     results.add(DescendentBasedRootFilter.createFileTypeBasedFilter(OrderRootType.SOURCES, true, StdFileTypes.JAVA, "source archive directory"));
64     results.add(new JavadocRootDetector());
65     results.add(new DescendentBasedRootFilter(AnnotationOrderRootType.getInstance(), false, "external annotations",
66                                               file -> ExternalAnnotationsManager.ANNOTATIONS_XML.equals(file.getName())));
67     results.add(new NativeLibraryRootFilter());
68     return results;
69   }
70
71   private static boolean isNativeLibrary(VirtualFile file) {
72     String extension = file.getExtension();
73     return extension != null && NATIVE_LIBRARY_EXTENSIONS.contains(extension);
74   }
75
76   @NotNull
77   @Override
78   public FileChooserDescriptor createAttachFilesChooserDescriptor(@Nullable String libraryName) {
79     final FileChooserDescriptor descriptor = new FileChooserDescriptor(true, true, true, false, true, true).withFileFilter(LIBRARY_ROOT_CONDITION);
80     descriptor.setTitle(StringUtil.isEmpty(libraryName) ? ProjectBundle.message("library.attach.files.action")
81                                                         : ProjectBundle.message("library.attach.files.to.library.action", libraryName));
82     descriptor.setDescription(ProjectBundle.message("library.java.attach.files.description"));
83     return descriptor;
84   }
85
86   public static OrderRootTypePresentation getDefaultPresentation(OrderRootType type) {
87     final OrderRootTypeUIFactory factory = OrderRootTypeUIFactory.FACTORY.getByKey(type);
88     return new OrderRootTypePresentation(factory.getNodeText(), factory.getIcon());
89   }
90
91   private static class JavadocRootDetector extends RootDetector {
92     private JavadocRootDetector() {
93       super(JavadocOrderRootType.getInstance(), false, "JavaDocs");
94     }
95
96     @NotNull
97     @Override
98     public Collection<VirtualFile> detectRoots(@NotNull VirtualFile rootCandidate, @NotNull ProgressIndicator progressIndicator) {
99       List<VirtualFile> result = new ArrayList<>();
100       collectJavadocRoots(rootCandidate, result, progressIndicator);
101       JavadocQuarantineStatusCleaner.cleanIfNeeded(VfsUtilCore.toVirtualFileArray(result));
102       return result;
103     }
104
105     private static void collectJavadocRoots(VirtualFile file, final List<VirtualFile> result, final ProgressIndicator progressIndicator) {
106       VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
107         @Override
108         public boolean visitFile(@NotNull VirtualFile file) {
109           progressIndicator.checkCanceled();
110           //noinspection SpellCheckingInspection
111           if (file.isDirectory() && file.findChild("allclasses-frame.html") != null && file.findChild("allclasses-noframe.html") != null) {
112             result.add(file);
113             return false;
114           }
115           return true;
116         }
117       });
118     }
119   }
120
121   private static class NativeLibraryRootFilter extends RootDetector {
122     private NativeLibraryRootFilter() {
123       super(NativeLibraryOrderRootType.getInstance(), false, "native library location");
124     }
125
126     @NotNull
127     @Override
128     public Collection<VirtualFile> detectRoots(@NotNull VirtualFile rootCandidate, @NotNull ProgressIndicator progressIndicator) {
129       if (rootCandidate.isInLocalFileSystem()) {
130         if (rootCandidate.isDirectory()) {
131           for (VirtualFile file : rootCandidate.getChildren()) {
132             if (isNativeLibrary(file)) {
133               return Collections.singleton(rootCandidate);
134             }
135           }
136         }
137         else if (isNativeLibrary(rootCandidate)) {
138           return Collections.singleton(rootCandidate.getParent());
139         }
140       }
141       return Collections.emptyList();
142     }
143   }
144
145   private static class AttachUrlJavadocDescriptor extends AttachRootButtonDescriptor {
146     private AttachUrlJavadocDescriptor() {
147       super(JavadocOrderRootType.getInstance(), IconUtil.getAddLinkIcon(), ProjectBundle.message("module.libraries.javadoc.url.button"));
148     }
149
150     @Override
151     public VirtualFile[] selectFiles(@NotNull JComponent parent,
152                                      @Nullable VirtualFile initialSelection,
153                                      @Nullable Module contextModule,
154                                      @NotNull LibraryEditor libraryEditor) {
155       VirtualFile vFile = Util.showSpecifyJavadocUrlDialog(parent);
156       return vFile != null ? new VirtualFile[]{vFile} : VirtualFile.EMPTY_ARRAY;
157     }
158   }
159 }