/*
* 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);
}
}
}