IDEA-225629: Make projectViewPane EP dynamic

GitOrigin-RevId: 4b0df024df5a8e6ee1b1f90a04bca39f52d16c80
This commit is contained in:
Sergey Malenkov
2020-04-22 22:53:20 +00:00
committed by intellij-monorepo-bot
parent 356b6e1fe6
commit 4aeb1e99de
4 changed files with 64 additions and 28 deletions
@@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.ProjectExtensionPointName;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
@@ -70,6 +71,14 @@ import java.util.function.Predicate;
public abstract class AbstractProjectViewPane implements DataProvider, Disposable, BusyObject {
private static final Logger LOG = Logger.getInstance(AbstractProjectViewPane.class);
public static final ProjectExtensionPointName<AbstractProjectViewPane> EP
= new ProjectExtensionPointName<>("com.intellij.projectViewPane");
/**
* @deprecated use {@link #EP} instead
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2022.2")
public static final ExtensionPointName<AbstractProjectViewPane> EP_NAME = ExtensionPointName.create("com.intellij.projectViewPane");
protected final @NotNull Project myProject;
@@ -553,6 +553,8 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo
toolWindowVisible = window.isVisible();
}
});
AbstractProjectViewPane.EP.addExtensionPointListener(project, this::reloadPanes, project);
}
private void constructUi() {
@@ -855,30 +857,51 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo
viewSelectionChanged();
}
private void ensurePanesLoaded() {
// avoid recursive loading
if (myExtensionsLoaded.getAndSet(true)) {
return;
}
private synchronized void reloadPanes() {
if (myProject.isDisposed() || !myExtensionsLoaded.get()) return; // panes will be loaded later
AbstractProjectViewPane[] extensions = AbstractProjectViewPane.EP_NAME.getExtensions(myProject);
Arrays.sort(extensions, PANE_WEIGHT_COMPARATOR);
for (AbstractProjectViewPane pane : extensions) {
if (myUninitializedPaneState.containsKey(pane.getId())) {
try {
pane.readExternal(myUninitializedPaneState.get(pane.getId()));
}
catch (InvalidDataException e) {
// ignore
}
myUninitializedPaneState.remove(pane.getId());
Map<String, AbstractProjectViewPane> newPanes = loadPanes();
Map<AbstractProjectViewPane, Boolean> oldPanes = new IdentityHashMap<>();
myUninitializedPanes.forEach(pane -> oldPanes.put(pane, pane == newPanes.get(pane.getId())));
myId2Pane.forEach((id, pane) -> oldPanes.put(pane, pane == newPanes.get(id)));
oldPanes.forEach((pane, exists) -> {
if (Boolean.FALSE.equals(exists)) {
removeProjectPane(pane);
Disposer.dispose(pane);
}
if (pane.isInitiallyVisible() && !myId2Pane.containsKey(pane.getId())) {
});
for (AbstractProjectViewPane pane : newPanes.values()) {
if (!Boolean.TRUE.equals(oldPanes.get(pane)) && pane.isInitiallyVisible()) {
addProjectPane(pane);
}
}
}
private void ensurePanesLoaded() {
if (myProject.isDisposed() || myExtensionsLoaded.getAndSet(true)) return; // avoid recursive loading
for (AbstractProjectViewPane pane : loadPanes().values()) {
if (pane.isInitiallyVisible()) {
addProjectPane(pane);
}
}
}
private Map<String, AbstractProjectViewPane> loadPanes() {
HashMap<String, AbstractProjectViewPane> map = new LinkedHashMap<>();
AbstractProjectViewPane.EP.getExtensions(myProject).stream().sorted(PANE_WEIGHT_COMPARATOR).forEach(pane -> {
AbstractProjectViewPane added = map.computeIfAbsent(pane.getId(), id -> pane);
if (pane != added) {
LOG.warn("ignore duplicated pane with id=" + pane.getId() + "\nold " + added.getClass() + "\nnew " + pane.getClass());
}
else {
Element element = myUninitializedPaneState.remove(pane.getId());
if (element != null) applyPaneState(pane, element);
}
});
return map;
}
private void viewSelectionChanged() {
Content content = getContentManager().getSelectedContent();
if (content == null) {
@@ -1561,7 +1584,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo
return "AndroidView";
}
else {
for (AbstractProjectViewPane extension : AbstractProjectViewPane.EP_NAME.getExtensions(myProject)) {
for (AbstractProjectViewPane extension : AbstractProjectViewPane.EP.getExtensions(myProject)) {
if (extension.isDefaultPane(myProject)) {
return extension.getId();
}
@@ -1580,11 +1603,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo
AbstractProjectViewPane pane = myId2Pane.get(paneId);
if (pane != null) {
try {
pane.readExternal(paneElement);
}
catch (InvalidDataException ignore) {
}
applyPaneState(pane, paneElement);
}
else {
myUninitializedPaneState.put(paneId, paneElement);
@@ -1592,6 +1611,14 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo
}
}
private static void applyPaneState(@NotNull AbstractProjectViewPane pane, @NotNull Element element) {
try {
pane.readExternal(element);
}
catch (InvalidDataException ignored) {
}
}
@Override
public Element getState() {
Element parentNode = new Element("projectView");
@@ -493,7 +493,7 @@
<extensionPoint name="sdkDownload" interface="com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownload" dynamic="true"/>
<extensionPoint name="projectViewPane" interface="com.intellij.ide.projectView.impl.AbstractProjectViewPane" area="IDEA_PROJECT"/>
<extensionPoint name="projectViewPane" interface="com.intellij.ide.projectView.impl.AbstractProjectViewPane" area="IDEA_PROJECT" dynamic="true"/>
<extensionPoint name="projectViewPaneSelectionHelper" interface="com.intellij.ide.projectView.impl.ProjectViewPaneSelectionHelper" dynamic="true"/>
<extensionPoint name="projectViewNodeDecorator" interface="com.intellij.ide.projectView.ProjectViewNodeDecorator" area="IDEA_PROJECT" dynamic="true"/>
@@ -1,4 +1,4 @@
// 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.
// 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.tasks.context;
@@ -30,7 +30,7 @@ final class ProjectViewContextProvider extends WorkingContextProvider {
@Override
public void saveContext(@NotNull Project project, @NotNull Element toElement) throws WriteExternalException {
for (AbstractProjectViewPane pane : AbstractProjectViewPane.EP_NAME.getExtensionList(project)) {
for (AbstractProjectViewPane pane : AbstractProjectViewPane.EP.getExtensions(project)) {
Element paneElement = new Element(pane.getId());
pane.writeExternal(paneElement);
toElement.addContent(paneElement);
@@ -39,7 +39,7 @@ final class ProjectViewContextProvider extends WorkingContextProvider {
@Override
public void loadContext(@NotNull Project project, @NotNull Element fromElement) throws InvalidDataException {
for (AbstractProjectViewPane pane : AbstractProjectViewPane.EP_NAME.getExtensionList(project)) {
for (AbstractProjectViewPane pane : AbstractProjectViewPane.EP.getExtensions(project)) {
Element paneElement = fromElement.getChild(pane.getId());
if (paneElement != null) {
pane.readExternal(paneElement);
@@ -52,7 +52,7 @@ final class ProjectViewContextProvider extends WorkingContextProvider {
@Override
public void clearContext(@NotNull Project project) {
for (AbstractProjectViewPane pane : AbstractProjectViewPane.EP_NAME.getExtensionList(project)) {
for (AbstractProjectViewPane pane : AbstractProjectViewPane.EP.getExtensions(project)) {
JTree tree = pane.getTree();
if (tree != null) {
TreeUtil.collapseAll(tree, 0);