/* * 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.smodel.references; import jetbrains.mps.smodel.SReferenceBase; import org.jetbrains.annotations.NotNull; import org.jetbrains.mps.openapi.event.SNodeAddEvent; import org.jetbrains.mps.openapi.event.SNodeRemoveEvent; import org.jetbrains.mps.openapi.event.SReferenceChangeEvent; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.model.SModelListenerBase; import org.jetbrains.mps.openapi.model.SNode; import org.jetbrains.mps.openapi.model.SNodeChangeListenerAdapter; import org.jetbrains.mps.openapi.model.SNodeUtil; import java.util.HashSet; import java.util.Set; public class ImmatureReferencesTracker { private SModel myModel = null; private SNodeChangeListenerAdapter myNodeListener = new MySNodeChangeListenerAdapter(); private Set<SReferenceBase> myImmatureRefs = new HashSet<SReferenceBase>(); private SModelListenerBase myModelListener = new MySModelListenerBase(); public void attach(SModel model, boolean doCheckImmediately) { assert myModel == null; myModel = model; myModel.addChangeListener(myNodeListener); myModel.addModelListener(myModelListener); if (doCheckImmediately){ addRefsFromModel(model); } } public void detach() { myModel.removeModelListener(myModelListener); myModel.removeChangeListener(myNodeListener); myModel = null; } public void makeMature() { for (SReferenceBase r : myImmatureRefs) { if (!r.isDirect()) { continue; } r.makeIndirect(); } myImmatureRefs.clear(); } private void checkAndAddNewRef(org.jetbrains.mps.openapi.model.SReference newRef) { if (!(newRef instanceof SReferenceBase)) { return; } SReferenceBase newRefBase = (SReferenceBase) newRef; if (!newRefBase.isDirect()) { return; } myImmatureRefs.add(newRefBase); } private void addRefsFromModel(SModel model) { for (SNode n: SNodeUtil.getDescendants(model)){ for (org.jetbrains.mps.openapi.model.SReference r : n.getReferences()) { checkAndAddNewRef(r); } } } private class MySModelListenerBase extends SModelListenerBase { @Override public void modelReplaced(SModel model) { addRefsFromModel(model); } } private class MySNodeChangeListenerAdapter extends SNodeChangeListenerAdapter { @Override public void referenceChanged(@NotNull SReferenceChangeEvent event) { org.jetbrains.mps.openapi.model.SReference newRef = event.getNewValue(); checkAndAddNewRef(newRef); } @Override public void nodeAdded(@NotNull SNodeAddEvent event) { for (SNode n: SNodeUtil.getDescendants(event.getChild())){ for (org.jetbrains.mps.openapi.model.SReference r : n.getReferences()) { checkAndAddNewRef(r); } } } @Override public void nodeRemoved(@NotNull SNodeRemoveEvent event) { for (SNode n: SNodeUtil.getDescendants(event.getChild())){ for (org.jetbrains.mps.openapi.model.SReference r : n.getReferences()) { if (!(r instanceof SReferenceBase)) { continue; } myImmatureRefs.remove((SReferenceBase) r); } } } } }