mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[platform] make facetType extension point dynamic (IDEA-225619)
GitOrigin-RevId: f5365be5b326b65082f06b14bff1d3fcc810fd30
This commit is contained in:
committed by
intellij-monorepo-bot
parent
099d5fcf7c
commit
18141a240d
@@ -6,6 +6,8 @@ import com.intellij.facet.mock.MockFacetConfiguration;
|
||||
import com.intellij.facet.mock.MockFacetType;
|
||||
import com.intellij.facet.mock.MockSubFacetType;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.roots.ProjectModelExternalSource;
|
||||
import com.intellij.testFramework.HeavyPlatformTestCase;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -32,12 +34,14 @@ public abstract class FacetTestCase extends HeavyPlatformTestCase {
|
||||
}
|
||||
|
||||
protected void removeAllFacets() {
|
||||
final FacetManager manager = getFacetManager();
|
||||
final ModifiableFacetModel model = manager.createModifiableModel();
|
||||
for (Facet facet : manager.getAllFacets()) {
|
||||
model.removeFacet(facet);
|
||||
for (Module module : ModuleManager.getInstance(myProject).getModules()) {
|
||||
FacetManager manager = FacetManager.getInstance(module);
|
||||
ModifiableFacetModel model = manager.createModifiableModel();
|
||||
for (Facet<?> facet : manager.getAllFacets()) {
|
||||
model.removeFacet(facet);
|
||||
}
|
||||
commit(model);
|
||||
}
|
||||
commit(model);
|
||||
}
|
||||
|
||||
protected FacetManager getFacetManager() {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright 2000-2020 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.facet
|
||||
|
||||
import com.intellij.facet.impl.invalid.InvalidFacetManager
|
||||
import com.intellij.facet.mock.MockFacet
|
||||
import com.intellij.facet.mock.MockFacetConfiguration
|
||||
import com.intellij.facet.mock.MockFacetType
|
||||
import com.intellij.facet.mock.MockSubFacetType
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.testFramework.HeavyPlatformTestCase
|
||||
|
||||
class FacetTypeUnloadingTest : HeavyPlatformTestCase() {
|
||||
fun `test unload and load facet`() {
|
||||
val facetManager = FacetManager.getInstance(module)
|
||||
runWithRegisteredFacetTypes(MockFacetType()) {
|
||||
runWriteAction {
|
||||
val configuration = MockFacetConfiguration().apply {
|
||||
data = "my data"
|
||||
}
|
||||
val model = facetManager.createModifiableModel()
|
||||
model.addFacet(MockFacet(module, "mock", configuration))
|
||||
model.commit()
|
||||
}
|
||||
assertEquals("mock", facetManager.getFacetsByType(MockFacetType.ID).single().name)
|
||||
}
|
||||
|
||||
assertTrue(facetManager.getFacetsByType(MockFacetType.ID).isEmpty())
|
||||
val invalidFacet = InvalidFacetManager.getInstance(myProject).invalidFacets.single()
|
||||
assertEquals("mock", invalidFacet.name)
|
||||
assertEquals("<configuration data=\"my data\" />", JDOMUtil.write(invalidFacet.configuration.facetState.configuration))
|
||||
|
||||
registerFacetType(MockFacetType(), testRootDisposable)
|
||||
assertTrue(InvalidFacetManager.getInstance(myProject).invalidFacets.isEmpty())
|
||||
val mockFacet = facetManager.getFacetsByType(MockFacetType.ID).single()
|
||||
assertEquals("mock", mockFacet.name)
|
||||
assertEquals("my data", mockFacet.configuration.data)
|
||||
}
|
||||
|
||||
fun `test unload and load facet with sub facets`() {
|
||||
val facetManager = FacetManager.getInstance(module)
|
||||
runWithRegisteredFacetTypes(MockFacetType(), MockSubFacetType()) {
|
||||
runWriteAction {
|
||||
val model = facetManager.createModifiableModel()
|
||||
val facet = MockFacet(module, "mock")
|
||||
model.addFacet(facet)
|
||||
model.addFacet(MockSubFacetType.getInstance().createFacet(module, "sub-facet", MockFacetConfiguration(), facet))
|
||||
model.commit()
|
||||
}
|
||||
assertEquals("mock", facetManager.getFacetsByType(MockFacetType.ID).single().name)
|
||||
assertEquals("sub-facet", facetManager.getFacetsByType(MockSubFacetType.ID).single().name)
|
||||
}
|
||||
|
||||
assertTrue(facetManager.getFacetsByType(MockFacetType.ID).isEmpty())
|
||||
assertTrue(facetManager.getFacetsByType(MockSubFacetType.ID).isEmpty())
|
||||
val invalidFacet = InvalidFacetManager.getInstance(myProject).invalidFacets.single()
|
||||
assertEquals("mock", invalidFacet.name)
|
||||
val subFacetState = invalidFacet.configuration.facetState.subFacets.single()
|
||||
assertEquals("sub-facet", subFacetState.name)
|
||||
|
||||
registerFacetType(MockFacetType(), testRootDisposable)
|
||||
registerFacetType(MockSubFacetType(), testRootDisposable)
|
||||
|
||||
assertTrue(InvalidFacetManager.getInstance(myProject).invalidFacets.isEmpty())
|
||||
val mockFacet = facetManager.getFacetsByType(MockFacetType.ID).single()
|
||||
assertEquals("mock", mockFacet.name)
|
||||
val mockSubFacet = facetManager.getFacetsByType(MockSubFacetType.ID).single()
|
||||
assertEquals("sub-facet", mockSubFacet.name)
|
||||
assertSame(mockFacet, mockSubFacet.underlyingFacet)
|
||||
}
|
||||
|
||||
fun `test unload and load sub facet`() {
|
||||
val facetManager = FacetManager.getInstance(module)
|
||||
registerFacetType(MockFacetType(), testRootDisposable)
|
||||
runWithRegisteredFacetTypes(MockSubFacetType()) {
|
||||
runWriteAction {
|
||||
val model = facetManager.createModifiableModel()
|
||||
val facet = MockFacet(module, "mock")
|
||||
model.addFacet(facet)
|
||||
model.addFacet(MockSubFacetType.getInstance().createFacet(module, "sub-facet", MockFacetConfiguration(), facet))
|
||||
model.commit()
|
||||
}
|
||||
assertEquals("mock", facetManager.getFacetsByType(MockFacetType.ID).single().name)
|
||||
assertEquals("sub-facet", facetManager.getFacetsByType(MockSubFacetType.ID).single().name)
|
||||
}
|
||||
|
||||
val mockFacet = facetManager.getFacetsByType(MockFacetType.ID).single()
|
||||
assertEquals("mock", mockFacet.name)
|
||||
assertTrue(facetManager.getFacetsByType(MockSubFacetType.ID).isEmpty())
|
||||
val invalidFacet = InvalidFacetManager.getInstance(myProject).invalidFacets.single()
|
||||
assertEquals("sub-facet", invalidFacet.name)
|
||||
assertSame(mockFacet, invalidFacet.underlyingFacet)
|
||||
|
||||
registerFacetType(MockSubFacetType(), testRootDisposable)
|
||||
assertTrue(InvalidFacetManager.getInstance(myProject).invalidFacets.isEmpty())
|
||||
val mockSubFacet = facetManager.getFacetsByType(MockSubFacetType.ID).single()
|
||||
assertEquals("sub-facet", mockSubFacet.name)
|
||||
assertSame(mockFacet, mockSubFacet.underlyingFacet)
|
||||
}
|
||||
|
||||
private inline fun runWithRegisteredFacetTypes(vararg types: FacetType<*, *>, action: () -> Unit) {
|
||||
val disposable = Disposer.newDisposable()
|
||||
for (type in types) {
|
||||
registerFacetType(type, disposable)
|
||||
}
|
||||
|
||||
try {
|
||||
action()
|
||||
}
|
||||
finally {
|
||||
Disposer.dispose(disposable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerFacetType(type: FacetType<*, *>, disposable: Disposable) {
|
||||
val facetTypeDisposable = Disposer.newDisposable()
|
||||
Disposer.register(disposable, Disposable {
|
||||
runWriteAction {
|
||||
Disposer.dispose(facetTypeDisposable)
|
||||
}
|
||||
})
|
||||
FacetType.EP_NAME.getPoint(null).registerExtension(type, facetTypeDisposable)
|
||||
}
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
//initialize facet types and register listeners
|
||||
FacetTypeRegistry.getInstance().facetTypes
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.intellij.facet.ui.DefaultFacetSettingsEditor;
|
||||
import com.intellij.facet.ui.FacetEditor;
|
||||
import com.intellij.facet.ui.MultipleFacetSettingsEditor;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.PluginAware;
|
||||
import com.intellij.openapi.extensions.PluginDescriptor;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -24,13 +26,14 @@ import javax.swing.*;
|
||||
* </extensions>
|
||||
* </pre>
|
||||
*/
|
||||
public abstract class FacetType<F extends Facet, C extends FacetConfiguration> {
|
||||
public abstract class FacetType<F extends Facet, C extends FacetConfiguration> implements PluginAware {
|
||||
public static final ExtensionPointName<FacetType> EP_NAME = ExtensionPointName.create("com.intellij.facetType");
|
||||
|
||||
private final @NotNull FacetTypeId<F> myId;
|
||||
private final @NotNull String myStringId;
|
||||
private final @NotNull String myPresentableName;
|
||||
private final @Nullable FacetTypeId myUnderlyingFacetType;
|
||||
private PluginDescriptor myPluginDescriptor;
|
||||
|
||||
public static <T extends FacetType> T findInstance(Class<T> aClass) {
|
||||
return EP_NAME.findExtension(aClass);
|
||||
@@ -90,6 +93,15 @@ public abstract class FacetType<F extends Facet, C extends FacetConfiguration> {
|
||||
return myUnderlyingFacetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPluginDescriptor(@NotNull PluginDescriptor pluginDescriptor) {
|
||||
myPluginDescriptor = pluginDescriptor;
|
||||
}
|
||||
|
||||
public final PluginDescriptor getPluginDescriptor() {
|
||||
return myPluginDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this method is not called by IDE core anymore. Use {@link com.intellij.framework.detection.FrameworkDetector} extension
|
||||
* to provide automatic detection for facets
|
||||
|
||||
@@ -29,6 +29,13 @@ public interface ModifiableFacetModel extends FacetModel {
|
||||
void addFacet(Facet<?> facet, @Nullable ProjectModelExternalSource externalSource);
|
||||
void removeFacet(Facet<?> facet);
|
||||
|
||||
/**
|
||||
* Replaces {@code original} facet by {@code replacement}. The only difference with {@code removeFacet(original); addFacet(replacement); }
|
||||
* is that this method preserves order of facets in internal structures to avoid modifications of *.iml files.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
void replaceFacet(@NotNull Facet<?> original, @NotNull Facet<?> replacement);
|
||||
|
||||
void rename(Facet<?> facet, String newName);
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -38,10 +38,10 @@ public abstract class FacetManagerBase extends FacetManager {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <F extends Facet<?>, C extends FacetConfiguration> F createFacet(@NotNull Module module, @NotNull FacetType<F, C> type,
|
||||
@NotNull String name,
|
||||
@NotNull C configuration,
|
||||
@Nullable Facet<?> underlying) {
|
||||
protected static <F extends Facet<?>, C extends FacetConfiguration> F createFacet(@NotNull Module module, @NotNull FacetType<F, C> type,
|
||||
@NotNull String name,
|
||||
@NotNull C configuration,
|
||||
@Nullable Facet<?> underlying) {
|
||||
final F facet = type.createFacet(module, name, configuration, underlying);
|
||||
assertTrue(facet.getModule() == module, facet, "module");
|
||||
assertTrue(facet.getConfiguration() == configuration, facet, "configuration");
|
||||
@@ -126,17 +126,19 @@ public abstract class FacetManagerBase extends FacetManager {
|
||||
@NotNull
|
||||
public static InvalidFacet createInvalidFacet(@NotNull Module module, @NotNull FacetState state, @Nullable Facet<?> underlyingFacet,
|
||||
@NotNull String errorMessage,
|
||||
boolean unknownType) {
|
||||
boolean unknownType, boolean reportError) {
|
||||
Project project = module.getProject();
|
||||
final InvalidFacetManager invalidFacetManager = InvalidFacetManager.getInstance(project);
|
||||
final InvalidFacetType type = InvalidFacetType.getInstance();
|
||||
final InvalidFacetConfiguration configuration = new InvalidFacetConfiguration(state, errorMessage);
|
||||
final InvalidFacet facet = createFacet(module, type, StringUtil.notNullize(state.getName()), configuration, underlyingFacet);
|
||||
if (!invalidFacetManager.isIgnored(facet)) {
|
||||
FacetLoadingErrorDescription description = new FacetLoadingErrorDescription(facet);
|
||||
ProjectLoadingErrorsNotifier.getInstance(project).registerError(description);
|
||||
if (unknownType) {
|
||||
UnknownFeaturesCollector.getInstance(project).registerUnknownFeature("com.intellij.facetType", state.getFacetType(), "Facet");
|
||||
if (reportError) {
|
||||
InvalidFacetManager invalidFacetManager = InvalidFacetManager.getInstance(project);
|
||||
if (!invalidFacetManager.isIgnored(facet)) {
|
||||
FacetLoadingErrorDescription description = new FacetLoadingErrorDescription(facet);
|
||||
ProjectLoadingErrorsNotifier.getInstance(project).registerError(description);
|
||||
if (unknownType) {
|
||||
UnknownFeaturesCollector.getInstance(project).registerUnknownFeature("com.intellij.facetType", state.getFacetType(), "Facet");
|
||||
}
|
||||
}
|
||||
}
|
||||
return facet;
|
||||
|
||||
@@ -134,7 +134,7 @@ public final class FacetManagerImpl extends FacetManagerBase implements ModuleCo
|
||||
ModifiableFacetModel model,
|
||||
final Facet<?> underlyingFacet,
|
||||
final String errorMessage, boolean unknownType) {
|
||||
model.addFacet(createInvalidFacet(getModule(), state, underlyingFacet, errorMessage, unknownType));
|
||||
model.addFacet(createInvalidFacet(getModule(), state, underlyingFacet, errorMessage, unknownType, true));
|
||||
}
|
||||
|
||||
private <F extends Facet<C>, C extends FacetConfiguration> void addFacet(final FacetType<F, C> type, final FacetState state, final Facet<?> underlyingFacet,
|
||||
@@ -161,24 +161,39 @@ public final class FacetManagerImpl extends FacetManagerBase implements ModuleCo
|
||||
}
|
||||
|
||||
if (facet == null) {
|
||||
final C configuration = type.createDefaultConfiguration();
|
||||
final Element config = state.getConfiguration();
|
||||
FacetUtil.loadFacetConfiguration(configuration, config);
|
||||
String name = state.getName();
|
||||
facet = createFacet(type, name, configuration, underlyingFacet);
|
||||
if (facet instanceof JDOMExternalizable) {
|
||||
//todo[nik] remove
|
||||
((JDOMExternalizable)facet).readExternal(config);
|
||||
}
|
||||
String externalSystemId = state.getExternalSystemId();
|
||||
if (externalSystemId != null) {
|
||||
facet.setExternalSource(ExternalProjectSystemRegistry.getInstance().getSourceById(externalSystemId));
|
||||
}
|
||||
facet = createFacetFromState(getModule(), type, state, underlyingFacet);
|
||||
model.addFacet(facet);
|
||||
}
|
||||
addFacets(state.getSubFacets(), facet, model);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@NotNull
|
||||
public static Facet<?> createFacetFromStateRaw(@NotNull Module module, @NotNull FacetType<?, ?> type, @NotNull FacetState state,
|
||||
@Nullable Facet<?> underlyingFacet) {
|
||||
//noinspection unchecked
|
||||
return createFacetFromState(module, type, state, underlyingFacet);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <F extends Facet<C>, C extends FacetConfiguration> F createFacetFromState(Module module, FacetType<F, C> type,
|
||||
FacetState state, Facet<?> underlyingFacet) {
|
||||
C configuration = type.createDefaultConfiguration();
|
||||
Element config = state.getConfiguration();
|
||||
FacetUtil.loadFacetConfiguration(configuration, config);
|
||||
String name = state.getName();
|
||||
F facet = createFacet(module, type, name, configuration, underlyingFacet);
|
||||
if (facet instanceof JDOMExternalizable) {
|
||||
//todo[nik] remove
|
||||
((JDOMExternalizable)facet).readExternal(config);
|
||||
}
|
||||
String externalSystemId = state.getExternalSystemId();
|
||||
if (externalSystemId != null) {
|
||||
facet.setExternalSource(ExternalProjectSystemRegistry.getInstance().getSourceById(externalSystemId));
|
||||
}
|
||||
return facet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noStateLoaded() {
|
||||
doLoadState(null);
|
||||
@@ -224,12 +239,8 @@ public final class FacetManagerImpl extends FacetManagerBase implements ModuleCo
|
||||
if (!filter.test(facet)) continue;
|
||||
final Facet<?> underlyingFacet = facet.getUnderlyingFacet();
|
||||
|
||||
FacetState facetState = createFacetState(facet, myModule.getProject());
|
||||
if (!(facet instanceof InvalidFacet)) {
|
||||
final Element config = FacetUtil.saveFacetConfiguration(facet);
|
||||
if (config == null) continue;
|
||||
facetState.setConfiguration(config);
|
||||
}
|
||||
FacetState facetState = saveFacetConfiguration(facet);
|
||||
if (facetState == null) continue;
|
||||
|
||||
getOrCreateTargetFacetList(underlyingFacet, states, myModule.getProject()).add(facetState);
|
||||
states.put(facet, facetState.getSubFacets());
|
||||
@@ -237,6 +248,17 @@ public final class FacetManagerImpl extends FacetManagerBase implements ModuleCo
|
||||
return managerState;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static @Nullable FacetState saveFacetConfiguration(Facet<?> facet) {
|
||||
FacetState facetState = createFacetState(facet, facet.getModule().getProject());
|
||||
if (!(facet instanceof InvalidFacet)) {
|
||||
final Element config = FacetUtil.saveFacetConfiguration(facet);
|
||||
if (config == null) return null;
|
||||
facetState.setConfiguration(config);
|
||||
}
|
||||
return facetState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration of some facet may be stored in one file, but configuration of its underlying facet may be stored in another file. For such
|
||||
* sub-facets we create parent elements which don't store configuration but only name and type.
|
||||
|
||||
@@ -72,6 +72,15 @@ public class FacetModelImpl extends FacetModelBase implements ModifiableFacetMod
|
||||
facetsChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceFacet(@NotNull Facet<?> original, @NotNull Facet<?> replacement) {
|
||||
int index = myFacets.indexOf(original);
|
||||
if (index != -1) {
|
||||
myFacets.set(index, replacement);
|
||||
facetsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rename(final Facet<?> facet, final String newName) {
|
||||
if (!newName.equals(facet.getName())) {
|
||||
|
||||
@@ -2,9 +2,16 @@
|
||||
package com.intellij.facet.impl
|
||||
|
||||
import com.intellij.facet.*
|
||||
import com.intellij.facet.impl.invalid.InvalidFacetManager
|
||||
import com.intellij.facet.impl.invalid.InvalidFacetType
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.ExtensionPointListener
|
||||
import com.intellij.openapi.extensions.PluginDescriptor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import org.jetbrains.jps.model.serialization.facet.FacetState
|
||||
import java.util.*
|
||||
|
||||
class FacetTypeRegistryImpl : FacetTypeRegistry() {
|
||||
@@ -23,13 +30,72 @@ class FacetTypeRegistryImpl : FacetTypeRegistry() {
|
||||
myTypeIds[id] = typeId
|
||||
}
|
||||
|
||||
private fun loadInvalidFacetsOfType(project: Project, facetType: FacetType<*, *>) {
|
||||
val modulesWithFacets = InvalidFacetManager.getInstance(project).invalidFacets
|
||||
.filter { it.configuration.facetState.facetType == facetType.stringId }
|
||||
.mapTo(HashSet()) { it.module }
|
||||
for (module in modulesWithFacets) {
|
||||
val model = FacetManager.getInstance(module).createModifiableModel()
|
||||
val invalidFacets = model.getFacetsByType(InvalidFacetType.TYPE_ID).filter { it.configuration.facetState.facetType == facetType.stringId }
|
||||
for (invalidFacet in invalidFacets) {
|
||||
val newFacet = FacetManagerImpl.createFacetFromStateRaw(module, facetType, invalidFacet.configuration.facetState,
|
||||
invalidFacet.underlyingFacet)
|
||||
model.replaceFacet(invalidFacet, newFacet)
|
||||
for (subFacet in invalidFacet.configuration.facetState.subFacets) {
|
||||
model.addFacet(FacetManagerBase.createInvalidFacet(module, subFacet, newFacet, invalidFacet.configuration.errorMessage, false, false))
|
||||
}
|
||||
}
|
||||
model.commit()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun unregisterFacetType(facetType: FacetType<*, *>) {
|
||||
val id = facetType.id
|
||||
val stringId = facetType.stringId
|
||||
LOG.assertTrue(myFacetTypes.remove(id) != null, "Facet type '$stringId' is not registered")
|
||||
myFacetTypes.remove(id)
|
||||
myTypeIds.remove(stringId)
|
||||
try {
|
||||
ProjectManager.getInstance().openProjects.forEach {
|
||||
convertFacetsToInvalid(it, facetType)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
val id = facetType.id
|
||||
val stringId = facetType.stringId
|
||||
LOG.assertTrue(myFacetTypes.remove(id) != null, "Facet type '$stringId' is not registered")
|
||||
myFacetTypes.remove(id)
|
||||
myTypeIds.remove(stringId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertFacetsToInvalid(project: Project, facetType: FacetType<*, *>) {
|
||||
val modulesWithFacets = ProjectFacetManager.getInstance(project).getFacets(facetType.id).mapTo(HashSet()) { it.module }
|
||||
for (module in modulesWithFacets) {
|
||||
val model = FacetManager.getInstance(module).createModifiableModel()
|
||||
val subFacets = model.allFacets.groupBy { it.underlyingFacet }
|
||||
val facets = model.getFacetsByType(facetType.id)
|
||||
for (facet in facets) {
|
||||
val facetState = saveFacetWithSubFacets(facet, subFacets) ?: continue
|
||||
val pluginName = facetType.pluginDescriptor?.name?.let { " '$it'" } ?: ""
|
||||
val errorMessage = "Plugin$pluginName which provides support for '${facetType.presentableName}' facets is unloaded"
|
||||
val reportError = !ApplicationManager.getApplication().isUnitTestMode
|
||||
val invalidFacet = FacetManagerBase.createInvalidFacet(module, facetState, facet.underlyingFacet, errorMessage, true, reportError)
|
||||
removeAllSubFacets(model, facet, subFacets)
|
||||
model.replaceFacet(facet, invalidFacet)
|
||||
}
|
||||
model.commit()
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeAllSubFacets(model: ModifiableFacetModel, facet: Facet<*>, subFacets: Map<Facet<*>, List<Facet<*>>>) {
|
||||
val toRemove = subFacets[facet] ?: return
|
||||
for (subFacet in toRemove) {
|
||||
removeAllSubFacets(model, subFacet, subFacets)
|
||||
model.removeFacet(subFacet)
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveFacetWithSubFacets(facet: Facet<*>?, subFacets: Map<Facet<FacetConfiguration>, List<Facet<*>>>): FacetState? {
|
||||
val state = FacetManagerImpl.saveFacetConfiguration(facet) ?: return null
|
||||
(subFacets[facet] ?: emptyList()).mapNotNullTo(state.subFacets) { saveFacetWithSubFacets(it, subFacets) }
|
||||
return state
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@@ -72,18 +138,26 @@ class FacetTypeRegistryImpl : FacetTypeRegistry() {
|
||||
if (myExtensionsLoaded) {
|
||||
return
|
||||
}
|
||||
FacetType.EP_NAME.getPoint(null).addExtensionPointListener(
|
||||
FacetType.EP_NAME.forEachExtensionSafe {
|
||||
registerFacetType(it)
|
||||
}
|
||||
myExtensionsLoaded = true
|
||||
FacetType.EP_NAME.addExtensionPointListener(
|
||||
object : ExtensionPointListener<FacetType<*, *>?> {
|
||||
override fun extensionAdded(extension: FacetType<*, *>, pluginDescriptor: PluginDescriptor) {
|
||||
registerFacetType(extension)
|
||||
runWriteAction {
|
||||
ProjectManager.getInstance().openProjects.forEach {
|
||||
loadInvalidFacetsOfType(it, extension)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun extensionRemoved(extension: FacetType<*, *>,
|
||||
pluginDescriptor: PluginDescriptor) {
|
||||
unregisterFacetType(extension)
|
||||
}
|
||||
}, true, null)
|
||||
myExtensionsLoaded = true
|
||||
}, null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -422,7 +422,7 @@
|
||||
<extensionPoint name="projectTemplateParameterFactory" interface="com.intellij.ide.util.projectWizard.ProjectTemplateParameterFactory"/>
|
||||
<extensionPoint name="projectTemplateFileProcessor" interface="com.intellij.ide.util.projectWizard.ProjectTemplateFileProcessor"/>
|
||||
|
||||
<extensionPoint name="facetType" interface="com.intellij.facet.FacetType"/>
|
||||
<extensionPoint name="facetType" interface="com.intellij.facet.FacetType" dynamic="true"/>
|
||||
|
||||
<extensionPoint name="facet.toolWindow" beanClass="com.intellij.facet.ui.FacetDependentToolWindow">
|
||||
<with attribute="factoryClass" implements="com.intellij.openapi.wm.ToolWindowFactory"/>
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ internal open class FacetModelViaWorkspaceModel(protected val legacyBridgeModule
|
||||
name = entity.name
|
||||
setFacetType(entity.facetType)
|
||||
configuration = entity.configurationXmlTag?.let { JDOMUtil.load(it) }
|
||||
}, underlyingFacet, ProjectBundle.message("error.message.unknown.facet.type.0", entity.facetType), true)
|
||||
}, underlyingFacet, ProjectBundle.message("error.message.unknown.facet.type.0", entity.facetType), true, true)
|
||||
}
|
||||
|
||||
val configuration = facetType.createDefaultConfiguration()
|
||||
|
||||
+5
@@ -47,6 +47,11 @@ internal class ModifiableFacetModelViaWorkspaceModel(private val initialStorage:
|
||||
facetsChanged()
|
||||
}
|
||||
|
||||
override fun replaceFacet(original: Facet<*>, replacement: Facet<*>) {
|
||||
removeFacet(original)
|
||||
addFacet(replacement)
|
||||
}
|
||||
|
||||
private fun removeFacetEntityWithSubFacets(entity: FacetEntity) {
|
||||
if (entity !in entityToFacet) return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user