/* * Copyright 2003-2012 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.idea.core.ui; import com.intellij.facet.FacetManager; import com.intellij.ide.projectView.impl.ProjectAbstractTreeStructureBase; import com.intellij.ide.projectView.impl.ProjectTreeStructure; import com.intellij.ide.projectView.impl.ProjectViewPane; import com.intellij.ide.projectView.impl.nodes.ProjectViewModuleNode; import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.projectView.impl.nodes.PsiFileNode; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import jetbrains.mps.fileTypes.MPSFileTypeFactory; import jetbrains.mps.ide.platform.refactoring.ModelElementTargetChooser; import jetbrains.mps.ide.platform.refactoring.NodeLocation; import jetbrains.mps.ide.platform.refactoring.NodeLocation.NodeLocationChild; import jetbrains.mps.ide.platform.refactoring.NodeLocation.NodeLocationRoot; import jetbrains.mps.ide.project.ProjectHelper; import jetbrains.mps.idea.core.MPSDataKeys; import jetbrains.mps.idea.core.facet.MPSConfigurationBean; import jetbrains.mps.idea.core.facet.MPSFacet; import jetbrains.mps.idea.core.facet.MPSFacetType; import jetbrains.mps.idea.core.projectView.MPSPsiElementTreeNode; import jetbrains.mps.idea.core.projectView.MPSPsiModelTreeNode; import jetbrains.mps.persistence.DefaultModelRoot; import jetbrains.mps.smodel.SModelFileTracker; import jetbrains.mps.vfs.IFile; import org.jetbrains.mps.openapi.module.SRepository; import org.jetbrains.mps.openapi.persistence.ModelRoot; import javax.swing.JComponent; import java.util.ArrayList; import java.util.Set; public class ModelOrNodeChooser extends ProjectViewPane implements ModelElementTargetChooser { private Project myProject; private JComponent myComponent; public ModelOrNodeChooser(Project project) { super(project); myProject = project; myComponent = createComponent(); } @Override public JComponent getComponent() { return myComponent; } protected ProjectAbstractTreeStructureBase createStructure() { return new ProjectTreeStructure(myProject, ID) { public Object[] getChildElements(Object element) { ArrayList<Object> result = new ArrayList<Object>(); for (Object o : super.getChildElements(element)) { if (o instanceof PsiFileNode) { PsiFileNode fileNode = (PsiFileNode) o; VirtualFile vFile = fileNode.getVirtualFile(); if (vFile != null && vFile.getFileType().equals(MPSFileTypeFactory.MPS_FILE_TYPE)) { result.add(o); } } else if (o instanceof MPSPsiElementTreeNode || o instanceof MPSPsiModelTreeNode) { result.add(o); } else if (o instanceof PsiDirectoryNode) { VirtualFile virtualFile = ((PsiDirectoryNode) o).getVirtualFile(); if (virtualFile != null && isModelRootOrParent(virtualFile)) { result.add(o); } } else if (o instanceof ProjectViewModuleNode && hasModelRoots(((ProjectViewModuleNode) o).getValue())) { result.add(o); } } return result.toArray(); } }; } private boolean hasModelRoots(Module module) { if (module == null) return false; MPSFacet mpsFacet = FacetManager.getInstance(module).getFacetByType(MPSFacetType.ID); if (mpsFacet == null || !mpsFacet.wasInitialized()) return false; MPSConfigurationBean configurationBean = mpsFacet.getConfiguration().getBean(); return configurationBean != null && !(configurationBean.getModelRoots().isEmpty()); } private boolean isModelRootOrParent(VirtualFile virtualFile) { if (!(virtualFile.isDirectory())) return false; Module module = ModuleUtil.findModuleForFile(virtualFile, myProject); if (module == null) return false; MPSFacet mpsFacet = FacetManager.getInstance(module).getFacetByType(MPSFacetType.ID); if (mpsFacet == null || !(mpsFacet.wasInitialized())) return false; MPSConfigurationBean configurationBean = mpsFacet.getConfiguration().getBean(); if (configurationBean == null) return false; String url = virtualFile.getUrl(); if (!LocalFileSystem.PROTOCOL.equals(VirtualFileManager.extractProtocol(url))) return false; String path = VirtualFileManager.extractPath(url); for (ModelRoot mr : configurationBean.getModelRoots()) { if (!(mr instanceof DefaultModelRoot)) continue; for (String sourceRoot : ((DefaultModelRoot) mr).getFiles(DefaultModelRoot.SOURCE_ROOTS)) { if (sourceRoot.startsWith(path)) return true; // TODO this gives some unneeded items (like src_gen when src is source root) if (path.startsWith(sourceRoot)) return true; } } return false; } @Override public NodeLocation getSelectedObject() { SRepository repository = ProjectHelper.getProjectRepository(myProject); if ((getSelectedNode() != null) && (getSelectedNode().getUserObject() instanceof MPSPsiElementTreeNode)) { return new NodeLocationChild(((MPSPsiElementTreeNode) (getSelectedNode().getUserObject())).getValue().getSNodeReference().resolve(repository)); } else { Set<IFile> models = MPSDataKeys.MODEL_FILES.getData(this); if (models != null && models.size() == 1) { return new NodeLocationRoot(SModelFileTracker.getInstance(repository).findModel(models.iterator().next())); } // we could handle the case when we haven't got a model // perhaps, in plugin every directory (under module with MPS facet) should be transparently made into model // we could create the model right here (we're in EDT here) // This way we would allow move nodes into a package where no mps roots are present yet } return null; } }