package typesystemIntegration.languageChecker; /*Generated by MPS */ import org.jetbrains.mps.openapi.module.SRepository; import jetbrains.mps.smodel.RepoListenerRegistrar; import java.util.Map; import jetbrains.mps.nodeEditor.EditorComponent; import jetbrains.mps.checkers.LanguageErrorsComponent; import jetbrains.mps.internal.collections.runtime.MapSequence; import java.util.HashMap; import org.jetbrains.mps.openapi.model.SModel; import java.util.Set; import org.jetbrains.annotations.NotNull; import jetbrains.mps.internal.collections.runtime.SetSequence; import jetbrains.mps.smodel.event.SModelListener; import jetbrains.mps.smodel.SModelAdapter; import org.jetbrains.mps.openapi.module.SRepositoryContentAdapter; import org.jetbrains.mps.openapi.module.SModule; import jetbrains.mps.smodel.SModelInternal; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.internal.collections.runtime.IVisitor; import org.jetbrains.annotations.Nullable; import jetbrains.mps.baseLanguage.closures.runtime.Wrappers; import jetbrains.mps.nodeEditor.inspector.InspectorEditorComponent; import java.util.List; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.HashSet; import com.intellij.openapi.application.ApplicationManager; /*package*/ class ErrorComponents { private final SRepository myRepository; /*package*/ ErrorComponents(SRepository repository) { myRepository = repository; new RepoListenerRegistrar(myRepository, myRepositoryListener).attach(); } /** * The two maps below are accessed from EDT (by {@link typesystemIntegration.languageChecker.ErrorComponents#myDisposeListener }) and from the background highlighter * thread. Access to the maps must be therefore guarded by this lock. */ private final Object myMapsLock = new Object(); private Map<EditorComponent, LanguageErrorsComponent> myEditorComponentToErrorMap = MapSequence.fromMap(new HashMap<EditorComponent, LanguageErrorsComponent>()); private Map<SModel, Set<EditorComponent>> myModelToEditorComponentsMap = MapSequence.fromMap(new HashMap<SModel, Set<EditorComponent>>()); private EditorComponent.EditorDisposeListener myDisposeListener = new EditorComponent.EditorDisposeListener() { @Override public void editorWillBeDisposed(@NotNull EditorComponent editorComponent) { synchronized (myMapsLock) { removeByEditorComponent(editorComponent); for (SModel model : MapSequence.fromMap(myModelToEditorComponentsMap).keySet()) { Set<EditorComponent> editorComponents = MapSequence.fromMap(myModelToEditorComponentsMap).get(model); if (SetSequence.fromSet(editorComponents).removeElement(editorComponent) != null) { if (SetSequence.fromSet(editorComponents).isEmpty()) { MapSequence.fromMap(myModelToEditorComponentsMap).removeKey(model); removeModelListener(model); } break; } } } } }; private SModelListener myModelListener = new SModelAdapter() { @Override public void beforeModelDisposed(SModel model) { synchronized (myMapsLock) { removeByModel(model); } } }; private final SRepositoryContentAdapter myRepositoryListener = new SRepositoryContentAdapter() { @Override protected boolean isIncluded(SModule module) { return !(module.isReadOnly()); } @Override protected void stopListening(SModel model) { synchronized (myMapsLock) { removeByModel(model); } removeModelListener(model); } }; private void removeByModel(SModel model) { Set<EditorComponent> editorComponents = MapSequence.fromMap(myModelToEditorComponentsMap).removeKey(model); if (editorComponents != null) { for (EditorComponent editorComponent : editorComponents) { removeByEditorComponent(editorComponent); } } } private void removeByEditorComponent(@NotNull EditorComponent editorComponent) { LanguageErrorsComponent component = MapSequence.fromMap(myEditorComponentToErrorMap).removeKey(editorComponent); if (component != null) { component.dispose(); } editorComponent.removeDisposeListener(myDisposeListener); } private void removeModelListener(SModel model) { ((SModelInternal) model).removeModelListener(myModelListener); } private void addModelListener(SModel modelDescriptor) { ((SModelInternal) modelDescriptor).addModelListener(myModelListener); } /*package*/ void dispose() { synchronized (myMapsLock) { new RepoListenerRegistrar(myRepository, myRepositoryListener).detach(); Sequence.fromIterable(MapSequence.fromMap(myEditorComponentToErrorMap).values()).visitAll(new IVisitor<LanguageErrorsComponent>() { public void visit(LanguageErrorsComponent it) { it.dispose(); } }); SetSequence.fromSet(MapSequence.fromMap(myEditorComponentToErrorMap).keySet()).visitAll(new IVisitor<EditorComponent>() { public void visit(EditorComponent it) { it.removeDisposeListener(myDisposeListener); } }); myEditorComponentToErrorMap = null; SetSequence.fromSet(MapSequence.fromMap(myModelToEditorComponentsMap).keySet()).visitAll(new IVisitor<SModel>() { public void visit(SModel it) { removeModelListener(it); } }); myModelToEditorComponentsMap = null; } } /** * * @return null if {@code editorComponent} is null, a non-null value otherwise */ @Nullable /*package*/ LanguageErrorsComponent getErrorsComponent(EditorComponent editorComponent) { synchronized (myMapsLock) { LanguageErrorsComponent errorsComponent; final Wrappers._T<EditorComponent> mainEditorComponent = new Wrappers._T<EditorComponent>(null); if (editorComponent instanceof InspectorEditorComponent) { List<SNode> editedNodeAncestors = SNodeOperations.getNodeAncestors(((SNode) editorComponent.getEditedNode()), null, true); for (EditorComponent candidate : MapSequence.fromMap(myEditorComponentToErrorMap).keySet()) { if (ListSequence.fromList(editedNodeAncestors).contains(candidate.getEditedNode())) { mainEditorComponent.value = candidate; break; } } if (mainEditorComponent.value == null) { return null; } } else { mainEditorComponent.value = editorComponent; } SModel model = editorComponent.getEditorContext().getModel(); errorsComponent = MapSequence.fromMap(myEditorComponentToErrorMap).get(mainEditorComponent.value); if (errorsComponent == null) { errorsComponent = new LanguageErrorsComponent(model); MapSequence.fromMap(myEditorComponentToErrorMap).put(mainEditorComponent.value, errorsComponent); Set<EditorComponent> mappedEditorComponent = MapSequence.fromMap(myModelToEditorComponentsMap).get(model); if (mappedEditorComponent == null) { mappedEditorComponent = SetSequence.fromSet(new HashSet<EditorComponent>()); MapSequence.fromMap(myModelToEditorComponentsMap).put(model, mappedEditorComponent); addModelListener(model); } SetSequence.fromSet(mappedEditorComponent).addElement(mainEditorComponent.value); ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { mainEditorComponent.value.addDisposeListener(myDisposeListener); if (mainEditorComponent.value.isDisposed()) { myDisposeListener.editorWillBeDisposed(mainEditorComponent.value); } } }); } return errorsComponent; } } /*package*/ void clear(EditorComponent editorComponent) { synchronized (myMapsLock) { MapSequence.fromMap(myEditorComponentToErrorMap).get(editorComponent).clear(); } } }