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() { } }