mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-164682 Removing sdk leads to exception
Rewritten SDK roots storage to use virtual file pointers to fix exceptions on load. Corresponding virtual file pointer's listener is used for informing ProjectRootManagerComponent of changed roots directly, eliminating need for all roots enumeration on each vfp change to determine if the "rootsChanged" event should be fired, which is good for performance.
This commit is contained in:
+42
-23
@@ -15,17 +15,20 @@
|
||||
*/
|
||||
package com.intellij.openapi.roots.ui.configuration.libraryEditor;
|
||||
|
||||
import com.intellij.ide.highlighter.ArchiveFileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.impl.libraries.JarDirectories;
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryImpl;
|
||||
import com.intellij.openapi.roots.libraries.LibraryProperties;
|
||||
import com.intellij.openapi.roots.libraries.LibraryType;
|
||||
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor;
|
||||
import com.intellij.openapi.vfs.impl.LightFilePointer;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -41,7 +44,8 @@ public class NewLibraryEditor extends LibraryEditorBase {
|
||||
private String myLibraryName;
|
||||
private final MultiMap<OrderRootType, LightFilePointer> myRoots;
|
||||
private final Set<LightFilePointer> myExcludedRoots;
|
||||
private final JarDirectories myJarDirectories = new JarDirectories();
|
||||
private final MultiMap<OrderRootType, String> myJarDirectoryUrls = new MultiMap<>();
|
||||
private final MultiMap<OrderRootType, String> myJarDirectoryRecursiveUrls = new MultiMap<>();
|
||||
private LibraryType myType;
|
||||
private LibraryProperties myProperties;
|
||||
private boolean myKeepInvalidUrls = true;
|
||||
@@ -57,10 +61,6 @@ public class NewLibraryEditor extends LibraryEditorBase {
|
||||
myExcludedRoots = new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
public boolean isKeepInvalidUrls() {
|
||||
return myKeepInvalidUrls;
|
||||
}
|
||||
|
||||
public void setKeepInvalidUrls(boolean keepInvalidUrls) {
|
||||
myKeepInvalidUrls = keepInvalidUrls;
|
||||
}
|
||||
@@ -122,8 +122,9 @@ public class NewLibraryEditor extends LibraryEditorBase {
|
||||
|
||||
if (file.isDirectory()) {
|
||||
final String url = file.getUrl();
|
||||
if (myJarDirectories.contains(rootType, url)) {
|
||||
LibraryImpl.collectJarFiles(file, result, myJarDirectories.isRecursive(rootType, url));
|
||||
if (isJarDirectory(url, rootType)) {
|
||||
boolean recursive = myJarDirectoryRecursiveUrls.get(rootType).contains(url);
|
||||
collectJarFiles(file, result, recursive);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -171,20 +172,15 @@ public class NewLibraryEditor extends LibraryEditorBase {
|
||||
@Override
|
||||
public void addJarDirectory(@NotNull final String url, boolean recursive, @NotNull OrderRootType rootType) {
|
||||
addRoot(url, rootType);
|
||||
myJarDirectories.add(rootType, url, recursive);
|
||||
(recursive ? myJarDirectoryRecursiveUrls : myJarDirectoryUrls).putValue(rootType, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRoot(@NotNull String url, @NotNull OrderRootType rootType) {
|
||||
myRoots.remove(rootType, new LightFilePointer(url));
|
||||
Iterator<LightFilePointer> iterator = myExcludedRoots.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
LightFilePointer pointer = iterator.next();
|
||||
if (!isUnderRoots(pointer.getUrl())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
myJarDirectories.remove(rootType, url);
|
||||
myExcludedRoots.removeIf(pointer -> !isUnderRoots(pointer.getUrl()));
|
||||
myJarDirectoryUrls.remove(rootType, url);
|
||||
myJarDirectoryRecursiveUrls.remove(rootType, url);
|
||||
}
|
||||
|
||||
private boolean isUnderRoots(@NotNull String url) {
|
||||
@@ -203,7 +199,7 @@ public class NewLibraryEditor extends LibraryEditorBase {
|
||||
|
||||
@Override
|
||||
public boolean isJarDirectory(@NotNull String url, @NotNull OrderRootType rootType) {
|
||||
return myJarDirectories.contains(rootType, url);
|
||||
return myJarDirectoryUrls.get(rootType).contains(url) || myJarDirectoryRecursiveUrls.get(rootType).contains(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,16 +243,39 @@ public class NewLibraryEditor extends LibraryEditorBase {
|
||||
// apply editor's state to the target container
|
||||
for (OrderRootType type : myRoots.keySet()) {
|
||||
for (LightFilePointer pointer : myRoots.get(type)) {
|
||||
if (!myJarDirectories.contains(type, pointer.getUrl())) {
|
||||
if (!isJarDirectory(pointer.getUrl(), type)) {
|
||||
addRoot.accept(pointer.getUrl(), type);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (OrderRootType type : myJarDirectories.getRootTypes()) {
|
||||
for (String url : myJarDirectories.getDirectories(type)) {
|
||||
addJarDir.accept(url, myJarDirectories.isRecursive(type, url), type);
|
||||
for (Map.Entry<OrderRootType, Collection<String>> entry : myJarDirectoryUrls.entrySet()) {
|
||||
OrderRootType type = entry.getKey();
|
||||
for (String url : entry.getValue()) {
|
||||
addJarDir.accept(url, false, type);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<OrderRootType, Collection<String>> entry : myJarDirectoryRecursiveUrls.entrySet()) {
|
||||
OrderRootType type = entry.getKey();
|
||||
for (String url : entry.getValue()) {
|
||||
addJarDir.accept(url, true, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void collectJarFiles(@NotNull VirtualFile dir, @NotNull List<VirtualFile> container, final boolean recursively) {
|
||||
VfsUtilCore.visitChildrenRecursively(dir, new VirtualFileVisitor(VirtualFileVisitor.SKIP_ROOT, recursively ? null : VirtualFileVisitor.ONE_LEVEL_DEEP) {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
if (!file.isDirectory() && FileTypeRegistry.getInstance().getFileTypeByFileName(file.getName()) == ArchiveFileType.INSTANCE) {
|
||||
VirtualFile jarRoot = StandardFileSystems.jar().findFileByPath(file.getPath() + URLUtil.JAR_SEPARATOR);
|
||||
if (jarRoot != null) {
|
||||
container.add(jarRoot);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2000-2017 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.
|
||||
package com.intellij.java.openapi.projectRoots;
|
||||
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.projectRoots.JavaSdk;
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable;
|
||||
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import org.jdom.Element;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ProjectJdkTest extends PlatformTestCase {
|
||||
public void testDoesntCrashOnJdkRootDisappearance() throws Exception {
|
||||
VirtualFile nDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(createTempDir("nroot", true));
|
||||
String nUrl = nDir.getUrl();
|
||||
ProjectJdkImpl jdk = WriteCommandAction.runWriteCommandAction(getProject(), (ThrowableComputable<ProjectJdkImpl, Exception>)()->{
|
||||
ProjectJdkImpl myJdk = (ProjectJdkImpl)ProjectJdkTable.getInstance().createSdk("my", JavaSdk.getInstance());
|
||||
Element element = JDOMUtil.load("<jdk version=\"2\">\n" +
|
||||
" <name value=\"1.8\" />\n" +
|
||||
" <type value=\"JavaSDK\" />\n" +
|
||||
" <version value=\"java version "1.8.0_152-ea"\" />\n" +
|
||||
" <homePath value=\"I:/Java/jdk1.8\" />\n" +
|
||||
" <roots>\n" +
|
||||
" <classPath>\n" +
|
||||
" <root type=\"composite\">\n" +
|
||||
" <root url=\"" + nUrl + "\" type=\"simple\" />\n" +
|
||||
" </root>\n" +
|
||||
" </classPath>\n" +
|
||||
" </roots>\n" +
|
||||
" <additional />\n" +
|
||||
" </jdk>\n"
|
||||
);
|
||||
myJdk.readExternal(element);
|
||||
return myJdk;
|
||||
});
|
||||
|
||||
try {
|
||||
List<String> urls = Arrays.stream(jdk.getRoots(OrderRootType.CLASSES)).peek(v -> assertTrue(v.isValid())).map(VirtualFile::getUrl).collect(Collectors.toList());
|
||||
assertOrderedEquals(urls, nUrl);
|
||||
|
||||
delete(nDir);
|
||||
assertFalse(nDir.isValid());
|
||||
|
||||
urls = Arrays.stream(jdk.getRoots(OrderRootType.CLASSES)).peek(v -> assertTrue(v.isValid())).map(VirtualFile::getUrl).collect(Collectors.toList());
|
||||
assertEmpty(urls);
|
||||
}
|
||||
finally {
|
||||
WriteCommandAction.runWriteCommandAction(getProject(), ()->ProjectJdkTable.getInstance().removeJdk(jdk));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,10 @@ import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.testFramework.ModuleTestCase;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.VfsTestUtil;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -215,9 +217,7 @@ public class RootsChangedTest extends ModuleTestCase {
|
||||
rootModelA.inheritSdk();
|
||||
rootModelB.inheritSdk();
|
||||
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
|
||||
if (rootModels.length > 0) {
|
||||
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
||||
}
|
||||
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
||||
assertEventsCount(1);
|
||||
|
||||
ProjectRootManager.getInstance(myProject).setProjectSdk(jdk);
|
||||
@@ -249,9 +249,7 @@ public class RootsChangedTest extends ModuleTestCase {
|
||||
rootModelA.addInvalidLibrary("Q", libraryTable.getTableLevel());
|
||||
rootModelB.addInvalidLibrary("Q", libraryTable.getTableLevel());
|
||||
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
|
||||
if (rootModels.length > 0) {
|
||||
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
||||
}
|
||||
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
||||
assertEventsCount(1);
|
||||
|
||||
final Library.ModifiableModel libraryModifiableModel2 = libraryA.getModifiableModel();
|
||||
@@ -318,9 +316,7 @@ public class RootsChangedTest extends ModuleTestCase {
|
||||
assertEventsCount(0);
|
||||
|
||||
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
|
||||
if (rootModels.length > 0) {
|
||||
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
||||
}
|
||||
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
||||
assertEventsCount(1);
|
||||
|
||||
libraryTable.removeLibrary(libraryQ);
|
||||
@@ -355,4 +351,21 @@ public class RootsChangedTest extends ModuleTestCase {
|
||||
afterCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void testRootsChangedPerformanceInPresenceOfManyVirtualFilePointers() throws Exception {
|
||||
VirtualFile temp = LocalFileSystem.getInstance().findFileByIoFile(createTempDirectory());
|
||||
String dirName = "xxx";
|
||||
for (int i = 0; i < 10_000; i++) {
|
||||
VirtualFilePointerManager.getInstance().create(temp.getUrl() + "/" + dirName + "/" + i, getTestRootDisposable(), null);
|
||||
}
|
||||
|
||||
VirtualFile xxx = createChildDirectory(temp, dirName);
|
||||
|
||||
PlatformTestUtil.startPerformanceTest("time wasted in ProjectRootManagerComponent.before/afterValidityChanged()", 10000, ()->{
|
||||
for (int i = 0; i < 100; i++) {
|
||||
rename(xxx, "yyy");
|
||||
rename(xxx, dirName);
|
||||
}
|
||||
}).assertTiming();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,22 +226,21 @@ public class LibraryTest extends ModuleRootManagerTestCase {
|
||||
Library library = WriteAction.compute(() -> table.createLibrary("jarDirs"));
|
||||
Library.ModifiableModel model = library.getModifiableModel();
|
||||
model.addJarDirectory("file://jar-dir", false, OrderRootType.CLASSES);
|
||||
model.addJarDirectory("file://jar-dir-rec", true, OrderRootType.CLASSES);
|
||||
model.addJarDirectory("file://jar-dir-src", false, OrderRootType.SOURCES);
|
||||
commit(model);
|
||||
|
||||
assertThat(serialize(library)).isEqualTo("<root>\n" +
|
||||
" <library name=\"jarDirs\">\n" +
|
||||
" <CLASSES>\n" +
|
||||
" <root url=\"file://jar-dir\" />\n" +
|
||||
" </CLASSES>\n" +
|
||||
" <CLASSES />\n" +
|
||||
" <JAVADOC />\n" +
|
||||
" <SOURCES>\n" +
|
||||
" <root url=\"file://jar-dir-src\" />\n" +
|
||||
" </SOURCES>\n" +
|
||||
" <SOURCES />\n" +
|
||||
" <jarDirectory url=\"file://jar-dir\" recursive=\"false\" />\n" +
|
||||
" <jarDirectory url=\"file://jar-dir-rec\" recursive=\"true\" />\n" +
|
||||
" <jarDirectory url=\"file://jar-dir-src\" recursive=\"false\" type=\"SOURCES\" />\n" +
|
||||
" </library>\n" +
|
||||
"</root>");
|
||||
"</root>"
|
||||
);
|
||||
}
|
||||
|
||||
private static Element serialize(Library library) {
|
||||
|
||||
+2
-2
@@ -67,9 +67,9 @@ public interface VirtualFilePointerContainer {
|
||||
* </myroot>
|
||||
* }</pre>
|
||||
*/
|
||||
void readExternal(@NotNull Element rootChild, @NotNull String childElementName) throws InvalidDataException;
|
||||
void readExternal(@NotNull Element rootChild, @NotNull String childElementName, boolean externalizeJarDirectories) throws InvalidDataException;
|
||||
|
||||
void writeExternal(@NotNull Element element, @NotNull String childElementName);
|
||||
void writeExternal(@NotNull Element element, @NotNull String childElementName, boolean externalizeJarDirectories);
|
||||
|
||||
void moveUp(@NotNull String url);
|
||||
|
||||
|
||||
+53
-20
@@ -21,10 +21,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TraceableDisposable;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
@@ -35,6 +32,7 @@ import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ConcurrentList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import org.jdom.Element;
|
||||
@@ -44,24 +42,28 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author dsl
|
||||
*/
|
||||
class VirtualFilePointerContainerImpl extends TraceableDisposable implements VirtualFilePointerContainer, Disposable {
|
||||
public class VirtualFilePointerContainerImpl extends TraceableDisposable implements VirtualFilePointerContainer, Disposable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer");
|
||||
@NotNull private final List<VirtualFilePointer> myList = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
@NotNull private final List<VirtualFilePointer> myJarDirectories = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
@NotNull private final List<VirtualFilePointer> myJarRecursiveDirectories = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
@NotNull private final ConcurrentList<VirtualFilePointer> myList = ContainerUtil.createConcurrentList();
|
||||
@NotNull private final ConcurrentList<VirtualFilePointer> myJarDirectories = ContainerUtil.createConcurrentList();
|
||||
@NotNull private final ConcurrentList<VirtualFilePointer> myJarRecursiveDirectories = ContainerUtil.createConcurrentList();
|
||||
@NotNull private final VirtualFilePointerManager myVirtualFilePointerManager;
|
||||
@NotNull private final Disposable myParent;
|
||||
private final VirtualFilePointerListener myListener;
|
||||
private volatile Trinity<String[], VirtualFile[], VirtualFile[]> myCachedThings;
|
||||
private volatile long myTimeStampOfCachedThings = -1;
|
||||
@NonNls private static final String URL_ATTR = "url";
|
||||
@NonNls public static final String URL_ATTR = "url";
|
||||
private boolean myDisposed;
|
||||
private static final boolean TRACE_CREATION = LOG.isDebugEnabled() || ApplicationManager.getApplication().isUnitTestMode();
|
||||
@NonNls public static final String JAR_DIRECTORY_ELEMENT = "jarDirectory";
|
||||
@NonNls public static final String RECURSIVE_ATTR = "recursive";
|
||||
|
||||
VirtualFilePointerContainerImpl(@NotNull VirtualFilePointerManager manager,
|
||||
@NotNull Disposable parentDisposable,
|
||||
@Nullable VirtualFilePointerListener listener) {
|
||||
@@ -72,23 +74,52 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(@NotNull final Element rootChild, @NotNull final String childName) throws InvalidDataException {
|
||||
public void readExternal(@NotNull final Element rootChild, @NotNull final String childName, boolean externalizeJarDirectories) throws InvalidDataException {
|
||||
final List<Element> urls = rootChild.getChildren(childName);
|
||||
for (Element url : urls) {
|
||||
final String urlAttribute = url.getAttributeValue(URL_ATTR);
|
||||
if (urlAttribute == null) throw new InvalidDataException("path element without url");
|
||||
add(urlAttribute);
|
||||
}
|
||||
if (externalizeJarDirectories) {
|
||||
List<Element> jarDirs = rootChild.getChildren(JAR_DIRECTORY_ELEMENT);
|
||||
for (Element jarDir : jarDirs) {
|
||||
String url = jarDir.getAttributeValue(URL_ATTR);
|
||||
if (url == null) throw new InvalidDataException("path element without url: " + JDOMUtil.getValue(jarDir));
|
||||
boolean recursive = Boolean.valueOf(jarDir.getAttributeValue(RECURSIVE_ATTR, "false"));
|
||||
addJarDirectory(url, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(@NotNull final Element element, @NotNull final String childElementName) {
|
||||
public void writeExternal(@NotNull final Element element, @NotNull final String childElementName, boolean externalizeJarDirectories) {
|
||||
for (VirtualFilePointer pointer : myList) {
|
||||
String url = pointer.getUrl();
|
||||
final Element rootPathElement = new Element(childElementName);
|
||||
rootPathElement.setAttribute(URL_ATTR, url);
|
||||
element.addContent(rootPathElement);
|
||||
}
|
||||
if (externalizeJarDirectories) {
|
||||
List<VirtualFilePointer> jarDirectories = new ArrayList<>(myJarDirectories);
|
||||
Collections.sort(jarDirectories, Comparator.comparing(VirtualFilePointer::getUrl, String.CASE_INSENSITIVE_ORDER));
|
||||
List<VirtualFilePointer> jarRecursiveDirectories = new ArrayList<>(myJarRecursiveDirectories);
|
||||
Collections.sort(jarRecursiveDirectories, Comparator.comparing(VirtualFilePointer::getUrl, String.CASE_INSENSITIVE_ORDER));
|
||||
for (VirtualFilePointer pointer : jarDirectories) {
|
||||
String url = pointer.getUrl();
|
||||
final Element jarDirElement = new Element(JAR_DIRECTORY_ELEMENT);
|
||||
jarDirElement.setAttribute(URL_ATTR, url);
|
||||
jarDirElement.setAttribute(RECURSIVE_ATTR, Boolean.toString(false));
|
||||
element.addContent(jarDirElement);
|
||||
}
|
||||
for (VirtualFilePointer pointer : jarRecursiveDirectories) {
|
||||
String url = pointer.getUrl();
|
||||
final Element jarDirElement = new Element(JAR_DIRECTORY_ELEMENT);
|
||||
jarDirElement.setAttribute(URL_ATTR, url);
|
||||
jarDirElement.setAttribute(RECURSIVE_ATTR, Boolean.toString(true));
|
||||
element.addContent(jarDirElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,14 +158,14 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
public void add(@NotNull VirtualFile file) {
|
||||
assert !myDisposed;
|
||||
dropCaches();
|
||||
myList.add(create(file));
|
||||
myList.addIfAbsent(create(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(@NotNull String url) {
|
||||
assert !myDisposed;
|
||||
dropCaches();
|
||||
myList.add(create(url));
|
||||
myList.addIfAbsent(create(url));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,7 +189,7 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
dropCaches();
|
||||
|
||||
for (final VirtualFilePointer pointer : that.getList()) {
|
||||
myList.add(duplicate(pointer));
|
||||
myList.addIfAbsent(duplicate(pointer));
|
||||
}
|
||||
for (VirtualFilePointer jarDirectory : ((VirtualFilePointerContainerImpl)that).myJarDirectories) {
|
||||
myJarDirectories.add(duplicate(jarDirectory));
|
||||
@@ -218,13 +249,14 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
for (VirtualFilePointer jarDirectoryPtr : myJarDirectories) {
|
||||
VirtualFile jarDirectory = jarDirectoryPtr.getFile();
|
||||
if (jarDirectory != null) {
|
||||
cachedUrls.add(jarDirectory.getUrl());
|
||||
VirtualFile[] children = jarDirectory.getChildren();
|
||||
for (VirtualFile file : children) {
|
||||
if (!file.isDirectory() && FileTypeRegistry.getInstance().getFileTypeByFileName(file.getName()) == ArchiveFileType.INSTANCE) {
|
||||
VirtualFile jarRoot = StandardFileSystems.jar().findFileByPath(file.getPath() + URLUtil.JAR_SEPARATOR);
|
||||
if (jarRoot != null) {
|
||||
cachedFiles.add(jarRoot);
|
||||
cachedDirectories.add(file);
|
||||
cachedDirectories.add(jarRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,6 +265,7 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
for (VirtualFilePointer jarDirectoryPtr : myJarRecursiveDirectories) {
|
||||
VirtualFile jarDirectory = jarDirectoryPtr.getFile();
|
||||
if (jarDirectory != null) {
|
||||
cachedUrls.add(jarDirectory.getUrl());
|
||||
VfsUtilCore.visitChildrenRecursively(jarDirectory, new VirtualFileVisitor() {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
@@ -240,7 +273,7 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
VirtualFile jarRoot = StandardFileSystems.jar().findFileByPath(file.getPath() + URLUtil.JAR_SEPARATOR);
|
||||
if (jarRoot != null) {
|
||||
cachedFiles.add(jarRoot);
|
||||
cachedDirectories.add(file);
|
||||
cachedDirectories.add(jarRoot);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -365,16 +398,16 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
@Override
|
||||
public void addJarDirectory(@NotNull String directoryUrl, boolean recursively) {
|
||||
VirtualFilePointer pointer = myVirtualFilePointerManager.createDirectoryPointer(directoryUrl, recursively, myParent, myListener);
|
||||
(recursively ? myJarRecursiveDirectories : myJarDirectories).add(pointer);
|
||||
(recursively ? myJarRecursiveDirectories : myJarDirectories).addIfAbsent(pointer);
|
||||
dropCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeJarDirectory(@NotNull String directoryUrl) {
|
||||
dropCaches();
|
||||
//noinspection NonShortCircuitBooleanExpression
|
||||
return myJarDirectories.removeIf(ptr-> FileUtil.pathsEqual(ptr.getUrl(), directoryUrl))
|
||||
| myJarRecursiveDirectories.removeIf(ptr-> FileUtil.pathsEqual(ptr.getUrl(), directoryUrl));
|
||||
boolean removed1 = myJarDirectories.removeIf(ptr -> FileUtil.pathsEqual(ptr.getUrl(), directoryUrl));
|
||||
boolean removed2 = myJarRecursiveDirectories.removeIf(ptr -> FileUtil.pathsEqual(ptr.getUrl(), directoryUrl));
|
||||
return removed1 || removed2;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.projectRoots.impl;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.components.*;
|
||||
@@ -23,6 +24,7 @@ import com.intellij.openapi.fileTypes.FileTypes;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.projectRoots.*;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
@@ -206,6 +208,9 @@ public class ProjectJdkTableImpl extends ProjectJdkTable implements ExportableCo
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
myMessageBus.syncPublisher(JDK_TABLE_TOPIC).jdkRemoved(jdk);
|
||||
mySdks.remove(jdk);
|
||||
if (jdk instanceof Disposable) {
|
||||
Disposer.dispose((Disposable)jdk);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+34
-37
@@ -37,16 +37,16 @@ import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.WatchedRootsProvider;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.vfs.ex.VirtualFileManagerAdapter;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.project.ProjectKt;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
@@ -74,6 +74,7 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
|
||||
private Set<LocalFileSystem.WatchRequest> myRootsToWatch = new THashSet<>();
|
||||
private final boolean myDoLogCachesUpdate;
|
||||
private Disposable myRootPointersDisposable = Disposer.newDisposable(); // accessed in EDT
|
||||
|
||||
public ProjectRootManagerComponent(Project project, StartupManager startupManager) {
|
||||
super(project);
|
||||
@@ -116,7 +117,6 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
}
|
||||
};
|
||||
|
||||
myConnection.subscribe(VirtualFilePointerListener.TOPIC, new MyVirtualFilePointerListener());
|
||||
myDoLogCachesUpdate = ApplicationManager.getApplication().isInternal() && !ApplicationManager.getApplication().isUnitTestMode();
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
|
||||
@Override
|
||||
protected void addRootsToWatch() {
|
||||
final Pair<Set<String>, Set<String>> roots = getAllRoots(false);
|
||||
final Pair<Set<String>, Set<String>> roots = getAllRoots();
|
||||
if (roots == null) return;
|
||||
myRootsToWatch = LocalFileSystem.getInstance().replaceWatchedRoots(myRootsToWatch, roots.first, roots.second);
|
||||
}
|
||||
@@ -168,18 +168,6 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
}
|
||||
}
|
||||
|
||||
private boolean affectsRoots(@NotNull VirtualFilePointer[] pointers) {
|
||||
Pair<Set<String>, Set<String>> roots = getAllRoots(true);
|
||||
if (roots == null) return false;
|
||||
|
||||
for (VirtualFilePointer pointer : pointers) {
|
||||
String path = extractLocalPath(pointer.getUrl());
|
||||
if (roots.first.contains(path) || roots.second.contains(path)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fireBeforeRootsChangeEvent(boolean fileTypes) {
|
||||
isFiringEvent = true;
|
||||
@@ -207,7 +195,8 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<Set<String>, Set<String>> getAllRoots(boolean includeSourceRoots) {
|
||||
private Pair<Set<String>, Set<String>> getAllRoots() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (myProject.isDefault()) return null;
|
||||
|
||||
final Set<String> recursive = new THashSet<>(FileUtil.PATH_HASHING_STRATEGY);
|
||||
@@ -232,12 +221,22 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
recursive.addAll(extension.getRootsToWatch());
|
||||
}
|
||||
|
||||
addRootsFromModules(includeSourceRoots, recursive, flat);
|
||||
Disposable oldDisposable = myRootPointersDisposable;
|
||||
myRootPointersDisposable = Disposer.newDisposable();
|
||||
Disposer.register(this, myRootPointersDisposable);
|
||||
// create container with these urls with the sole purpose to get events to getRootsValidityChangedListener() when these roots change
|
||||
VirtualFilePointerContainer container = VirtualFilePointerManager.getInstance().createContainer(myRootPointersDisposable, getRootsValidityChangedListener());
|
||||
recursive.forEach(path -> container.addJarDirectory(VfsUtilCore.pathToUrl(path), true));
|
||||
flat.forEach(path -> container.add(VfsUtilCore.pathToUrl(path)));
|
||||
|
||||
Disposer.dispose(oldDisposable); // dispose after the re-creating container to keep virtual file pointers from disposing and re-creating back
|
||||
|
||||
// module roots already fire validity change events
|
||||
addRootsFromModulesTo(recursive, flat);
|
||||
return Pair.create(recursive, flat);
|
||||
}
|
||||
|
||||
private void addRootsFromModules(boolean includeSourceRoots, Set<String> recursive, Set<String> flat) {
|
||||
private void addRootsFromModulesTo(@NotNull Set<String> recursive, @NotNull Set<String> flat) {
|
||||
Set<String> urls = ContainerUtil.newTroveSet(FileUtil.PATH_HASHING_STRATEGY);
|
||||
|
||||
for (Module module : ModuleManager.getInstance(myProject).getModules()) {
|
||||
@@ -245,10 +244,6 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
|
||||
ContainerUtil.addAll(urls, rootManager.getContentRootUrls());
|
||||
|
||||
if (includeSourceRoots) {
|
||||
ContainerUtil.addAll(urls, rootManager.getSourceRootUrls());
|
||||
}
|
||||
|
||||
rootManager.orderEntries().withoutModuleSourceEntries().withoutDepModules().forEach(entry -> {
|
||||
for (OrderRootType type : OrderRootType.getAllTypes()) {
|
||||
ContainerUtil.addAll(urls, entry.getUrls(type));
|
||||
@@ -302,7 +297,7 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
@Override
|
||||
public void markRootsForRefresh() {
|
||||
Set<String> paths = ContainerUtil.newTroveSet(FileUtil.PATH_HASHING_STRATEGY);
|
||||
addRootsFromModules(false, paths, paths);
|
||||
addRootsFromModulesTo(paths, paths);
|
||||
|
||||
LocalFileSystem fs = LocalFileSystem.getInstance();
|
||||
for (String path : paths) {
|
||||
@@ -339,7 +334,7 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
}
|
||||
}
|
||||
|
||||
private class MyVirtualFilePointerListener implements VirtualFilePointerListener {
|
||||
private final VirtualFilePointerListener myRootsChangedListener = new VirtualFilePointerListener() {
|
||||
@Override
|
||||
public void beforeValidityChanged(@NotNull VirtualFilePointer[] pointers) {
|
||||
if (myProject.isDisposed()) {
|
||||
@@ -347,18 +342,14 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
}
|
||||
|
||||
if (myInsideRefresh == 0) {
|
||||
if (affectsRoots(pointers)) {
|
||||
beforeRootsChange(false);
|
||||
if (myDoLogCachesUpdate) LOG.debug(new Throwable(pointers.length > 0 ? pointers[0].getPresentableUrl():""));
|
||||
}
|
||||
beforeRootsChange(false);
|
||||
if (myDoLogCachesUpdate) LOG.debug(new Throwable(pointers.length > 0 ? pointers[0].getPresentableUrl():""));
|
||||
}
|
||||
else if (!myPointerChangesDetected) {
|
||||
//this is the first pointer changing validity
|
||||
if (affectsRoots(pointers)) {
|
||||
myPointerChangesDetected = true;
|
||||
myProject.getMessageBus().syncPublisher(ProjectTopics.PROJECT_ROOTS).beforeRootsChange(new ModuleRootEventImpl(myProject, false));
|
||||
if (myDoLogCachesUpdate) LOG.debug(new Throwable(pointers.length > 0 ? pointers[0].getPresentableUrl():""));
|
||||
}
|
||||
myPointerChangesDetected = true;
|
||||
myProject.getMessageBus().syncPublisher(ProjectTopics.PROJECT_ROOTS).beforeRootsChange(new ModuleRootEventImpl(myProject, false));
|
||||
if (myDoLogCachesUpdate) LOG.debug(new Throwable(pointers.length > 0 ? pointers[0].getPresentableUrl():""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,9 +362,15 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
|
||||
if (myInsideRefresh > 0) {
|
||||
clearScopesCaches();
|
||||
}
|
||||
else if (affectsRoots(pointers)) {
|
||||
else {
|
||||
rootsChanged(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VirtualFilePointerListener getRootsValidityChangedListener() {
|
||||
return myRootsChangedListener;
|
||||
}
|
||||
}
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* 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.roots.impl.libraries;
|
||||
|
||||
import com.intellij.openapi.roots.impl.RootProviderBaseImpl;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class JarDirectoryWatcherFactoryImpl extends JarDirectoryWatcherFactory {
|
||||
@Override
|
||||
public JarDirectoryWatcher createWatcher(JarDirectories jarDirectories, RootProviderBaseImpl rootProvider) {
|
||||
return new JarDirectoryWatcherImpl(jarDirectories, rootProvider);
|
||||
}
|
||||
}
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.roots.impl.libraries;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.impl.RootProviderBaseImpl;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
|
||||
import com.intellij.openapi.vfs.newvfs.events.*;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author ksafonov
|
||||
*/
|
||||
public class JarDirectoryWatcherImpl implements JarDirectoryWatcher {
|
||||
private final JarDirectories myJarDirectories;
|
||||
private final RootProviderBaseImpl myRootProvider;
|
||||
private MessageBusConnection myBusConnection = null;
|
||||
private Collection<LocalFileSystem.WatchRequest> myWatchRequests = Collections.emptySet();
|
||||
|
||||
public JarDirectoryWatcherImpl(JarDirectories jarDirectories, RootProviderBaseImpl rootProvider) {
|
||||
myJarDirectories = jarDirectories;
|
||||
myRootProvider = rootProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWatchedRoots() {
|
||||
final LocalFileSystem fs = LocalFileSystem.getInstance();
|
||||
if (!myJarDirectories.isEmpty()) {
|
||||
final Set<String> recursiveRoots = new HashSet<>();
|
||||
final Set<String> flatRoots = new HashSet<>();
|
||||
final VirtualFileManager fm = VirtualFileManager.getInstance();
|
||||
for (OrderRootType rootType : myJarDirectories.getRootTypes()) {
|
||||
for (String url : myJarDirectories.getDirectories(rootType)) {
|
||||
if (fm.getFileSystem(VirtualFileManager.extractProtocol(url)) instanceof LocalFileSystem) {
|
||||
final boolean watchRecursively = myJarDirectories.isRecursive(rootType, url);
|
||||
final String path = VirtualFileManager.extractPath(url);
|
||||
(watchRecursively ? recursiveRoots : flatRoots).add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myWatchRequests = fs.replaceWatchedRoots(myWatchRequests, recursiveRoots, flatRoots);
|
||||
|
||||
if (myBusConnection == null) {
|
||||
myBusConnection = ApplicationManager.getApplication().getMessageBus().connect();
|
||||
myBusConnection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
|
||||
@Override
|
||||
public void after(@NotNull final List<? extends VFileEvent> events) {
|
||||
boolean changesDetected = false;
|
||||
for (VFileEvent event : events) {
|
||||
if (event instanceof VFileCopyEvent) {
|
||||
final VFileCopyEvent copyEvent = (VFileCopyEvent)event;
|
||||
final VirtualFile file = copyEvent.getFile();
|
||||
if (isUnderJarDirectory(copyEvent.getNewParent().getUrl() + "/" + copyEvent.getNewChildName()) ||
|
||||
isUnderJarDirectory(file.getUrl())) {
|
||||
changesDetected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event instanceof VFileMoveEvent) {
|
||||
final VFileMoveEvent moveEvent = (VFileMoveEvent)event;
|
||||
final VirtualFile file = moveEvent.getFile();
|
||||
if (isUnderJarDirectory(file.getUrl()) || isUnderJarDirectory(moveEvent.getOldParent().getUrl() + "/" + file.getName())) {
|
||||
changesDetected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event instanceof VFileDeleteEvent) {
|
||||
final VFileDeleteEvent deleteEvent = (VFileDeleteEvent)event;
|
||||
if (isUnderJarDirectory(deleteEvent.getFile().getUrl())) {
|
||||
changesDetected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event instanceof VFileCreateEvent) {
|
||||
final VFileCreateEvent createEvent = (VFileCreateEvent)event;
|
||||
if (isUnderJarDirectory(createEvent.getParent().getUrl() + "/" + createEvent.getChildName())) {
|
||||
changesDetected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changesDetected) {
|
||||
fireRootSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUnderJarDirectory(String url) {
|
||||
for (String rootUrl : myJarDirectories.getAllDirectories()) {
|
||||
if (FileUtil.startsWith(url, rootUrl)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
protected void fireRootSetChanged() {
|
||||
myRootProvider.fireRootSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
if (!myWatchRequests.isEmpty()) {
|
||||
LocalFileSystem.getInstance().removeWatchedRoots(myWatchRequests);
|
||||
myWatchRequests = Collections.emptySet();
|
||||
}
|
||||
|
||||
final MessageBusConnection connection = myBusConnection;
|
||||
if (connection != null) {
|
||||
myBusConnection = null;
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ class FilePointerPartNode {
|
||||
boolean separator,
|
||||
@NotNull CharSequence childName, int childStart, int childEnd,
|
||||
@NotNull FilePointerPartNode[] outNode,
|
||||
@NotNull List<FilePointerPartNode> outDirs) {
|
||||
@Nullable List<FilePointerPartNode> outDirs) {
|
||||
int partStart;
|
||||
if (parent == null) {
|
||||
partStart = 0;
|
||||
@@ -110,7 +110,8 @@ class FilePointerPartNode {
|
||||
if (partStart + index-childStart == found.part.length()) {
|
||||
// go to children
|
||||
for (FilePointerPartNode child : found.children) {
|
||||
int childPos = child.position(null, null, childSeparator, childName, index, childEnd, outNode, outDirs);
|
||||
// do not accidentally modify outDirs
|
||||
int childPos = child.position(null, null, childSeparator, childName, index, childEnd, outNode, null);
|
||||
if (childPos != -1) {
|
||||
addRecursiveDirectoryPtr(outDirs);
|
||||
|
||||
@@ -122,8 +123,8 @@ class FilePointerPartNode {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void addRecursiveDirectoryPtr(@NotNull List<FilePointerPartNode> dirs) {
|
||||
if(hasRecursiveDirectoryPointer() && (dirs.isEmpty() || dirs.get(dirs.size()-1) != this)) {
|
||||
private void addRecursiveDirectoryPtr(@Nullable List<FilePointerPartNode> dirs) {
|
||||
if(dirs != null && hasRecursiveDirectoryPointer() && (dirs.isEmpty() || dirs.get(dirs.size()-1) != this)) {
|
||||
dirs.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,9 +188,6 @@
|
||||
<applicationService serviceInterface="com.intellij.openapi.fileEditor.UniqueVFilePathBuilder"
|
||||
serviceImplementation="com.intellij.openapi.fileEditor.impl.UniqueVFilePathBuilderImpl"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.roots.impl.libraries.JarDirectoryWatcherFactory"
|
||||
serviceImplementation="com.intellij.openapi.roots.impl.libraries.JarDirectoryWatcherFactoryImpl"/>
|
||||
|
||||
<applicationService serviceImplementation="com.intellij.psi.codeStyle.arrangement.engine.ArrangementEngine"/>
|
||||
<applicationService serviceImplementation="com.intellij.psi.codeStyle.arrangement.MemberOrderService"/>
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.ex;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public interface ProjectRoot {
|
||||
boolean isValid();
|
||||
@NotNull
|
||||
VirtualFile[] getVirtualFiles();
|
||||
|
||||
@NotNull
|
||||
String[] getUrls();
|
||||
|
||||
@NotNull
|
||||
String getPresentableString();
|
||||
|
||||
void update();
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.ex;
|
||||
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface ProjectRootContainer {
|
||||
@NotNull
|
||||
VirtualFile[] getRootFiles(@NotNull OrderRootType type);
|
||||
@NotNull ProjectRoot[] getRoots(@NotNull OrderRootType type);
|
||||
|
||||
// must execute modifications inside this method only
|
||||
void changeRoots(@NotNull Runnable change);
|
||||
|
||||
@NotNull
|
||||
ProjectRoot addRoot(@NotNull VirtualFile virtualFile, @NotNull OrderRootType type);
|
||||
void addRoot(@NotNull ProjectRoot root, @NotNull OrderRootType type);
|
||||
void removeRoot(@NotNull ProjectRoot root, @NotNull OrderRootType type);
|
||||
void removeAllRoots(@NotNull OrderRootType type);
|
||||
|
||||
void removeAllRoots();
|
||||
|
||||
void removeRoot(@NotNull VirtualFile root, @NotNull OrderRootType type);
|
||||
|
||||
void update();
|
||||
}
|
||||
-162
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* 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.impl;
|
||||
|
||||
import com.intellij.openapi.projectRoots.ex.ProjectRoot;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
class CompositeProjectRoot implements ProjectRoot {
|
||||
@NonNls private static final String SIMPLE_ROOT = "simple";
|
||||
@NonNls private static final String COMPOSITE_ROOT = "composite";
|
||||
@NonNls private static final String ATTRIBUTE_TYPE = "type";
|
||||
@NonNls private static final String ELEMENT_ROOT = "root";
|
||||
private final List<ProjectRoot> myRoots = new ArrayList<>();
|
||||
|
||||
@NotNull
|
||||
ProjectRoot[] getProjectRoots() {
|
||||
return myRoots.toArray(new ProjectRoot[myRoots.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getPresentableString() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public VirtualFile[] getVirtualFiles() {
|
||||
List<VirtualFile> result = new ArrayList<>();
|
||||
for (ProjectRoot root : myRoots) {
|
||||
ContainerUtil.addAll(result, root.getVirtualFiles());
|
||||
}
|
||||
|
||||
return VfsUtilCore.toVirtualFileArray(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String[] getUrls() {
|
||||
final List<String> result = new ArrayList<>();
|
||||
for (ProjectRoot root : myRoots) {
|
||||
ContainerUtil.addAll(result, root.getUrls());
|
||||
}
|
||||
return ArrayUtil.toStringArray(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void remove(@NotNull ProjectRoot root) {
|
||||
myRoots.remove(root);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
ProjectRoot add(@NotNull VirtualFile virtualFile) {
|
||||
final SimpleProjectRoot root = new SimpleProjectRoot(virtualFile);
|
||||
myRoots.add(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
void add(@NotNull ProjectRoot root) {
|
||||
myRoots.add(root);
|
||||
}
|
||||
|
||||
void remove(@NotNull VirtualFile root) {
|
||||
for (Iterator<ProjectRoot> iterator = myRoots.iterator(); iterator.hasNext();) {
|
||||
ProjectRoot projectRoot = iterator.next();
|
||||
if (projectRoot instanceof SimpleProjectRoot) {
|
||||
SimpleProjectRoot r = (SimpleProjectRoot)projectRoot;
|
||||
if (root.equals(r.getFile())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
myRoots.clear();
|
||||
}
|
||||
|
||||
public void readExternal(Element element) {
|
||||
for (Element child : element.getChildren()) {
|
||||
myRoots.add(read(child));
|
||||
}
|
||||
}
|
||||
|
||||
public void writeExternal(Element element) {
|
||||
for (ProjectRoot root : myRoots) {
|
||||
Element e = write(root);
|
||||
element.addContent(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
for (ProjectRoot root : myRoots) {
|
||||
root.update();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static ProjectRoot read(Element element) {
|
||||
final String type = element.getAttributeValue(ATTRIBUTE_TYPE);
|
||||
|
||||
if (type.equals(SIMPLE_ROOT)) {
|
||||
return new SimpleProjectRoot(element);
|
||||
}
|
||||
if (type.equals(COMPOSITE_ROOT)) {
|
||||
CompositeProjectRoot root = new CompositeProjectRoot();
|
||||
root.readExternal(element);
|
||||
return root;
|
||||
}
|
||||
throw new IllegalArgumentException("Wrong type: " + type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static Element write(ProjectRoot projectRoot) {
|
||||
Element element = new Element(ELEMENT_ROOT);
|
||||
if (projectRoot instanceof SimpleProjectRoot) {
|
||||
element.setAttribute(ATTRIBUTE_TYPE, SIMPLE_ROOT);
|
||||
((SimpleProjectRoot)projectRoot).writeExternal(element);
|
||||
}
|
||||
else if (projectRoot instanceof CompositeProjectRoot) {
|
||||
element.setAttribute(ATTRIBUTE_TYPE, COMPOSITE_ROOT);
|
||||
((CompositeProjectRoot)projectRoot).writeExternal(element);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Wrong root: " + projectRoot);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
+56
-51
@@ -18,35 +18,36 @@ package com.intellij.openapi.projectRoots.impl;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.projectRoots.*;
|
||||
import com.intellij.openapi.projectRoots.ex.ProjectRoot;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.roots.RootProvider;
|
||||
import com.intellij.openapi.roots.impl.ProjectRootManagerImpl;
|
||||
import com.intellij.openapi.roots.impl.RootProviderBaseImpl;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModificator {
|
||||
public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModificator, Disposable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectJdkImpl");
|
||||
private final ProjectRootContainerImpl myRootContainer;
|
||||
private String myName;
|
||||
private String myVersionString;
|
||||
private boolean myVersionDefined;
|
||||
private String myHomePath = "";
|
||||
private final MyRootProvider myRootProvider = new MyRootProvider();
|
||||
private final RootsAsVirtualFilePointers myRoots;
|
||||
private ProjectJdkImpl myOrigin;
|
||||
private SdkAdditionalData myAdditionalData;
|
||||
private SdkTypeId mySdkType;
|
||||
@@ -57,12 +58,37 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
@NonNls private static final String ELEMENT_ROOTS = "roots";
|
||||
@NonNls private static final String ELEMENT_HOMEPATH = "homePath";
|
||||
@NonNls private static final String ELEMENT_ADDITIONAL = "additional";
|
||||
private final MyRootProvider myRootProvider = new MyRootProvider();
|
||||
|
||||
public ProjectJdkImpl(String name, SdkTypeId sdkType) {
|
||||
mySdkType = sdkType;
|
||||
myRootContainer = new ProjectRootContainerImpl(true);
|
||||
myName = name;
|
||||
myRootContainer.addProjectRootContainerListener(myRootProvider);
|
||||
|
||||
VirtualFilePointerListener listener = new VirtualFilePointerListener() {
|
||||
@Override
|
||||
public void beforeValidityChanged(@NotNull VirtualFilePointer[] pointers) {
|
||||
//todo check if this sdk is really used in the project
|
||||
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
|
||||
VirtualFilePointerListener listener = ((ProjectRootManagerImpl)ProjectRootManager.getInstance(project)).getRootsValidityChangedListener();
|
||||
listener.beforeValidityChanged(pointers);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validityChanged(@NotNull VirtualFilePointer[] pointers) {
|
||||
//todo check if this sdk is really used in the project
|
||||
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
|
||||
VirtualFilePointerListener listener = ((ProjectRootManagerImpl)ProjectRootManager.getInstance(project)).getRootsValidityChangedListener();
|
||||
listener.validityChanged(pointers);
|
||||
}
|
||||
}
|
||||
};
|
||||
myRoots = new RootsAsVirtualFilePointers(true, listener, this);
|
||||
Disposer.register(ApplicationManager.getApplication(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
public ProjectJdkImpl(String name, SdkTypeId sdkType, String homePath, String version) {
|
||||
@@ -151,14 +177,12 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
myVersionDefined = false;
|
||||
}
|
||||
|
||||
myRootContainer.changeRoots(() -> {
|
||||
String versionValue = element.getAttributeValue(ELEMENT_VERSION, "");
|
||||
if (versionValue.isEmpty() || !"2".equals(versionValue)) {
|
||||
throw new InvalidDataException("Too old version is not supported: " + versionValue);
|
||||
}
|
||||
myHomePath = element.getChild(ELEMENT_HOMEPATH).getAttributeValue(ATTRIBUTE_VALUE);
|
||||
myRootContainer.readExternal(element.getChild(ELEMENT_ROOTS));
|
||||
});
|
||||
String versionValue = element.getAttributeValue(ELEMENT_VERSION, "");
|
||||
if (versionValue.isEmpty() || !"2".equals(versionValue)) {
|
||||
throw new InvalidDataException("Too old version is not supported: " + versionValue);
|
||||
}
|
||||
myHomePath = element.getChild(ELEMENT_HOMEPATH).getAttributeValue(ATTRIBUTE_VALUE);
|
||||
myRoots.readExternal(element.getChild(ELEMENT_ROOTS));
|
||||
|
||||
final Element additional = element.getChild(ELEMENT_ADDITIONAL);
|
||||
if (additional != null) {
|
||||
@@ -170,7 +194,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
}
|
||||
}
|
||||
|
||||
public void writeExternal(Element element) {
|
||||
public void writeExternal(@NotNull Element element) {
|
||||
element.setAttribute(ELEMENT_VERSION, "2");
|
||||
|
||||
final Element name = new Element(ELEMENT_NAME);
|
||||
@@ -194,7 +218,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
element.addContent(home);
|
||||
|
||||
Element roots = new Element(ELEMENT_ROOTS);
|
||||
myRootContainer.writeExternal(roots);
|
||||
myRoots.writeExternal(roots);
|
||||
element.addContent(roots);
|
||||
|
||||
Element additional = new Element(ELEMENT_ADDITIONAL);
|
||||
@@ -236,29 +260,25 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
dest.myVersionDefined = myVersionDefined;
|
||||
dest.myVersionString = myVersionString;
|
||||
dest.setSdkAdditionalData(getSdkAdditionalData());
|
||||
dest.copyRootsFrom(myRootContainer);
|
||||
dest.copyRootsFrom(myRoots);
|
||||
dest.myRootProvider.rootsChanged();
|
||||
}
|
||||
|
||||
void copyRootsFrom(@NotNull ProjectRootContainerImpl rootContainer) {
|
||||
myRootContainer.copyRootsFrom(rootContainer);
|
||||
private void copyRootsFrom(@NotNull RootProvider rootContainer) {
|
||||
myRoots.copyRootsFrom(rootContainer);
|
||||
}
|
||||
|
||||
private class MyRootProvider extends RootProviderBaseImpl implements ProjectRootListener {
|
||||
@Override
|
||||
@NotNull
|
||||
public String[] getUrls(@NotNull OrderRootType rootType) {
|
||||
final ProjectRoot[] rootFiles = myRootContainer.getRoots(rootType);
|
||||
final ArrayList<String> result = new ArrayList<>();
|
||||
for (ProjectRoot rootFile : rootFiles) {
|
||||
ContainerUtil.addAll(result, rootFile.getUrls());
|
||||
}
|
||||
return ArrayUtil.toStringArray(result);
|
||||
return myRoots.getUrls(rootType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public VirtualFile[] getFiles(@NotNull final OrderRootType rootType) {
|
||||
return myRootContainer.getRootFiles(rootType);
|
||||
return myRoots.getFiles(rootType);
|
||||
}
|
||||
|
||||
private final List<RootSetChangedListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
@@ -298,8 +318,6 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
public SdkModificator getSdkModificator() {
|
||||
ProjectJdkImpl sdk = clone();
|
||||
sdk.myOrigin = this;
|
||||
sdk.myRootContainer.startChange();
|
||||
sdk.update();
|
||||
return sdk;
|
||||
}
|
||||
|
||||
@@ -309,6 +327,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
|
||||
copyTo(myOrigin);
|
||||
myOrigin = null;
|
||||
Disposer.dispose(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -323,33 +342,28 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VirtualFile[] getRoots(OrderRootType rootType) {
|
||||
final ProjectRoot[] roots = myRootContainer.getRoots(rootType); // use getRoots() cause the data is most up-to-date there
|
||||
final List<VirtualFile> files = new ArrayList<>(roots.length);
|
||||
for (ProjectRoot root : roots) {
|
||||
ContainerUtil.addAll(files, root.getVirtualFiles());
|
||||
}
|
||||
return VfsUtilCore.toVirtualFileArray(files);
|
||||
public VirtualFile[] getRoots(@NotNull OrderRootType rootType) {
|
||||
return myRoots.getFiles(rootType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRoot(@NotNull VirtualFile root, @NotNull OrderRootType rootType) {
|
||||
myRootContainer.addRoot(root, rootType);
|
||||
myRoots.addRoot(root, rootType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRoot(@NotNull VirtualFile root, @NotNull OrderRootType rootType) {
|
||||
myRootContainer.removeRoot(root, rootType);
|
||||
myRoots.removeRoot(root, rootType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRoots(@NotNull OrderRootType rootType) {
|
||||
myRootContainer.removeAllRoots(rootType);
|
||||
myRoots.removeAllRoots(rootType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllRoots() {
|
||||
myRootContainer.removeAllRoots();
|
||||
myRoots.removeAllRoots();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -357,15 +371,6 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
|
||||
return myOrigin != null;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
try {
|
||||
myRootContainer.update();
|
||||
}
|
||||
finally {
|
||||
resetVersionString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myName + (myVersionDefined ? ": " + myVersionString : "") + " (" + myHomePath + ")";
|
||||
|
||||
-270
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
* 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.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.projectRoots.ProjectRootListener;
|
||||
import com.intellij.openapi.projectRoots.ex.ProjectRoot;
|
||||
import com.intellij.openapi.projectRoots.ex.ProjectRootContainer;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.PersistentOrderRootType;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.JDOMExternalizable;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRootContainer {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectRootContainerImpl");
|
||||
private final Map<OrderRootType, CompositeProjectRoot> myRoots = new THashMap<>();
|
||||
private final Map<OrderRootType, VirtualFile[]> myCachedFiles = new THashMap<>();
|
||||
|
||||
private boolean myInsideChange;
|
||||
private final List<ProjectRootListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
|
||||
private final boolean myNoCopyJars;
|
||||
|
||||
ProjectRootContainerImpl(boolean noCopyJars) {
|
||||
myNoCopyJars = noCopyJars;
|
||||
|
||||
for (OrderRootType rootType : OrderRootType.getAllTypes()) {
|
||||
myRoots.put(rootType, new CompositeProjectRoot());
|
||||
myCachedFiles.put(rootType, VirtualFile.EMPTY_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public VirtualFile[] getRootFiles(@NotNull OrderRootType type) {
|
||||
return ObjectUtils.chooseNotNull(myCachedFiles.get(type), VirtualFile.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ProjectRoot[] getRoots(@NotNull OrderRootType type) {
|
||||
return myRoots.get(type).getProjectRoots();
|
||||
}
|
||||
|
||||
void startChange() {
|
||||
myInsideChange = true; // argh!! has to have this abomination just because of horrible Sdk.getSdkModificator()/commitChanges() are separated
|
||||
}
|
||||
|
||||
private void assertNotInsideChange() {
|
||||
if (myInsideChange) throw new IllegalStateException();
|
||||
}
|
||||
private void assertInsideChange() {
|
||||
if (!myInsideChange) throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeRoots(@NotNull Runnable change) {
|
||||
assertNotInsideChange();
|
||||
myInsideChange = true;
|
||||
Map<OrderRootType, VirtualFile[]> oldRoots = new THashMap<>(myCachedFiles);
|
||||
|
||||
try {
|
||||
change.run();
|
||||
}
|
||||
finally {
|
||||
myInsideChange = false;
|
||||
|
||||
if (cacheFiles(oldRoots)) {
|
||||
fireRootsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean cacheFiles(@NotNull Map<OrderRootType, VirtualFile[]> oldRoots) {
|
||||
myCachedFiles.clear();
|
||||
|
||||
boolean changed = false;
|
||||
for (OrderRootType orderRootType : OrderRootType.getAllTypes()) {
|
||||
final VirtualFile[] roots = myRoots.get(orderRootType).getVirtualFiles();
|
||||
changed |= !Comparing.equal(roots, oldRoots.get(orderRootType));
|
||||
myCachedFiles.put(orderRootType, roots);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void addProjectRootContainerListener(@NotNull ProjectRootListener listener) {
|
||||
myListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeProjectRootContainerListener(@NotNull ProjectRootListener listener) {
|
||||
myListeners.remove(listener);
|
||||
}
|
||||
|
||||
private void fireRootsChanged() {
|
||||
for (final ProjectRootListener listener : myListeners) {
|
||||
listener.rootsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRoot(@NotNull ProjectRoot root, @NotNull OrderRootType type) {
|
||||
assertInsideChange();
|
||||
myRoots.get(type).remove(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ProjectRoot addRoot(@NotNull VirtualFile virtualFile, @NotNull OrderRootType type) {
|
||||
assertInsideChange();
|
||||
return myRoots.get(type).add(virtualFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRoot(@NotNull ProjectRoot root, @NotNull OrderRootType type) {
|
||||
assertInsideChange();
|
||||
myRoots.get(type).add(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllRoots(@NotNull OrderRootType type) {
|
||||
assertInsideChange();
|
||||
myRoots.get(type).clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRoot(@NotNull VirtualFile root, @NotNull OrderRootType type) {
|
||||
assertInsideChange();
|
||||
myRoots.get(type).remove(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllRoots() {
|
||||
assertInsideChange();
|
||||
for (CompositeProjectRoot myRoot : myRoots.values()) {
|
||||
myRoot.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
assertInsideChange();
|
||||
for (CompositeProjectRoot myRoot : myRoots.values()) {
|
||||
myRoot.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(Element element) {
|
||||
assertInsideChange();
|
||||
for (PersistentOrderRootType type : OrderRootType.getAllPersistentTypes()) {
|
||||
read(element, type);
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
myRoots.values().forEach(root -> {
|
||||
if (myNoCopyJars) {
|
||||
setNoCopyJars(root);
|
||||
}
|
||||
});
|
||||
cacheFiles(new THashMap<>(myCachedFiles));
|
||||
});
|
||||
|
||||
for (OrderRootType type : OrderRootType.getAllTypes()) {
|
||||
if (myRoots.get(type) == null) {
|
||||
LOG.error(type + " wasn't serialized");
|
||||
myRoots.put(type, new CompositeProjectRoot());
|
||||
}
|
||||
|
||||
final VirtualFile[] newRoots = getRootFiles(type);
|
||||
final VirtualFile[] oldRoots = VirtualFile.EMPTY_ARRAY;
|
||||
if (!Comparing.equal(oldRoots, newRoots)) {
|
||||
fireRootsChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(Element element) {
|
||||
List<PersistentOrderRootType> allTypes = OrderRootType.getSortedRootTypes();
|
||||
for (PersistentOrderRootType type : allTypes) {
|
||||
write(element, type);
|
||||
}
|
||||
}
|
||||
|
||||
void copyRootsFrom(@NotNull ProjectRootContainerImpl rootContainer) {
|
||||
changeRoots(() -> {
|
||||
removeAllRoots();
|
||||
for (OrderRootType rootType : OrderRootType.getAllTypes()) {
|
||||
final ProjectRoot[] newRoots = rootContainer.getRoots(rootType);
|
||||
for (ProjectRoot newRoot : newRoots) {
|
||||
addRoot(newRoot, rootType);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void setNoCopyJars(ProjectRoot root) {
|
||||
if (root instanceof SimpleProjectRoot) {
|
||||
String url = ((SimpleProjectRoot)root).getUrl();
|
||||
if (StandardFileSystems.JAR_PROTOCOL.equals(VirtualFileManager.extractProtocol(url))) {
|
||||
String path = VirtualFileManager.extractPath(url);
|
||||
final VirtualFileSystem fileSystem = StandardFileSystems.jar();
|
||||
if (fileSystem instanceof JarCopyingFileSystem) {
|
||||
((JarCopyingFileSystem)fileSystem).setNoCopyJarForPath(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (root instanceof CompositeProjectRoot) {
|
||||
ProjectRoot[] roots = ((CompositeProjectRoot)root).getProjectRoots();
|
||||
for (ProjectRoot root1 : roots) {
|
||||
setNoCopyJars(root1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void read(Element element, PersistentOrderRootType type) {
|
||||
String sdkRootName = type.getSdkRootName();
|
||||
Element child = sdkRootName != null ? element.getChild(sdkRootName) : null;
|
||||
if (child == null) {
|
||||
myRoots.put(type, new CompositeProjectRoot());
|
||||
return;
|
||||
}
|
||||
|
||||
List<Element> children = child.getChildren();
|
||||
if (children.size() != 1) {
|
||||
LOG.error(children);
|
||||
}
|
||||
CompositeProjectRoot root = (CompositeProjectRoot)CompositeProjectRoot.read(children.get(0));
|
||||
myRoots.put(type, root);
|
||||
}
|
||||
|
||||
private void write(Element roots, PersistentOrderRootType type) {
|
||||
String sdkRootName = type.getSdkRootName();
|
||||
if (sdkRootName != null) {
|
||||
Element e = new Element(sdkRootName);
|
||||
roots.addContent(e);
|
||||
final Element root = CompositeProjectRoot.write(myRoots.get(type));
|
||||
e.addContent(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
// Copyright 2000-2017 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.
|
||||
|
||||
package com.intellij.openapi.projectRoots.impl;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.PersistentOrderRootType;
|
||||
import com.intellij.openapi.roots.RootProvider;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public class RootsAsVirtualFilePointers implements RootProvider {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectRootContainerImpl");
|
||||
private final Map<OrderRootType, VirtualFilePointerContainer> myRoots = new THashMap<>();
|
||||
|
||||
private final boolean myNoCopyJars;
|
||||
|
||||
RootsAsVirtualFilePointers(boolean noCopyJars, VirtualFilePointerListener listener, @NotNull Disposable parent) {
|
||||
myNoCopyJars = noCopyJars;
|
||||
|
||||
for (OrderRootType rootType : OrderRootType.getAllTypes()) {
|
||||
myRoots.put(rootType, VirtualFilePointerManager.getInstance().createContainer(parent, listener));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public VirtualFile[] getFiles(@NotNull OrderRootType type) {
|
||||
return myRoots.get(type).getFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String[] getUrls(@NotNull OrderRootType type) {
|
||||
return myRoots.get(type).getUrls();
|
||||
}
|
||||
|
||||
public void addRoot(@NotNull VirtualFile virtualFile, @NotNull OrderRootType type) {
|
||||
myRoots.get(type).add(virtualFile);
|
||||
}
|
||||
|
||||
public void removeAllRoots(@NotNull OrderRootType type) {
|
||||
myRoots.get(type).clear();
|
||||
}
|
||||
|
||||
public void removeRoot(@NotNull VirtualFile root, @NotNull OrderRootType type) {
|
||||
VirtualFilePointerContainer container = myRoots.get(type);
|
||||
VirtualFilePointer pointer = container.findByUrl(root.getUrl());
|
||||
if (pointer != null) {
|
||||
container.remove(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllRoots() {
|
||||
for (VirtualFilePointerContainer myRoot : myRoots.values()) {
|
||||
myRoot.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void readExternal(@NotNull Element element) {
|
||||
for (PersistentOrderRootType type : OrderRootType.getAllPersistentTypes()) {
|
||||
read(element, type);
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(() -> myRoots.values().forEach(container -> {
|
||||
if (myNoCopyJars) {
|
||||
for (String root : container.getUrls()) {
|
||||
setNoCopyJars(root);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
for (OrderRootType type : OrderRootType.getAllTypes()) {
|
||||
if (myRoots.get(type) == null) {
|
||||
LOG.error(type + " wasn't serialized");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeExternal(@NotNull Element element) {
|
||||
List<PersistentOrderRootType> allTypes = OrderRootType.getSortedRootTypes();
|
||||
for (PersistentOrderRootType type : allTypes) {
|
||||
write(element, type);
|
||||
}
|
||||
}
|
||||
|
||||
void copyRootsFrom(@NotNull RootProvider rootContainer) {
|
||||
removeAllRoots();
|
||||
for (OrderRootType rootType : OrderRootType.getAllTypes()) {
|
||||
final VirtualFile[] newRoots = rootContainer.getFiles(rootType);
|
||||
for (VirtualFile newRoot : newRoots) {
|
||||
addRoot(newRoot, rootType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setNoCopyJars(@NotNull String url) {
|
||||
if (StandardFileSystems.JAR_PROTOCOL.equals(VirtualFileManager.extractProtocol(url))) {
|
||||
String path = VirtualFileManager.extractPath(url);
|
||||
final VirtualFileSystem fileSystem = StandardFileSystems.jar();
|
||||
if (fileSystem instanceof JarCopyingFileSystem) {
|
||||
((JarCopyingFileSystem)fileSystem).setNoCopyJarForPath(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
<roots>
|
||||
<sourcePath>
|
||||
<root type="composite">
|
||||
<root type="simple" url="jar://I:/Java/jdk1.8/src.zip!/" />
|
||||
<root type="simple" url="jar://I:/Java/jdk1.8/javafx-src.zip!/" />
|
||||
</root>
|
||||
</sourcePath>
|
||||
</roots>
|
||||
*/
|
||||
private void read(@NotNull Element roots, @NotNull PersistentOrderRootType type) {
|
||||
String sdkRootName = type.getSdkRootName();
|
||||
Element child = sdkRootName != null ? roots.getChild(sdkRootName) : null;
|
||||
if (child == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Element> composites = child.getChildren();
|
||||
if (composites.size() != 1) {
|
||||
LOG.error(composites);
|
||||
}
|
||||
Element composite = composites.get(0);
|
||||
|
||||
myRoots.get(type).readExternal(composite, "root", false);
|
||||
}
|
||||
|
||||
/**
|
||||
<roots>
|
||||
<sourcePath>
|
||||
<root type="composite">
|
||||
<root type="simple" url="jar://I:/Java/jdk1.8/src.zip!/" />
|
||||
<root type="simple" url="jar://I:/Java/jdk1.8/javafx-src.zip!/" />
|
||||
</root>
|
||||
</sourcePath>
|
||||
</roots>
|
||||
*/
|
||||
private void write(@NotNull Element roots, @NotNull PersistentOrderRootType type) {
|
||||
String sdkRootName = type.getSdkRootName();
|
||||
if (sdkRootName == null) {
|
||||
return;
|
||||
}
|
||||
Element e = new Element(sdkRootName);
|
||||
roots.addContent(e);
|
||||
Element composite = new Element("root");
|
||||
composite.setAttribute("type", "composite");
|
||||
e.addContent(composite);
|
||||
myRoots.get(type).writeExternal(composite, "root", false);
|
||||
for (Element root : composite.getChildren()) {
|
||||
root.setAttribute("type", "simple");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRootSetChangedListener(@NotNull RootSetChangedListener listener) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRootSetChangedListener(@NotNull RootSetChangedListener listener, @NotNull Disposable parentDisposable) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRootSetChangedListener(@NotNull RootSetChangedListener listener) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
-131
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* 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.impl;
|
||||
|
||||
import com.intellij.openapi.projectRoots.ex.ProjectRoot;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public class SimpleProjectRoot implements ProjectRoot {
|
||||
@NotNull
|
||||
private final String myUrl;
|
||||
private VirtualFile myFile;
|
||||
private final VirtualFile[] myFileArray = new VirtualFile[1];
|
||||
private boolean myInitialized;
|
||||
@NonNls private static final String ATTRIBUTE_URL = "url";
|
||||
|
||||
public SimpleProjectRoot(@NotNull VirtualFile file) {
|
||||
myFile = file;
|
||||
myUrl = myFile.getUrl();
|
||||
}
|
||||
|
||||
public SimpleProjectRoot(@NotNull String url) {
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
SimpleProjectRoot(@NotNull Element element) {
|
||||
myUrl = readUrl(element);
|
||||
}
|
||||
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getPresentableString() {
|
||||
String path = VirtualFileManager.extractPath(myUrl);
|
||||
path = StringUtil.trimEnd(path, URLUtil.JAR_SEPARATOR);
|
||||
return path.replace('/', File.separatorChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public VirtualFile[] getVirtualFiles() {
|
||||
if (!myInitialized) initialize();
|
||||
|
||||
if (myFile == null) {
|
||||
return VirtualFile.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
myFileArray[0] = myFile;
|
||||
return myFileArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String[] getUrls() {
|
||||
return new String[]{getUrl()};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
if (!myInitialized) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
return myFile != null && myFile.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
myInitialized = true;
|
||||
|
||||
if (myFile == null || !myFile.isValid()) {
|
||||
myFile = VirtualFileManager.getInstance().findFileByUrl(myUrl);
|
||||
if (myFile != null && !canHaveChildren()) {
|
||||
myFile = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canHaveChildren() {
|
||||
return myFile.getFileSystem().getProtocol().equals(URLUtil.HTTP_PROTOCOL) || myFile.isDirectory();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String readUrl(Element element) {
|
||||
return element.getAttributeValue(ATTRIBUTE_URL);
|
||||
}
|
||||
|
||||
public void writeExternal(Element element) {
|
||||
if (!myInitialized) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
element.setAttribute(ATTRIBUTE_URL, getUrl());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -63,7 +63,7 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE
|
||||
|
||||
ContentEntryImpl(@NotNull String url, @NotNull RootModelImpl m) {
|
||||
super(m);
|
||||
myRoot = VirtualFilePointerManager.getInstance().create(url, this, null);
|
||||
myRoot = VirtualFilePointerManager.getInstance().create(url, this, m.getRootsChangedListener());
|
||||
}
|
||||
|
||||
ContentEntryImpl(@NotNull Element e, @NotNull RootModelImpl m) throws InvalidDataException {
|
||||
|
||||
+3
-3
@@ -43,13 +43,13 @@ public abstract class ContentFolderBaseImpl extends RootModelComponentBase imple
|
||||
ContentFolderBaseImpl(@NotNull VirtualFile file, @NotNull ContentEntryImpl contentEntry) {
|
||||
super(contentEntry.getRootModel());
|
||||
myContentEntry = contentEntry;
|
||||
myFilePointer = VirtualFilePointerManager.getInstance().create(file, this, null);
|
||||
myFilePointer = VirtualFilePointerManager.getInstance().create(file, this, getRootModel().getRootsChangedListener());
|
||||
}
|
||||
|
||||
ContentFolderBaseImpl(@NotNull String url, @NotNull ContentEntryImpl contentEntry) {
|
||||
super(contentEntry.getRootModel());
|
||||
myContentEntry = contentEntry;
|
||||
myFilePointer = VirtualFilePointerManager.getInstance().create(url, this, null);
|
||||
myFilePointer = VirtualFilePointerManager.getInstance().create(url, this, getRootModel().getRootsChangedListener());
|
||||
}
|
||||
|
||||
protected ContentFolderBaseImpl(@NotNull ContentFolderBaseImpl that, @NotNull ContentEntryImpl contentEntry) {
|
||||
@@ -63,7 +63,7 @@ public abstract class ContentFolderBaseImpl extends RootModelComponentBase imple
|
||||
protected ContentFolderBaseImpl(@NotNull VirtualFilePointer filePointer, @NotNull ContentEntryImpl contentEntry) {
|
||||
super(contentEntry.getRootModel());
|
||||
myContentEntry = contentEntry;
|
||||
myFilePointer = VirtualFilePointerManager.getInstance().duplicate(filePointer,this, null);
|
||||
myFilePointer = VirtualFilePointerManager.getInstance().duplicate(filePointer,this, getRootModel().getRootsChangedListener());
|
||||
}
|
||||
|
||||
private static String getUrlFrom(Element element) throws InvalidDataException {
|
||||
|
||||
+1
-3
@@ -34,13 +34,12 @@ import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer
|
||||
*/
|
||||
public class InheritedJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implements InheritedJdkOrderEntry, ClonableOrderEntry, WritableOrderEntry {
|
||||
@NonNls public static final String ENTRY_TYPE = JpsModuleRootModelSerializer.INHERITED_JDK_TYPE;
|
||||
private final MyJdkTableListener myJdkTableListener = new MyJdkTableListener();
|
||||
private final MyProjectJdkListener myListener = new MyProjectJdkListener();
|
||||
|
||||
InheritedJdkOrderEntryImpl(@NotNull RootModelImpl rootModel, @NotNull ProjectRootManagerImpl projectRootManager) {
|
||||
super(rootModel, projectRootManager);
|
||||
myProjectRootManagerImpl.addProjectJdkListener(myListener);
|
||||
myProjectRootManagerImpl.addJdkTableListener(myJdkTableListener);
|
||||
myProjectRootManagerImpl.addJdkTableListener(new MyJdkTableListener(), this);
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -107,7 +106,6 @@ public class InheritedJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implem
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
myProjectRootManagerImpl.removeJdkTableListener(myJdkTableListener);
|
||||
myProjectRootManagerImpl.removeProjectJdkListener(myListener);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -119,7 +119,7 @@ public class JavaModuleExternalPathsImpl extends JavaModuleExternalPaths {
|
||||
if (pathsElement != null) {
|
||||
VirtualFilePointerContainer container = VirtualFilePointerManager.getInstance().createContainer(this, null);
|
||||
myOrderRootPointerContainers.put(orderRootType, container);
|
||||
container.readExternal(pathsElement, ROOT_ELEMENT);
|
||||
container.readExternal(pathsElement, ROOT_ELEMENT, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ public class JavaModuleExternalPathsImpl extends JavaModuleExternalPaths {
|
||||
VirtualFilePointerContainer container = myOrderRootPointerContainers.get(orderRootType);
|
||||
if (container != null && container.size() > 0) {
|
||||
final Element javaDocPaths = new Element(((PersistentOrderRootType)orderRootType).getModulePathsName());
|
||||
container.writeExternal(javaDocPaths, ROOT_ELEMENT);
|
||||
container.writeExternal(javaDocPaths, ROOT_ELEMENT, false);
|
||||
element.addContent(javaDocPaths);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-13
@@ -40,8 +40,8 @@ public class ModuleJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implement
|
||||
ModuleJdkOrderEntry,
|
||||
ProjectJdkTable.Listener {
|
||||
@NonNls public static final String ENTRY_TYPE = JpsModuleRootModelSerializer.JDK_TYPE;
|
||||
@NonNls public static final String JDK_NAME_ATTR = JpsModuleRootModelSerializer.JDK_NAME_ATTRIBUTE;
|
||||
@NonNls public static final String JDK_TYPE_ATTR = JpsModuleRootModelSerializer.JDK_TYPE_ATTRIBUTE;
|
||||
@NonNls private static final String JDK_NAME_ATTR = JpsModuleRootModelSerializer.JDK_NAME_ATTRIBUTE;
|
||||
@NonNls private static final String JDK_TYPE_ATTR = JpsModuleRootModelSerializer.JDK_TYPE_ATTRIBUTE;
|
||||
|
||||
@Nullable private Sdk myJdk;
|
||||
private String myJdkName;
|
||||
@@ -103,7 +103,7 @@ public class ModuleJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implement
|
||||
myJdk = jdk;
|
||||
setJdkName(jdkName);
|
||||
setJdkType(jdkType);
|
||||
addListener();
|
||||
myProjectRootManagerImpl.addJdkTableListener(this, this);
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -114,10 +114,6 @@ public class ModuleJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implement
|
||||
return myJdkType;
|
||||
}
|
||||
|
||||
private void addListener() {
|
||||
myProjectRootManagerImpl.addJdkTableListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RootProvider getRootProvider() {
|
||||
return myJdk == null ? null : myJdk.getRootProvider();
|
||||
@@ -214,12 +210,6 @@ public class ModuleJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implement
|
||||
return new ModuleJdkOrderEntryImpl(this, rootModel, ProjectRootManagerImpl.getInstanceImpl(getRootModel().getModule().getProject()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
myProjectRootManagerImpl.removeJdkTableListener(this);
|
||||
}
|
||||
|
||||
private void setJdkName(String jdkName) {
|
||||
myJdkName = jdkName;
|
||||
}
|
||||
|
||||
+20
-17
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.intellij.openapi.roots.impl;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
@@ -31,9 +32,11 @@ import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.roots.libraries.LibraryTable;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.EmptyRunnable;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -53,8 +56,8 @@ import java.util.*;
|
||||
public class ProjectRootManagerImpl extends ProjectRootManagerEx implements PersistentStateComponent<Element> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectRootManagerImpl");
|
||||
|
||||
@NonNls public static final String PROJECT_JDK_NAME_ATTR = "project-jdk-name";
|
||||
@NonNls public static final String PROJECT_JDK_TYPE_ATTR = "project-jdk-type";
|
||||
@NonNls private static final String PROJECT_JDK_NAME_ATTR = "project-jdk-name";
|
||||
@NonNls private static final String PROJECT_JDK_TYPE_ATTR = "project-jdk-type";
|
||||
|
||||
protected final Project myProject;
|
||||
|
||||
@@ -92,7 +95,7 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
myBatchLevel -= 1;
|
||||
if (myChanged && myBatchLevel == 0) {
|
||||
try {
|
||||
WriteAction.run(this::fireChange);
|
||||
WriteAction.run(() -> fireRootsChanged(myFileTypes));
|
||||
}
|
||||
finally {
|
||||
myChanged = false;
|
||||
@@ -100,10 +103,6 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
}
|
||||
}
|
||||
|
||||
private boolean fireChange() {
|
||||
return fireRootsChanged(myFileTypes);
|
||||
}
|
||||
|
||||
protected void beforeRootsChanged() {
|
||||
if (myBatchLevel == 0 || !myChanged) {
|
||||
if (fireBeforeRootsChanged(myFileTypes)) {
|
||||
@@ -114,7 +113,7 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
|
||||
protected void rootsChanged() {
|
||||
if (myBatchLevel == 0) {
|
||||
if (fireChange()) {
|
||||
if (fireRootsChanged(myFileTypes)) {
|
||||
myChanged = false;
|
||||
}
|
||||
}
|
||||
@@ -123,6 +122,7 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
|
||||
protected final BatchSession myRootsChanged = new BatchSession(false);
|
||||
protected final BatchSession myFileTypesChanged = new BatchSession(true);
|
||||
private final VirtualFilePointerListener myRootsValidityChangedListener = new VirtualFilePointerListener(){};
|
||||
|
||||
public static ProjectRootManagerImpl getInstanceImpl(Project project) {
|
||||
return (ProjectRootManagerImpl)getInstance(project);
|
||||
@@ -253,12 +253,12 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProjectJdkListener(ProjectJdkListener listener) {
|
||||
public void addProjectJdkListener(@NotNull ProjectJdkListener listener) {
|
||||
myProjectJdkEventDispatcher.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProjectJdkListener(ProjectJdkListener listener) {
|
||||
public void removeProjectJdkListener(@NotNull ProjectJdkListener listener) {
|
||||
myProjectJdkEventDispatcher.removeListener(listener);
|
||||
}
|
||||
|
||||
@@ -419,6 +419,7 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
protected void addRootsToWatch() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
@@ -610,7 +611,7 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
}
|
||||
});
|
||||
String currentName = getProjectSdkName();
|
||||
if (previousName != null && previousName.equals(currentName)) {
|
||||
if (previousName.equals(currentName)) {
|
||||
// if already had jdk name and that name was the name of the jdk just changed
|
||||
myProjectSdkName = jdk.getName();
|
||||
myProjectSdkType = jdk.getSdkType().getName();
|
||||
@@ -618,14 +619,11 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<RootProvider, Set<OrderEntry>> myRegisteredRootProviders = new HashMap<>();
|
||||
private final Map<RootProvider, Set<OrderEntry>> myRegisteredRootProviders = ContainerUtil.newIdentityTroveMap();
|
||||
|
||||
void addJdkTableListener(ProjectJdkTable.Listener jdkTableListener) {
|
||||
void addJdkTableListener(@NotNull ProjectJdkTable.Listener jdkTableListener, @NotNull Disposable parent) {
|
||||
myJdkTableMultiListener.addListener(jdkTableListener);
|
||||
}
|
||||
|
||||
void removeJdkTableListener(ProjectJdkTable.Listener jdkTableListener) {
|
||||
myJdkTableMultiListener.removeListener(jdkTableListener);
|
||||
Disposer.register(parent, ()->myJdkTableMultiListener.removeListener(jdkTableListener));
|
||||
}
|
||||
|
||||
void assertListenersAreDisposed() {
|
||||
@@ -663,4 +661,9 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
|
||||
}
|
||||
|
||||
public void markRootsForRefresh() { }
|
||||
|
||||
@NotNull
|
||||
public VirtualFilePointerListener getRootsValidityChangedListener() {
|
||||
return myRootsValidityChangedListener;
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
@@ -831,4 +832,9 @@ public class RootModelImpl extends RootModelBase implements ModifiableRootModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VirtualFilePointerListener getRootsChangedListener() {
|
||||
return myProjectRootManager.getRootsValidityChangedListener();
|
||||
}
|
||||
}
|
||||
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.roots.impl.libraries;
|
||||
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.PersistentOrderRootType;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizable;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class JarDirectories implements JDOMExternalizable {
|
||||
private final MultiMap<OrderRootType, String> myDirectories = new MultiMap<>();
|
||||
private final MultiMap<OrderRootType, String> myRecursivelyIncluded = new MultiMap<>();
|
||||
|
||||
@NonNls private static final String JAR_DIRECTORY_ELEMENT = "jarDirectory";
|
||||
@NonNls private static final String URL_ATTR = "url";
|
||||
@NonNls private static final String RECURSIVE_ATTR = "recursive";
|
||||
@NonNls private static final String ROOT_TYPE_ATTR = "type";
|
||||
public static final OrderRootType DEFAULT_JAR_DIRECTORY_TYPE = OrderRootType.CLASSES;
|
||||
|
||||
public void copyFrom(@NotNull JarDirectories other) {
|
||||
myDirectories.clear();
|
||||
myDirectories.putAllValues(other.myDirectories);
|
||||
myRecursivelyIncluded.clear();
|
||||
myRecursivelyIncluded.putAllValues(other.myRecursivelyIncluded);
|
||||
}
|
||||
|
||||
public boolean contains(@NotNull OrderRootType rootType, @NotNull String url) {
|
||||
return myDirectories.get(rootType).contains(url);
|
||||
}
|
||||
|
||||
public boolean isRecursive(@NotNull OrderRootType rootType, @NotNull String url) {
|
||||
return myRecursivelyIncluded.get(rootType).contains(url);
|
||||
}
|
||||
|
||||
public void add(@NotNull OrderRootType rootType, @NotNull String url, boolean recursively) {
|
||||
myDirectories.putValue(rootType, url);
|
||||
if (recursively) {
|
||||
myRecursivelyIncluded.putValue(rootType, url);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(@NotNull OrderRootType rootType, @NotNull String url) {
|
||||
myDirectories.remove(rootType, url);
|
||||
myRecursivelyIncluded.remove(rootType, url);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
myDirectories.clear();
|
||||
myRecursivelyIncluded.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<OrderRootType> getRootTypes() {
|
||||
return myDirectories.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<String> getDirectories(@NotNull OrderRootType rootType) {
|
||||
return myDirectories.get(rootType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<? extends String> getAllDirectories() {
|
||||
return myDirectories.values();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myDirectories.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof JarDirectories)) return false;
|
||||
|
||||
JarDirectories that = (JarDirectories)o;
|
||||
return myDirectories.equals(that.myDirectories) && myRecursivelyIncluded.equals(that.myRecursivelyIncluded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * myDirectories.hashCode() + myRecursivelyIncluded.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JAR dirs: " + myDirectories.values();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void readExternal(Element element) throws InvalidDataException {
|
||||
clear();
|
||||
final List<Element> jarDirs = element.getChildren(JAR_DIRECTORY_ELEMENT);
|
||||
for (Element jarDir : jarDirs) {
|
||||
final String url = jarDir.getAttributeValue(URL_ATTR);
|
||||
final String recursive = jarDir.getAttributeValue(RECURSIVE_ATTR);
|
||||
final OrderRootType rootType = getJarDirectoryRootType(jarDir.getAttributeValue(ROOT_TYPE_ATTR));
|
||||
if (url != null) {
|
||||
add(rootType, url, Boolean.valueOf(Boolean.parseBoolean(recursive)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static OrderRootType getJarDirectoryRootType(@Nullable String type) {
|
||||
for (PersistentOrderRootType rootType : OrderRootType.getAllPersistentTypes()) {
|
||||
if (rootType.name().equals(type)) {
|
||||
return rootType;
|
||||
}
|
||||
}
|
||||
return DEFAULT_JAR_DIRECTORY_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(Element element) {
|
||||
final List<OrderRootType> rootTypes = LibraryImpl.sortRootTypes(getRootTypes());
|
||||
for (OrderRootType rootType : rootTypes) {
|
||||
final List<String> urls = new ArrayList<>(getDirectories(rootType));
|
||||
Collections.sort(urls, String.CASE_INSENSITIVE_ORDER);
|
||||
for (String url : urls) {
|
||||
final Element jarDirElement = new Element(JAR_DIRECTORY_ELEMENT);
|
||||
jarDirElement.setAttribute(URL_ATTR, url);
|
||||
jarDirElement.setAttribute(RECURSIVE_ATTR, Boolean.toString(isRecursive(rootType, url)));
|
||||
if (!rootType.equals(DEFAULT_JAR_DIRECTORY_TYPE)) {
|
||||
jarDirElement.setAttribute(ROOT_TYPE_ATTR, rootType.name());
|
||||
}
|
||||
element.addContent(jarDirElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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.roots.impl.libraries;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.roots.impl.RootProviderBaseImpl;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class JarDirectoryWatcherFactory {
|
||||
private static final JarDirectoryWatcherFactory Instance = new JarDirectoryWatcherFactory();
|
||||
|
||||
public static JarDirectoryWatcherFactory getInstance() {
|
||||
final JarDirectoryWatcherFactory factory = ServiceManager.getService(JarDirectoryWatcherFactory.class);
|
||||
return factory != null ? factory : Instance;
|
||||
}
|
||||
|
||||
public JarDirectoryWatcher createWatcher(JarDirectories jarDirectories, RootProviderBaseImpl rootProvider) {
|
||||
return new JarDirectoryWatcher() {
|
||||
@Override
|
||||
public void updateWatchedRoots() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+150
-152
@@ -15,33 +15,32 @@
|
||||
*/
|
||||
package com.intellij.openapi.roots.impl.libraries;
|
||||
|
||||
import com.intellij.ide.highlighter.ArchiveFileType;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.ComponentSerializationUtil;
|
||||
import com.intellij.openapi.components.StateSplitterEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectUtilCore;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.roots.impl.ProjectRootManagerImpl;
|
||||
import com.intellij.openapi.roots.impl.RootModelImpl;
|
||||
import com.intellij.openapi.roots.impl.RootProviderBaseImpl;
|
||||
import com.intellij.openapi.roots.libraries.*;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor;
|
||||
import com.intellij.openapi.vfs.impl.VirtualFilePointerContainerImpl;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
|
||||
import com.intellij.util.xmlb.XmlSerializer;
|
||||
import gnu.trove.THashSet;
|
||||
@@ -52,62 +51,36 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.openapi.components.StateSplitterEx.EXTERNAL_SYSTEM_ID_ATTRIBUTE;
|
||||
import static com.intellij.openapi.vfs.VirtualFileVisitor.ONE_LEVEL_DEEP;
|
||||
import static com.intellij.openapi.vfs.VirtualFileVisitor.SKIP_ROOT;
|
||||
|
||||
/**
|
||||
* @author dsl
|
||||
*/
|
||||
public class LibraryImpl extends TraceableDisposable implements LibraryEx.ModifiableModelEx, LibraryEx {
|
||||
public class LibraryImpl extends TraceableDisposable implements LibraryEx.ModifiableModelEx, LibraryEx, RootProvider {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.impl.LibraryImpl");
|
||||
@NonNls public static final String LIBRARY_NAME_ATTR = "name";
|
||||
@NonNls public static final String LIBRARY_TYPE_ATTR = "type";
|
||||
@NonNls public static final String ROOT_PATH_ELEMENT = "root";
|
||||
@NonNls private static final String LIBRARY_TYPE_ATTR = "type";
|
||||
@NonNls private static final String ROOT_PATH_ELEMENT = "root";
|
||||
@NonNls public static final String ELEMENT = "library";
|
||||
@NonNls public static final String PROPERTIES_ELEMENT = "properties";
|
||||
@NonNls private static final String PROPERTIES_ELEMENT = "properties";
|
||||
private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters();
|
||||
private static final String EXCLUDED_ROOTS_TAG = "excluded";
|
||||
private String myName;
|
||||
private final LibraryTable myLibraryTable;
|
||||
private final Map<OrderRootType, VirtualFilePointerContainer> myRoots;
|
||||
@Nullable private VirtualFilePointerContainer myExcludedRoots;
|
||||
private final JarDirectories myJarDirectories = new JarDirectories();
|
||||
private final LibraryImpl mySource;
|
||||
private PersistentLibraryKind<?> myKind;
|
||||
private LibraryProperties myProperties;
|
||||
|
||||
private final MyRootProviderImpl myRootProvider = new MyRootProviderImpl();
|
||||
@Nullable
|
||||
private final ModifiableRootModel myRootModel;
|
||||
private boolean myDisposed;
|
||||
private final Disposable myPointersDisposable = Disposer.newDisposable();
|
||||
private final JarDirectoryWatcher myRootsWatcher = JarDirectoryWatcherFactory.getInstance().createWatcher(myJarDirectories, myRootProvider);
|
||||
private final ProjectModelExternalSource myExternalSource;
|
||||
private final EventDispatcher<RootSetChangedListener> myDispatcher = EventDispatcher.create(RootSetChangedListener.class);
|
||||
|
||||
LibraryImpl(LibraryTable table, @NotNull Element element, ModifiableRootModel rootModel) throws InvalidDataException {
|
||||
this(table, rootModel, null, element.getAttributeValue(LIBRARY_NAME_ATTR), findPersistentLibraryKind(element), findExternalSource(element));
|
||||
readProperties(element);
|
||||
myJarDirectories.readExternal(element);
|
||||
readRoots(element);
|
||||
myRootsWatcher.updateWatchedRoots();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ProjectModelExternalSource findExternalSource(Element element) {
|
||||
@Nullable String externalSourceId = element.getAttributeValue(EXTERNAL_SYSTEM_ID_ATTRIBUTE);
|
||||
return externalSourceId != null ? ExternalProjectSystemRegistry.getInstance().getSourceById(externalSourceId) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PersistentLibraryKind<?> findPersistentLibraryKind(@NotNull Element element) {
|
||||
String typeString = element.getAttributeValue(LIBRARY_TYPE_ATTR);
|
||||
LibraryKind kind = LibraryKind.findById(typeString);
|
||||
if (kind != null && !(kind instanceof PersistentLibraryKind<?>)) {
|
||||
LOG.error("Cannot load non-persistable library kind: " + typeString);
|
||||
return null;
|
||||
}
|
||||
return (PersistentLibraryKind<?>)kind;
|
||||
this(table, rootModel, null, null, findPersistentLibraryKind(element), findExternalSource(element));
|
||||
readExternal(element);
|
||||
}
|
||||
|
||||
LibraryImpl(String name, @Nullable final PersistentLibraryKind<?> kind, LibraryTable table, ModifiableRootModel rootModel,
|
||||
@@ -135,12 +108,11 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
if (from.myExcludedRoots != null) {
|
||||
myExcludedRoots = from.myExcludedRoots.clone(myPointersDisposable);
|
||||
}
|
||||
myJarDirectories.copyFrom(from.myJarDirectories);
|
||||
}
|
||||
|
||||
// primary
|
||||
private LibraryImpl(LibraryTable table, @Nullable ModifiableRootModel rootModel, LibraryImpl newSource, String name,
|
||||
@Nullable final PersistentLibraryKind<?> kind, @Nullable ProjectModelExternalSource externalSource) {
|
||||
@Nullable PersistentLibraryKind<?> kind, @Nullable ProjectModelExternalSource externalSource) {
|
||||
super(true);
|
||||
myLibraryTable = table;
|
||||
myRootModel = rootModel;
|
||||
@@ -150,9 +122,26 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
myExternalSource = externalSource;
|
||||
//init roots depends on my myKind
|
||||
myRoots = initRoots();
|
||||
Disposer.register(this, myRootsWatcher);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ProjectModelExternalSource findExternalSource(Element element) {
|
||||
@Nullable String externalSourceId = element.getAttributeValue(StateSplitterEx.EXTERNAL_SYSTEM_ID_ATTRIBUTE);
|
||||
return externalSourceId != null ? ExternalProjectSystemRegistry.getInstance().getSourceById(externalSourceId) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PersistentLibraryKind<?> findPersistentLibraryKind(@NotNull Element element) {
|
||||
String typeString = element.getAttributeValue(LIBRARY_TYPE_ATTR);
|
||||
LibraryKind kind = LibraryKind.findById(typeString);
|
||||
if (kind != null && !(kind instanceof PersistentLibraryKind<?>)) {
|
||||
LOG.error("Cannot load non-persistable library kind: " + typeString);
|
||||
return null;
|
||||
}
|
||||
return (PersistentLibraryKind<?>)kind;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<OrderRootType> getAllRootTypes() {
|
||||
Set<OrderRootType> rootTypes = new HashSet<>(Arrays.asList(OrderRootType.getAllTypes()));
|
||||
if (myKind != null) {
|
||||
@@ -171,7 +160,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
|
||||
private void checkDisposed() {
|
||||
if (isDisposed()) {
|
||||
throwDisposalError("'" + myName + "' already disposed:");
|
||||
throwDisposalError("'" + myName + "' already disposed: " + getStackTrace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,37 +189,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
checkDisposed();
|
||||
|
||||
VirtualFilePointerContainer container = myRoots.get(rootType);
|
||||
if (container == null) {
|
||||
return VirtualFile.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
List<VirtualFile> expanded = new SmartList<>();
|
||||
for (VirtualFile file : container.getFiles()) {
|
||||
if (file.isDirectory()) {
|
||||
if (myJarDirectories.contains(rootType, file.getUrl())) {
|
||||
collectJarFiles(file, expanded, myJarDirectories.isRecursive(rootType, file.getUrl()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
expanded.add(file);
|
||||
}
|
||||
return VfsUtilCore.toVirtualFileArray(expanded);
|
||||
}
|
||||
|
||||
public static void collectJarFiles(VirtualFile dir, List<VirtualFile> container, boolean recursively) {
|
||||
VfsUtilCore.visitChildrenRecursively(dir, new VirtualFileVisitor(SKIP_ROOT, recursively ? null : ONE_LEVEL_DEEP) {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
if (!file.isDirectory() && FileTypeRegistry.getInstance().getFileTypeByFileName(file.getName()) == ArchiveFileType.INSTANCE) {
|
||||
VirtualFile jarRoot = StandardFileSystems.jar().findFileByPath(file.getPath() + URLUtil.JAR_SEPARATOR);
|
||||
if (jarRoot != null) {
|
||||
container.add(jarRoot);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return container == null ? VirtualFile.EMPTY_ARRAY : container.getFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,15 +206,15 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
return new LibraryImpl(this, this, myRootModel);
|
||||
}
|
||||
|
||||
public Library cloneLibrary(RootModelImpl rootModel) {
|
||||
@NotNull
|
||||
public Library cloneLibrary(@NotNull RootModelImpl rootModel) {
|
||||
LOG.assertTrue(myLibraryTable == null);
|
||||
final LibraryImpl clone = new LibraryImpl(this, null, rootModel);
|
||||
clone.myRootsWatcher.updateWatchedRoots();
|
||||
return clone;
|
||||
return new LibraryImpl(this, null, rootModel);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getInvalidRootUrls(OrderRootType type) {
|
||||
public List<String> getInvalidRootUrls(@NotNull OrderRootType type) {
|
||||
if (myDisposed) return Collections.emptyList();
|
||||
|
||||
final List<VirtualFilePointer> pointers = myRoots.get(type).getList();
|
||||
@@ -280,21 +239,32 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
@Override
|
||||
@NotNull
|
||||
public RootProvider getRootProvider() {
|
||||
return myRootProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<OrderRootType, VirtualFilePointerContainer> initRoots() {
|
||||
Disposer.register(this, myPointersDisposable);
|
||||
|
||||
Map<OrderRootType, VirtualFilePointerContainer> result = new HashMap<>(4);
|
||||
|
||||
VirtualFilePointerListener listener = getListener();
|
||||
|
||||
for (OrderRootType rootType : getAllRootTypes()) {
|
||||
result.put(rootType, VirtualFilePointerManager.getInstance().createContainer(myPointersDisposable));
|
||||
VirtualFilePointerContainer container = VirtualFilePointerManager.getInstance().createContainer(myPointersDisposable, listener);
|
||||
result.put(rootType, container);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFilePointerListener getListener() {
|
||||
Project project = myLibraryTable instanceof ProjectLibraryTable ? ((ProjectLibraryTable)myLibraryTable).getProject() : null;
|
||||
return myRootModel != null ? ((RootModelImpl)myRootModel).getRootsChangedListener() : project != null ? ProjectRootManagerImpl
|
||||
.getInstanceImpl(project).getRootsValidityChangedListener() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ProjectModelExternalSource getExternalSource() {
|
||||
@@ -306,8 +276,36 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
readName(element);
|
||||
readProperties(element);
|
||||
readRoots(element);
|
||||
myJarDirectories.readExternal(element);
|
||||
myRootsWatcher.updateWatchedRoots();
|
||||
readJarDirectories(element);
|
||||
}
|
||||
|
||||
@NonNls private static final String ROOT_TYPE_ATTR = "type";
|
||||
private static final OrderRootType DEFAULT_JAR_DIRECTORY_TYPE = OrderRootType.CLASSES;
|
||||
|
||||
// just to maintain .xml compatibility
|
||||
// VirtualFilePointerContainerImpl does the same but stores its jar dirs attributes inside <root> element
|
||||
@Deprecated // todo to remove sometime later
|
||||
private void readJarDirectories(Element element) {
|
||||
final List<Element> jarDirs = element.getChildren(VirtualFilePointerContainerImpl.JAR_DIRECTORY_ELEMENT);
|
||||
for (Element jarDir : jarDirs) {
|
||||
final String url = jarDir.getAttributeValue(VirtualFilePointerContainerImpl.URL_ATTR);
|
||||
if (url != null) {
|
||||
final String recursive = jarDir.getAttributeValue(VirtualFilePointerContainerImpl.RECURSIVE_ATTR);
|
||||
final OrderRootType rootType = getJarDirectoryRootType(jarDir.getAttributeValue(ROOT_TYPE_ATTR));
|
||||
VirtualFilePointerContainer roots = myRoots.get(rootType);
|
||||
boolean recursively = Boolean.parseBoolean(recursive);
|
||||
roots.addJarDirectory(url, recursively);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static OrderRootType getJarDirectoryRootType(@Nullable String type) {
|
||||
for (PersistentOrderRootType rootType : OrderRootType.getAllPersistentTypes()) {
|
||||
if (rootType.name().equals(type)) {
|
||||
return rootType;
|
||||
}
|
||||
}
|
||||
return DEFAULT_JAR_DIRECTORY_TYPE;
|
||||
}
|
||||
|
||||
private void readProperties(Element element) {
|
||||
@@ -324,25 +322,26 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
}
|
||||
}
|
||||
|
||||
private void readName(Element element) {
|
||||
private void readName(@NotNull Element element) {
|
||||
myName = element.getAttributeValue(LIBRARY_NAME_ATTR);
|
||||
}
|
||||
|
||||
private void readRoots(Element element) throws InvalidDataException {
|
||||
private void readRoots(@NotNull Element element) throws InvalidDataException {
|
||||
for (OrderRootType rootType : getAllRootTypes()) {
|
||||
final Element rootChild = element.getChild(rootType.name());
|
||||
if (rootChild == null) {
|
||||
continue;
|
||||
}
|
||||
VirtualFilePointerContainer roots = myRoots.get(rootType);
|
||||
roots.readExternal(rootChild, ROOT_PATH_ELEMENT);
|
||||
roots.readExternal(rootChild, ROOT_PATH_ELEMENT, false);
|
||||
}
|
||||
Element excludedRoot = element.getChild(EXCLUDED_ROOTS_TAG);
|
||||
if (excludedRoot != null) {
|
||||
getOrCreateExcludedRoots().readExternal(excludedRoot, ROOT_PATH_ELEMENT);
|
||||
getOrCreateExcludedRoots().readExternal(excludedRoot, ROOT_PATH_ELEMENT, false);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private VirtualFilePointerContainer getOrCreateExcludedRoots() {
|
||||
if (myExcludedRoots == null) {
|
||||
myExcludedRoots = VirtualFilePointerManager.getInstance().createContainer(myPointersDisposable);
|
||||
@@ -352,7 +351,8 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
|
||||
//TODO<rv> Remove the next two methods as a temporary solution. Sort in OrderRootType.
|
||||
//
|
||||
public static List<OrderRootType> sortRootTypes(Collection<OrderRootType> rootTypes) {
|
||||
@NotNull
|
||||
private static List<OrderRootType> sortRootTypes(@NotNull Collection<OrderRootType> rootTypes) {
|
||||
List<OrderRootType> allTypes = new ArrayList<>(rootTypes);
|
||||
Collections.sort(allTypes, (o1, o2) -> o1.name().compareToIgnoreCase(o2.name()));
|
||||
return allTypes;
|
||||
@@ -389,11 +389,11 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
}
|
||||
if (ProjectUtilCore.isExternalStorageEnabled(project)) {
|
||||
//we can add this attribute only if the library configuration will be stored separately, otherwise we will get modified files in .idea/libraries.
|
||||
element.setAttribute(EXTERNAL_SYSTEM_ID_ATTRIBUTE, myExternalSource.getId());
|
||||
element.setAttribute(StateSplitterEx.EXTERNAL_SYSTEM_ID_ATTRIBUTE, myExternalSource.getId());
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<OrderRootType> storableRootTypes = new ArrayList<>(Arrays.asList(OrderRootType.getAllTypes()));
|
||||
List<OrderRootType> storableRootTypes = new ArrayList<>(Arrays.asList(OrderRootType.getAllTypes()));
|
||||
if (myKind != null) {
|
||||
storableRootTypes.addAll(Arrays.asList(myKind.getAdditionalRootTypes()));
|
||||
}
|
||||
@@ -405,18 +405,41 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
}
|
||||
|
||||
final Element rootTypeElement = new Element(rootType.name());
|
||||
roots.writeExternal(rootTypeElement, ROOT_PATH_ELEMENT);
|
||||
roots.writeExternal(rootTypeElement, ROOT_PATH_ELEMENT, false);
|
||||
element.addContent(rootTypeElement);
|
||||
}
|
||||
if (myExcludedRoots != null && myExcludedRoots.size() > 0) {
|
||||
Element excluded = new Element(EXCLUDED_ROOTS_TAG);
|
||||
myExcludedRoots.writeExternal(excluded, ROOT_PATH_ELEMENT);
|
||||
myExcludedRoots.writeExternal(excluded, ROOT_PATH_ELEMENT, false);
|
||||
element.addContent(excluded);
|
||||
}
|
||||
myJarDirectories.writeExternal(element);
|
||||
writeJarDirectories(element);
|
||||
rootElement.addContent(element);
|
||||
}
|
||||
|
||||
// just to maintain .xml compatibility
|
||||
// VirtualFilePointerContainerImpl does the same but stores its jar dirs attributes inside <root> element
|
||||
@Deprecated // todo to remove sometime later
|
||||
private void writeJarDirectories(Element element) {
|
||||
final List<OrderRootType> rootTypes = sortRootTypes(myRoots.keySet());
|
||||
for (OrderRootType rootType : rootTypes) {
|
||||
VirtualFilePointerContainer container = myRoots.get(rootType);
|
||||
List<Pair<String, Boolean>> jarDirectories = new ArrayList<>(container.getJarDirectories());
|
||||
Collections.sort(jarDirectories, Comparator.comparing(p->p.getFirst(), String.CASE_INSENSITIVE_ORDER));
|
||||
for (Pair<String, Boolean> pair : jarDirectories) {
|
||||
String url = pair.getFirst();
|
||||
boolean isRecursive = pair.getSecond();
|
||||
final Element jarDirElement = new Element(VirtualFilePointerContainerImpl.JAR_DIRECTORY_ELEMENT);
|
||||
jarDirElement.setAttribute(VirtualFilePointerContainerImpl.URL_ATTR, url);
|
||||
jarDirElement.setAttribute(VirtualFilePointerContainerImpl.RECURSIVE_ATTR, Boolean.toString(isRecursive));
|
||||
if (!rootType.equals(DEFAULT_JAR_DIRECTORY_TYPE)) {
|
||||
jarDirElement.setAttribute(ROOT_TYPE_ATTR, rootType.name());
|
||||
}
|
||||
element.addContent(jarDirElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWritable() {
|
||||
return mySource != null;
|
||||
}
|
||||
@@ -465,7 +488,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKind(PersistentLibraryKind<?> kind) {
|
||||
public void setKind(@NotNull PersistentLibraryKind<?> kind) {
|
||||
LOG.assertTrue(isWritable());
|
||||
LOG.assertTrue(myKind == null || myKind == kind, "Library kind cannot be changed from " + myKind + " to " + kind);
|
||||
myKind = kind;
|
||||
@@ -492,12 +515,12 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
|
||||
@Override
|
||||
public void addJarDirectory(@NotNull final String url, final boolean recursive) {
|
||||
addJarDirectory(url, recursive, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE);
|
||||
addJarDirectory(url, recursive, OrderRootType.CLASSES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addJarDirectory(@NotNull final VirtualFile file, final boolean recursive) {
|
||||
addJarDirectory(file, recursive, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE);
|
||||
addJarDirectory(file, recursive, OrderRootType.CLASSES);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -506,8 +529,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
LOG.assertTrue(isWritable());
|
||||
|
||||
final VirtualFilePointerContainer container = myRoots.get(rootType);
|
||||
container.add(url);
|
||||
myJarDirectories.add(rootType, url, recursive);
|
||||
container.addJarDirectory(url, recursive);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -516,18 +538,19 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
LOG.assertTrue(isWritable());
|
||||
|
||||
final VirtualFilePointerContainer container = myRoots.get(rootType);
|
||||
container.add(file);
|
||||
myJarDirectories.add(rootType, file.getUrl(), recursive);
|
||||
container.addJarDirectory(file.getUrl(), recursive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJarDirectory(@NotNull final String url) {
|
||||
return isJarDirectory(url, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE);
|
||||
return isJarDirectory(url, OrderRootType.CLASSES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJarDirectory(@NotNull final String url, @NotNull final OrderRootType rootType) {
|
||||
return myJarDirectories.contains(rootType, url);
|
||||
VirtualFilePointerContainer container = myRoots.get(rootType);
|
||||
List<Pair<String, Boolean>> jarDirectories = container.getJarDirectories();
|
||||
return jarDirectories.contains(Pair.create(url, false)) || jarDirectories.contains(Pair.create(url, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -556,10 +579,9 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
}
|
||||
}
|
||||
}
|
||||
myJarDirectories.remove(rootType, url);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return container.removeJarDirectory(url);
|
||||
}
|
||||
|
||||
private boolean isUnderRoots(@NotNull String url) {
|
||||
@@ -594,29 +616,8 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
return !mySource.equals(this);
|
||||
}
|
||||
|
||||
private boolean areRootsChanged(final LibraryImpl that) {
|
||||
private boolean areRootsChanged(@NotNull LibraryImpl that) {
|
||||
return !that.equals(this);
|
||||
//final OrderRootType[] allTypes = OrderRootType.getAllTypes();
|
||||
//for (OrderRootType type : allTypes) {
|
||||
// final String[] urls = getUrls(type);
|
||||
// final String[] thatUrls = that.getUrls(type);
|
||||
// if (urls.length != thatUrls.length) {
|
||||
// return true;
|
||||
// }
|
||||
// for (int idx = 0; idx < urls.length; idx++) {
|
||||
// final String url = urls[idx];
|
||||
// final String thatUrl = thatUrls[idx];
|
||||
// if (!Comparing.equal(url, thatUrl)) {
|
||||
// return true;
|
||||
// }
|
||||
// final Boolean jarDirRecursive = myJarDirectories.get(url);
|
||||
// final Boolean sourceJarDirRecursive = that.myJarDirectories.get(thatUrl);
|
||||
// if (jarDirRecursive == null ? sourceJarDirRecursive != null : !jarDirRecursive.equals(sourceJarDirRecursive)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//return false;
|
||||
}
|
||||
|
||||
public Library getSource() {
|
||||
@@ -648,18 +649,16 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
if (areRootsChanged(fromModel)) {
|
||||
disposeMyPointers();
|
||||
copyRootsFrom(fromModel);
|
||||
myJarDirectories.copyFrom(fromModel.myJarDirectories);
|
||||
myRootsWatcher.updateWatchedRoots();
|
||||
myRootProvider.fireRootSetChanged();
|
||||
fireRootSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void copyRootsFrom(LibraryImpl fromModel) {
|
||||
private void copyRootsFrom(@NotNull LibraryImpl fromModel) {
|
||||
Map<OrderRootType, VirtualFilePointerContainer> clonedRoots = ContainerUtil.newHashMap();
|
||||
for (Map.Entry<OrderRootType, VirtualFilePointerContainer> entry : fromModel.myRoots.entrySet()) {
|
||||
OrderRootType rootType = entry.getKey();
|
||||
VirtualFilePointerContainer container = entry.getValue();
|
||||
VirtualFilePointerContainer clone = container.clone(myPointersDisposable);
|
||||
VirtualFilePointerContainer clone = container.clone(myPointersDisposable, getListener());
|
||||
clonedRoots.put(rootType, clone);
|
||||
}
|
||||
myRoots.clear();
|
||||
@@ -680,24 +679,6 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
Disposer.register(this, myPointersDisposable);
|
||||
}
|
||||
|
||||
private class MyRootProviderImpl extends RootProviderBaseImpl {
|
||||
@Override
|
||||
@NotNull
|
||||
public String[] getUrls(@NotNull OrderRootType rootType) {
|
||||
Set<String> originalUrls = new LinkedHashSet<>(Arrays.asList(LibraryImpl.this.getUrls(rootType)));
|
||||
for (VirtualFile file : getFiles(rootType)) { // Add those expanded with jar directories.
|
||||
originalUrls.add(file.getUrl());
|
||||
}
|
||||
return ArrayUtil.toStringArray(originalUrls);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public VirtualFile[] getFiles(@NotNull final OrderRootType rootType) {
|
||||
return LibraryImpl.this.getFiles(rootType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LibraryTable getTable() {
|
||||
return myLibraryTable;
|
||||
@@ -709,7 +690,6 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
|
||||
final LibraryImpl library = (LibraryImpl)o;
|
||||
|
||||
if (!myJarDirectories.equals(library.myJarDirectories)) return false;
|
||||
if (myName != null ? !myName.equals(library.myName) : library.myName != null) return false;
|
||||
if (myRoots != null ? !myRoots.equals(library.myRoots) : library.myRoots != null) return false;
|
||||
if (myKind != null ? !myKind.equals(library.myKind) : library.myKind != null) return false;
|
||||
@@ -722,18 +702,36 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
public int hashCode() {
|
||||
int result = myName != null ? myName.hashCode() : 0;
|
||||
result = 31 * result + (myRoots != null ? myRoots.hashCode() : 0);
|
||||
result = 31 * result + myJarDirectories.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNls
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Library: name:" + myName + "; jars:" + myJarDirectories + "; roots:" + myRoots.values();
|
||||
return "Library: name:" + myName + "; roots:" + myRoots.values();
|
||||
}
|
||||
|
||||
@Nullable("will return non-null value only for module level libraries")
|
||||
public Module getModule() {
|
||||
return myRootModel == null ? null : myRootModel.getModule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRootSetChangedListener(@NotNull RootSetChangedListener listener) {
|
||||
myDispatcher.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRootSetChangedListener(@NotNull RootSetChangedListener listener) {
|
||||
myDispatcher.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRootSetChangedListener(@NotNull RootSetChangedListener listener, @NotNull Disposable parentDisposable) {
|
||||
myDispatcher.addListener(listener, parentDisposable);
|
||||
}
|
||||
|
||||
private void fireRootSetChanged() {
|
||||
myDispatcher.getMulticaster().rootSetChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ class FileAssociationsManagerImpl extends FileAssociationsManager implements Pro
|
||||
if (url != null) {
|
||||
final VirtualFilePointer pointer = myFilePointerManager.create(url, myProject, null);
|
||||
final VirtualFilePointerContainer container = myFilePointerManager.createContainer(myProject);
|
||||
container.readExternal(child, "association");
|
||||
container.readExternal(child, "association", false);
|
||||
myAssociations.put(pointer, container);
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ class FileAssociationsManagerImpl extends FileAssociationsManager implements Pro
|
||||
final Element e = new Element("file");
|
||||
e.setAttribute("url", pointer.getUrl());
|
||||
final VirtualFilePointerContainer container = myAssociations.get(pointer);
|
||||
container.writeExternal(e, "association");
|
||||
container.writeExternal(e, "association", false);
|
||||
element.addContent(e);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user