package jetbrains.mps.watching;
/*Generated by MPS */
import com.intellij.openapi.components.ApplicationComponent;
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import com.intellij.ide.FrameStateManager;
import com.intellij.ide.FrameStateListener;
import java.util.Set;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import java.util.HashSet;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import jetbrains.mps.project.MPSProject;
import jetbrains.mps.ide.project.ProjectHelper;
import org.jetbrains.mps.openapi.model.SModel;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.fileEditor.FileEditorManager;
import jetbrains.mps.nodefs.MPSNodeVirtualFile;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.ide.editor.MPSEditorUtil;
import jetbrains.mps.internal.collections.runtime.CollectionSequence;
import jetbrains.mps.workbench.FileSystemModelHelper;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.vfs.newvfs.RefreshSession;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import jetbrains.mps.ide.vfs.IdeaFile;
import org.apache.log4j.Level;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class ModelFocusSynchronizer implements ApplicationComponent {
private static final Logger LOG = LogManager.getLogger(ModelFocusSynchronizer.class);
public ModelFocusSynchronizer(FrameStateManager frameStateManager) {
frameStateManager.addListener(new FrameStateListener() {
@Override
public void onFrameDeactivated() {
}
@Override
public void onFrameActivated() {
final Set<IFile> files = SetSequence.fromSet(new HashSet<IFile>());
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
// XXX could use MPS's ProjectManager, but it's complicated to get IDEA project out of regular mps's Project.
MPSProject mpsProject = ProjectHelper.fromIdeaProject(project);
if (mpsProject == null) {
continue;
}
mpsProject.getModelAccess().runReadInEDT(new Runnable() {
public void run() {
if (project.isDisposed()) {
return;
}
Set<SModel> models = SetSequence.fromSet(new HashSet<SModel>());
for (VirtualFile vf : FileEditorManager.getInstance(project).getSelectedFiles()) {
if (vf instanceof MPSNodeVirtualFile) {
// XXX as long as we update VFS files, why do we care to find actual edited node? Why vf.getNode() is not sufficient?
MPSNodeVirtualFile nvf = ((MPSNodeVirtualFile) vf);
SNode node = MPSEditorUtil.getCurrentEditedNode(project, nvf);
if (node == null) {
node = nvf.getNode();
}
if (node != null) {
SModel model = node.getModel();
if (model != null) {
SetSequence.fromSet(models).addElement(model);
}
}
}
}
for (SModel model : SetSequence.fromSet(models)) {
SetSequence.fromSet(files).addSequence(CollectionSequence.fromCollection(new FileSystemModelHelper(model).getFiles()));
}
}
});
}
// the sole reason for invokeLater here is to run after all runReadInEDT. IOW, we implicitly
// synchronize file collection task with refresh task by using EDT thread. Just don't want to bother with
// explicit sync (e.g. semaphore incremented before runReadInEDT, decremented in the end and RefreshQueue waiting for
// semaphore == 0.
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (!(SetSequence.fromSet(files).isEmpty())) {
RefreshSession session = RefreshQueue.getInstance().createSession(true, true, null);
for (IFile file : SetSequence.fromSet(files)) {
IFile fileToRefresh = file;
while (!(fileToRefresh.exists())) {
fileToRefresh = fileToRefresh.getParent();
}
if (!(fileToRefresh instanceof IdeaFile)) {
if (LOG.isEnabledFor(Level.WARN)) {
LOG.warn("File " + fileToRefresh + " must be a project file and managed by IDEA FS");
}
continue;
}
VirtualFile virtualFile = ((IdeaFile) fileToRefresh).getVirtualFile();
if (virtualFile != null) {
session.addFile(virtualFile);
}
}
session.launch();
}
}
});
}
});
}
@NonNls
@NotNull
@Override
public String getComponentName() {
return getClass().getName();
}
@Override
public void initComponent() {
}
@Override
public void disposeComponent() {
}
}