/*
* 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 org.jetbrains.mps.openapi.model;
import org.jetbrains.mps.openapi.model.SModel.Problem;
import org.jetbrains.mps.openapi.module.SRepository;
/**
* This interface can be implemented to track model state.
*
* Generally, we try to send most specific event only, e.g.
* if a model content is replaced, we likely to send only {@link #modelReplaced(SModel)}, not a sequence of
* {@link #modelUnloaded(SModel)}, {@link #modelLoaded(SModel, boolean)}, {@link #modelReplaced(SModel)}.
* However, at the moment we do not ensure this, and chances are you get different sequence for different models.
* FIXME we lack tests that state aforementioned contract for notifications.
*
* FIXME may be useful to provide modelChanged() notification to avoid attaching node change listeners just to figure out if model has been changed.
* Event makes sense for EditableSModel only, perhaps, could be a separate listener, then?
*/
public interface SModelListener {
void modelLoaded(SModel model, boolean partially);
void modelReplaced(SModel model);
void modelUnloaded(SModel model);
void modelSaved(SModel model);
/**
* Fired when a model becomes visible in a repository.
* <p/>
* IMPORTANT: it's unspecified whether the model is part of a module the moment this event is fired or not.
* Do not expect {@link SModel#getModule()} to give meaningful value. This contract may change (i.e. become stricter) in future.
* <p/>
* NOTE: This is not an event most clients could make use of, as it's technically tricky to attach a listener to a model not yet
* visible inside a repository, and thus it's more of internal mechanism (i.e. code that instantiates a model may attach a listener
* to not yet published model and thus get notified). Besides, detached models do not get their listeners automatically discarded,
* and the listeners get a chance to react to model detach/re-attach sequence with this event.
*
* @param model affected model, never <code>null</code>
* @param repository repository the model become available at, never <code>null</code>
*/
void modelAttached(SModel model, SRepository repository);
/**
* Fired when a model is no longer part of a repository, e.g. due to removal from module.
* This event is intended to clean-up listener caches associated with the model and to gracefully unregister other listeners.
* <p/>
* IMPORTANT: it's unspecified whether the model is part of a module the moment this event is fired or not.
* Do not expect {@link SModel#getModule()} to give meaningful value. This contract may change (i.e. become stricter) in future.
* <p/>
* Primary drive force for this event is desire to add model listener only, without a need to listen to
* {@linkplain org.jetbrains.mps.openapi.module.SModuleListener module events} to find out when the model is no longer available.
* <p/>
* Note, {@linkplain SModelListener listeners} not unregistered from the model would get notified with {@link #modelAttached(SModel, SRepository)}
* in case detached model is brought back (perhaps, in completely different module and repository).
*
* @param model affected model, never <code>null</code>
* @param repository repository the model become available at, never <code>null</code>
*/
void modelDetached(SModel model, SRepository repository);
/**
* This event is fired when the storage-memory conflict is detected (== isChanged() && needsReloading()).
* An IDE can listen to it and give user a way to resolve the conflict by invoking either updateTimestamp(), or reloadFromSource().
*/
void conflictDetected(SModel model);
/**
* This method is called each time a new problem, or a set of problems is discovered.
*/
void problemsDetected(SModel model, Iterable<Problem> problems);
}