/* * Copyright 2003-2016 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 jetbrains.mps.ide.editor; import com.intellij.openapi.components.ProjectComponent; import com.intellij.util.containers.MultiMap; import jetbrains.mps.ide.ThreadUtils; import jetbrains.mps.nodeEditor.EditorComponent.EditorDisposeListener; import jetbrains.mps.openapi.editor.EditorComponent; import jetbrains.mps.openapi.editor.extensions.EditorExtension; import jetbrains.mps.openapi.editor.extensions.EditorExtensionRegistry; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Map.Entry; import java.util.Set; public class EditorExtensionRegistryImpl implements EditorExtensionRegistry, ProjectComponent { private final Set<EditorExtension> myExtensions = new HashSet<EditorExtension>(); private final MultiMap<EditorComponent, EditorExtension> myEditorExtensions = MultiMap.create(); private final EditorDisposeListener myUnextendOnEditorDisposeListener = new UnextendOnEditorDisposeListener(); @Override public void projectOpened() { } @Override public void projectClosed() { } @Override public void initComponent() { } @Override public void disposeComponent() { assert myExtensions.isEmpty(); assert myEditorExtensions.isEmpty(); } @NotNull @Override public String getComponentName() { return EditorExtensionRegistry.class.getSimpleName(); } @Override public void registerExtension(@NotNull EditorExtension extension) { ThreadUtils.assertEDT(); if (!myExtensions.add(extension)) { throw new IllegalArgumentException("Extension already registered: " + extension); } for (Entry<EditorComponent, Collection<EditorExtension>> entry : myEditorExtensions.entrySet()) { EditorComponent editorComponent = entry.getKey(); if (!entry.getValue().add(extension)) { throw new IllegalArgumentException("Extension already installed on editor component: " + extension + ", " + editorComponent); } extension.install(editorComponent); } } @Override public void unregisterExtension(@NotNull EditorExtension extension) { ThreadUtils.assertEDT(); if (!myExtensions.remove(extension)) { return; } for (Entry<EditorComponent, Collection<EditorExtension>> entry : myEditorExtensions.entrySet()) { if (entry.getValue().remove(extension)) { extension.uninstall(entry.getKey()); } } } @Override public void extend(@NotNull EditorComponent editorComponent) { ThreadUtils.assertEDT(); if (myEditorExtensions.containsKey(editorComponent)) { throw new IllegalArgumentException("Editor already extended: " + editorComponent); } Collection<EditorExtension> applicableExtensions = getApplicableExtensions(editorComponent); myEditorExtensions.put(editorComponent, applicableExtensions); installExtensions(editorComponent, applicableExtensions); ((jetbrains.mps.nodeEditor.EditorComponent) editorComponent).addDisposeListener(myUnextendOnEditorDisposeListener); } private Collection<EditorExtension> getApplicableExtensions(EditorComponent editorComponent) { Collection<EditorExtension> applicableExtensions = new ArrayList<EditorExtension>(myExtensions.size()); for (EditorExtension extension : myExtensions) { if (extension.isApplicable(editorComponent)) { applicableExtensions.add(extension); } } return applicableExtensions; } private void installExtensions(EditorComponent editorComponent, Iterable<EditorExtension> applicableExtensions) { for (EditorExtension extension : applicableExtensions) { extension.install(editorComponent); } } private void uninstallExtensions(EditorComponent editorComponent, Iterable<EditorExtension> extensions) { for (EditorExtension extension : extensions) { extension.uninstall(editorComponent); } } private class UnextendOnEditorDisposeListener implements EditorDisposeListener { @Override public void editorWillBeDisposed(@NotNull jetbrains.mps.nodeEditor.EditorComponent component) { ThreadUtils.assertEDT(); Collection<EditorExtension> extensions = myEditorExtensions.remove(component); if (extensions == null) { return; } uninstallExtensions(component, extensions); } } }