diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/LibrariesModifiableModel.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/LibrariesModifiableModel.java index dd4cd4212c45..f95672041fd8 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/LibrariesModifiableModel.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/LibrariesModifiableModel.java @@ -17,6 +17,7 @@ package com.intellij.openapi.roots.ui.configuration.projectRoot; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.openapi.roots.impl.libraries.LibraryImpl; import com.intellij.openapi.roots.impl.libraries.LibraryTableBase; import com.intellij.openapi.roots.libraries.Library; @@ -62,8 +63,13 @@ public class LibrariesModifiableModel implements LibraryTableBase.ModifiableMode @Override public Library createLibrary(String name, @Nullable PersistentLibraryKind type) { - final Library library = getLibrariesModifiableModel().createLibrary(name, type); - //createLibraryEditor(library); \ + return createLibrary(name, type, null); + } + + @Override + public Library createLibrary(String name, @Nullable PersistentLibraryKind type, @Nullable ProjectModelExternalSource externalSource) { + final Library library = getLibrariesModifiableModel().createLibrary(name, type, externalSource); + //createLibraryEditor(library); final BaseLibrariesConfigurable configurable = ProjectStructureConfigurable.getInstance(myProject).getConfigurableFor(library); configurable.createLibraryNode(library); return library; diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/IdeModifiableModelsProvider.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/IdeModifiableModelsProvider.java index 03c918416c70..170f507097a5 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/IdeModifiableModelsProvider.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/IdeModifiableModelsProvider.java @@ -21,6 +21,7 @@ import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.packaging.artifacts.ModifiableArtifactModel; @@ -59,6 +60,8 @@ public interface IdeModifiableModelsProvider extends IdeModelsProvider { Library createLibrary(String name); + Library createLibrary(String name, @Nullable ProjectModelExternalSource externalSource); + void removeLibrary(Library library); ModalityState getModalityStateForQuestionDialogs(); diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java index fff1bfd5ced6..3531aa280f30 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java @@ -37,8 +37,10 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ExternalProjectSystemRegistry; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Conditions; @@ -794,6 +796,10 @@ public class ExternalSystemApiUtil { return (T)loader.loadClass(clazz.getName()).newInstance(); } + public static ProjectModelExternalSource toExternalSource(@NotNull ProjectSystemId systemId) { + return ExternalProjectSystemRegistry.getInstance().getSourceById(systemId.getId()); + } + @Contract(value = "_, null -> false", pure=true) public static boolean isExternalSystemAwareModule(@NotNull ProjectSystemId systemId, @Nullable Module module) { return module != null && !module.isDisposed() && systemId.getId().equals(module.getOptionValue(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY)); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/AbstractIdeModifiableModelsProvider.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/AbstractIdeModifiableModelsProvider.java index 11e0b0c999c8..90e214954583 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/AbstractIdeModifiableModelsProvider.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/AbstractIdeModifiableModelsProvider.java @@ -236,6 +236,11 @@ public abstract class AbstractIdeModifiableModelsProvider extends IdeModelsProvi return getModifiableProjectLibrariesModel().createLibrary(name); } + @Override + public Library createLibrary(String name, @Nullable ProjectModelExternalSource externalSource) { + return getModifiableProjectLibrariesModel().createLibrary(name, null, externalSource); + } + @Override public void removeLibrary(Library library) { getModifiableProjectLibrariesModel().removeLibrary(library); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java index 00d5b7fa93a8..b48cc4e9304d 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java @@ -78,7 +78,7 @@ public class LibraryDataService extends AbstractProjectDataService () -> StringUtil.capitalize(sourceId.toLowerCase(Locale.US))); + public ProjectModelExternalSource getSourceById(String id) { + return myExternalSources.computeIfAbsent(id, ProjectModelExternalSourceImpl::new); + } + + private static class ProjectModelExternalSourceImpl implements ProjectModelExternalSource { + private final String myId; + private final String myDisplayName; + + public ProjectModelExternalSourceImpl(String id) { + myId = id; + //todo[nik] specify display name explicitly instead, the current code is copied from ProjectSystemId constructor + myDisplayName = StringUtil.capitalize(myId.toLowerCase(Locale.US)); + } + + @NotNull + @Override + public String getDisplayName() { + return myDisplayName; + } + + @NotNull + @Override + public String getId() { + return myId; + } } } diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/ExternalProjectSystemRegistry.java b/platform/projectModel-api/src/com/intellij/openapi/roots/ExternalProjectSystemRegistry.java index a173d106c1b5..166c4d2b0b7b 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/ExternalProjectSystemRegistry.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/ExternalProjectSystemRegistry.java @@ -18,6 +18,7 @@ package com.intellij.openapi.roots; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.module.Module; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -29,9 +30,16 @@ public interface ExternalProjectSystemRegistry { return ServiceManager.getService(ExternalProjectSystemRegistry.class); } + @NotNull + ProjectModelExternalSource getSourceById(String id); + @Nullable ProjectModelExternalSource getExternalSource(Module module); + /** + * These fields are temporary added to API until we have proper extension points for different external systems. + */ + String MAVEN_EXTERNAL_SOURCE_ID = "Maven"; String EXTERNAL_SYSTEM_ID_KEY = "external.system.id"; String IS_MAVEN_MODULE_KEY = "org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule"; } diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectModelExternalSource.java b/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectModelExternalSource.java index 5aa3d9279806..4d116febd617 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectModelExternalSource.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectModelExternalSource.java @@ -28,4 +28,7 @@ import org.jetbrains.annotations.NotNull; public interface ProjectModelExternalSource { @NotNull String getDisplayName(); + + @NotNull + String getId(); } diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/Library.java b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/Library.java index 8a2bda7ade0f..66ee8e2f570d 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/Library.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/Library.java @@ -17,6 +17,7 @@ package com.intellij.openapi.roots.libraries; import com.intellij.openapi.Disposable; import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.ProjectModelElement; import com.intellij.openapi.roots.RootProvider; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.vfs.VirtualFile; @@ -27,7 +28,7 @@ import org.jetbrains.annotations.Nullable; /** * @author dsl */ -public interface Library extends JDOMExternalizable, Disposable { +public interface Library extends JDOMExternalizable, Disposable, ProjectModelElement { Library[] EMPTY_ARRAY = new Library[0]; @Nullable String getName(); diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryTable.java b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryTable.java index 02e0d9faa6c9..c8da4d68f2ad 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryTable.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryTable.java @@ -16,6 +16,7 @@ package com.intellij.openapi.roots.libraries; import com.intellij.openapi.Disposable; +import com.intellij.openapi.roots.ProjectModelExternalSource; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -71,6 +72,8 @@ public interface LibraryTable { Library createLibrary(String name, @Nullable PersistentLibraryKind type); + Library createLibrary(String name, @Nullable PersistentLibraryKind type, @Nullable ProjectModelExternalSource externalSource); + void removeLibrary(@NotNull Library library); void commit(); diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryOrderEntryImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryOrderEntryImpl.java index 94304fa8941d..10cd2130a301 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryOrderEntryImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryOrderEntryImpl.java @@ -55,9 +55,10 @@ public class ModuleLibraryOrderEntryImpl extends LibraryOrderEntryBaseImpl imple myScope = scope; } - ModuleLibraryOrderEntryImpl(String name, final PersistentLibraryKind kind, @NotNull RootModelImpl rootModel, @NotNull ProjectRootManagerImpl projectRootManager) { + ModuleLibraryOrderEntryImpl(String name, final PersistentLibraryKind kind, @NotNull RootModelImpl rootModel, + @NotNull ProjectRootManagerImpl projectRootManager, ProjectModelExternalSource externalSource) { super(rootModel, projectRootManager); - myLibrary = LibraryTableImplUtil.createModuleLevelLibrary(name, kind, getRootModel()); + myLibrary = LibraryTableImplUtil.createModuleLevelLibrary(name, kind, getRootModel(), externalSource); doinit(); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryTable.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryTable.java index beed83d17e78..a3f3807e52ce 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryTable.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryTable.java @@ -21,6 +21,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.openapi.roots.impl.libraries.LibraryTableBase; import com.intellij.openapi.roots.impl.libraries.LibraryTableImplUtil; import com.intellij.openapi.roots.libraries.Library; @@ -90,8 +91,13 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi } @Override - public Library createLibrary(String name, @Nullable PersistentLibraryKind kind) { - LibraryOrderEntry orderEntry = new ModuleLibraryOrderEntryImpl(name, kind, myRootModel, myProjectRootManager); + public Library createLibrary(String name, @Nullable PersistentLibraryKind type) { + return createLibrary(name, type, null); + } + + @Override + public Library createLibrary(String name, @Nullable PersistentLibraryKind kind, @Nullable ProjectModelExternalSource externalSource) { + LibraryOrderEntry orderEntry = new ModuleLibraryOrderEntryImpl(name, kind, myRootModel, myProjectRootManager, externalSource); myRootModel.addOrderEntry(orderEntry); return orderEntry.getLibrary(); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java index b4a101d56b2f..bdd6dc80671c 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java @@ -20,13 +20,12 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ComponentSerializationUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.ModifiableRootModel; -import com.intellij.openapi.roots.OrderRootType; -import com.intellij.openapi.roots.RootProvider; +import com.intellij.openapi.roots.*; 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.util.registry.Registry; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -64,6 +63,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi @NonNls public static final String PROPERTIES_ELEMENT = "properties"; private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters(); private static final String EXCLUDED_ROOTS_TAG = "excluded"; + private static final String EXTERNAL_SYSTEM_ID_ATTRIBUTE = "external-system-id"; private String myName; private final LibraryTable myLibraryTable; private final Map myRoots; @@ -78,15 +78,22 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi private boolean myDisposed; private final Disposable myPointersDisposable = Disposer.newDisposable(); private final JarDirectoryWatcher myRootsWatcher = JarDirectoryWatcherFactory.getInstance().createWatcher(myJarDirectories, myRootProvider); + private final ProjectModelExternalSource myExternalSource; LibraryImpl(LibraryTable table, @NotNull Element element, ModifiableRootModel rootModel) throws InvalidDataException { - this(table, rootModel, null, element.getAttributeValue(LIBRARY_NAME_ATTR), findPersistentLibraryKind(element)); + 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); @@ -98,15 +105,16 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi return (PersistentLibraryKind)kind; } - LibraryImpl(String name, @Nullable final PersistentLibraryKind kind, LibraryTable table, ModifiableRootModel rootModel) { - this(table, rootModel, null, name, kind); + LibraryImpl(String name, @Nullable final PersistentLibraryKind kind, LibraryTable table, ModifiableRootModel rootModel, + ProjectModelExternalSource externalSource) { + this(table, rootModel, null, name, kind, externalSource); if (kind != null) { myProperties = kind.createDefaultProperties(); } } private LibraryImpl(@NotNull LibraryImpl from, LibraryImpl newSource, ModifiableRootModel rootModel) { - this(from.myLibraryTable, rootModel, newSource, from.myName, from.myKind); + this(from.myLibraryTable, rootModel, newSource, from.myName, from.myKind, from.myExternalSource); from.checkDisposed(); if (from.myKind != null && from.myProperties != null) { @@ -126,13 +134,15 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi } // primary - private LibraryImpl(LibraryTable table, ModifiableRootModel rootModel, LibraryImpl newSource, String name, @Nullable final PersistentLibraryKind kind) { + private LibraryImpl(LibraryTable table, ModifiableRootModel rootModel, LibraryImpl newSource, String name, + @Nullable final PersistentLibraryKind kind, @Nullable ProjectModelExternalSource externalSource) { super(true); myLibraryTable = table; myRootModel = rootModel; mySource = newSource; myKind = kind; myName = name; + myExternalSource = externalSource; //init roots depends on my myKind myRoots = initRoots(); Disposer.register(this, myRootsWatcher); @@ -279,6 +289,12 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi return result; } + @Nullable + @Override + public ProjectModelExternalSource getExternalSource() { + return myExternalSource; + } + @Override public void readExternal(Element element) throws InvalidDataException { readName(element); @@ -355,6 +371,12 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi } } } + + if (myExternalSource != null && Registry.is("store.imported.project.elements.separately")) { + //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()); + } + ArrayList storableRootTypes = new ArrayList<>(); storableRootTypes.addAll(Arrays.asList(OrderRootType.getAllTypes())); if (myKind != null) { diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java index 46b43ef33ea7..af09b6e2781a 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java @@ -22,6 +22,7 @@ import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.roots.libraries.PersistentLibraryKind; @@ -268,7 +269,7 @@ public abstract class LibraryTableBase implements PersistentStateComponent