project structure dialog: help user to avoid mistakes while editing roots of Maven libraries (IDEA-186751)

Now it isn't possible to manually add new roots to repository libraries (except roots with external annotations) and when a root is deleted we automatically mark the corresponding artifact as excluded in the library configuration.

GitOrigin-RevId: 43b368ff367f5fc330e1be67267a5edbed37ab86
This commit is contained in:
nik
2019-10-01 14:38:32 +03:00
committed by intellij-monorepo-bot
parent 9307d5a030
commit 4146be3312
5 changed files with 136 additions and 10 deletions

View File

@@ -0,0 +1,93 @@
// Copyright 2000-2019 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.jarRepository;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.ui.AttachRootButtonDescriptor;
import com.intellij.openapi.roots.libraries.ui.LibraryRootsComponentDescriptor;
import com.intellij.openapi.roots.libraries.ui.OrderRootTypePresentation;
import com.intellij.openapi.roots.libraries.ui.RootDetector;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.DefaultLibraryRootsComponentDescriptor;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.utils.library.RepositoryLibraryProperties;
import java.io.File;
import java.util.Collections;
import java.util.List;
class RepositoryLibraryRootsComponentDescriptor extends LibraryRootsComponentDescriptor {
private static final Logger LOG = Logger.getInstance(RepositoryLibraryRootsComponentDescriptor.class);
@Nullable
@Override
public OrderRootTypePresentation getRootTypePresentation(@NotNull OrderRootType type) {
return DefaultLibraryRootsComponentDescriptor.getDefaultPresentation(type);
}
@NotNull
@Override
public List<? extends RootDetector> getRootDetectors() {
return Collections.singletonList(DefaultLibraryRootsComponentDescriptor.createAnnotationsRootDetector());
}
@NotNull
@Override
public FileChooserDescriptor createAttachFilesChooserDescriptor(@Nullable String libraryName) {
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
descriptor.setTitle("Attach External Annotations");
descriptor.setDescription("Select directory where external annotations are located");
return descriptor;
}
@Override
public String getAttachFilesActionName() {
return "Attach Annotations...";
}
@NotNull
@Override
public List<? extends AttachRootButtonDescriptor> createAttachButtons() {
return Collections.emptyList();
}
@NotNull
@Override
public RootRemovalHandler createRootRemovalHandler() {
return new RootRemovalHandler() {
@Override
public void onRootRemoved(@NotNull String rootUrl, @NotNull OrderRootType rootType, @NotNull LibraryEditor libraryEditor) {
if (rootType == OrderRootType.CLASSES) {
String coordinates = getMavenCoordinates(rootUrl);
if (coordinates != null) {
RepositoryLibraryProperties properties = (RepositoryLibraryProperties)libraryEditor.getProperties();
properties.setExcludedDependencies(ContainerUtil.append(properties.getExcludedDependencies(), coordinates));
}
else {
LOG.warn("Cannot determine Maven coordinates for removed library root " + rootUrl);
}
}
}
};
}
@Nullable
private static String getMavenCoordinates(@NotNull String jarUrl) {
File jarFile = new File(PathUtil.getLocalPath(VfsUtilCore.urlToPath(jarUrl)));
if (jarFile.getParentFile() == null) return null;
File artifactDir = jarFile.getParentFile().getParentFile();
if (artifactDir == null) return null;
File localRepoRoot = JarRepositoryManager.getLocalRepositoryPath();
if (!FileUtil.isAncestor(localRepoRoot, artifactDir, true)) return null;
String relativePath = FileUtil.getRelativePath(localRepoRoot, artifactDir.getParentFile());
if (relativePath == null) return null;
return relativePath.replace(File.separatorChar, '.') + ":" + artifactDir.getName();
}
}

View File

@@ -19,8 +19,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.libraries.LibraryType;
import com.intellij.openapi.roots.libraries.NewLibraryConfiguration;
import com.intellij.openapi.roots.libraries.PersistentLibraryKind;
import com.intellij.openapi.roots.libraries.ui.LibraryEditorComponent;
import com.intellij.openapi.roots.libraries.ui.LibraryPropertiesEditor;
import com.intellij.openapi.roots.libraries.ui.*;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -84,4 +83,10 @@ public class RepositoryLibraryType extends LibraryType<RepositoryLibraryProperti
RepositoryLibraryDescription description = RepositoryLibraryDescription.findDescription(properties);
return "Maven: " + description.getDisplayName(properties.getVersion());
}
@Nullable
@Override
public LibraryRootsComponentDescriptor createLibraryRootsComponentDescriptor() {
return new RepositoryLibraryRootsComponentDescriptor();
}
}

View File

@@ -63,12 +63,17 @@ public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponen
results.addAll(LibrarySourceRootDetectorUtil.JAVA_SOURCE_ROOT_DETECTOR.getExtensionList());
results.add(DescendentBasedRootFilter.createFileTypeBasedFilter(OrderRootType.SOURCES, true, StdFileTypes.JAVA, "source archive directory"));
results.add(new JavadocRootDetector());
results.add(new DescendentBasedRootFilter(AnnotationOrderRootType.getInstance(), false, "external annotations",
file -> ExternalAnnotationsManager.ANNOTATIONS_XML.equals(file.getName())));
results.add(createAnnotationsRootDetector());
results.add(new NativeLibraryRootFilter());
return results;
}
@NotNull
public static DescendentBasedRootFilter createAnnotationsRootDetector() {
return new DescendentBasedRootFilter(AnnotationOrderRootType.getInstance(), false, "external annotations",
file -> ExternalAnnotationsManager.ANNOTATIONS_XML.equals(file.getName()));
}
private static boolean isNativeLibrary(VirtualFile file) {
String extension = file.getExtension();
return extension != null && NATIVE_LIBRARY_EXTENSIONS.contains(extension);

View File

@@ -78,6 +78,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
private Module myContextModule;
private LibraryRootsComponent.AddExcludedRootActionButton myAddExcludedRootActionButton;
private StructureTreeModel<AbstractTreeStructure> myTreeModel;
private LibraryRootsComponentDescriptor.RootRemovalHandler myRootRemovalHandler;
public LibraryRootsComponent(@Nullable Project project, @NotNull LibraryEditor libraryEditor) {
this(project, new Computable.PredefinedValueComputable<>(libraryEditor));
@@ -99,6 +100,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
if (myDescriptor == null) {
myDescriptor = new DefaultLibraryRootsComponentDescriptor();
}
myRootRemovalHandler = myDescriptor.createRootRemovalHandler();
myModificationOfImportedModelWarningComponent = new ModificationOfImportedModelWarningComponent();
myBottomPanel.add(BorderLayout.CENTER, myModificationOfImportedModelWarningComponent.getLabel());
init(new LibraryTreeStructure(this, myDescriptor));
@@ -187,19 +189,21 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
ApplicationManager.getApplication().runWriteAction(() -> {
for (Object selectedElement : selectedElements) {
LibraryEditor libraryEditor = getLibraryEditor();
if (selectedElement instanceof ItemElement) {
final ItemElement itemElement = (ItemElement)selectedElement;
getLibraryEditor().removeRoot(itemElement.getUrl(), itemElement.getRootType());
libraryEditor.removeRoot(itemElement.getUrl(), itemElement.getRootType());
myRootRemovalHandler.onRootRemoved(itemElement.getUrl(), itemElement.getRootType(), libraryEditor);
}
else if (selectedElement instanceof OrderRootTypeElement) {
final OrderRootType rootType = ((OrderRootTypeElement)selectedElement).getOrderRootType();
final String[] urls = getLibraryEditor().getUrls(rootType);
final String[] urls = libraryEditor.getUrls(rootType);
for (String url : urls) {
getLibraryEditor().removeRoot(url, rootType);
libraryEditor.removeRoot(url, rootType);
}
}
else if (selectedElement instanceof ExcludedRootElement) {
getLibraryEditor().removeExcludedRoot(((ExcludedRootElement)selectedElement).getUrl());
libraryEditor.removeExcludedRoot(((ExcludedRootElement)selectedElement).getUrl());
}
}
});
@@ -226,13 +230,14 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
toolbarDecorator.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
AttachFilesAction attachFilesAction = new AttachFilesAction(myDescriptor.getAttachFilesActionName());
if (popupItems.isEmpty()) {
new AttachFilesAction(myDescriptor.getAttachFilesActionName()).perform();
attachFilesAction.perform();
return;
}
List<AnAction> actions = new ArrayList<>();
actions.add(new AttachFilesAction(myDescriptor.getAttachFilesActionName()));
actions.add(attachFilesAction);
for (AttachRootButtonDescriptor descriptor : popupItems) {
actions.add(new AttachItemAction(descriptor, descriptor.getButtonText(), null));
}

View File

@@ -17,6 +17,7 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.ui.impl.LibraryRootsDetectorImpl;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -74,6 +75,19 @@ public abstract class LibraryRootsComponentDescriptor {
return descriptor;
}
/**
* Creates a instance which will be notified when a root is removed in the library editor.
*/
@NotNull
public RootRemovalHandler createRootRemovalHandler() {
return new RootRemovalHandler() {
@Override
public void onRootRemoved(@NotNull String rootUrl, @NotNull OrderRootType rootType, @NotNull LibraryEditor libraryEditor) {
}
};
}
/**
* @return descriptors for additional 'Attach' buttons in the library roots editor
*/
@@ -91,4 +105,8 @@ public abstract class LibraryRootsComponentDescriptor {
public String getAttachFilesActionName() {
return ProjectBundle.message("button.text.attach.files");
}
public interface RootRemovalHandler {
void onRootRemoved(@NotNull String rootUrl, @NotNull OrderRootType rootType, @NotNull LibraryEditor libraryEditor);
}
}