package jetbrains.mps.idea.java.psiStubs;
/*Generated by MPS */
import jetbrains.mps.extapi.persistence.ModelRootBase;
import jetbrains.mps.idea.java.psi.JavaPsiListener;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import com.intellij.openapi.module.Module;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.model.SModelId;
import jetbrains.mps.idea.java.psi.PsiChangesWatcher;
import java.util.Map;
import org.jetbrains.mps.openapi.model.SModelReference;
import java.util.List;
import com.intellij.psi.PsiDirectory;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.util.HashMap;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.psi.PsiManager;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import jetbrains.mps.internal.collections.runtime.IMapping;
import jetbrains.mps.internal.collections.runtime.Sequence;
import com.intellij.psi.PsiJavaFile;
import jetbrains.mps.java.stub.JavaPackageNameStub;
import org.jetbrains.mps.openapi.persistence.Memento;
import com.intellij.psi.PsiFileSystemItem;
public class PsiJavaStubModelRoot extends ModelRootBase implements JavaPsiListener {
private static Logger LOG = Logger.getLogger(PsiJavaStubModelRoot.class);
private static final String TYPE = "JavaPsiStubs";
@NotNull
private Module myIdeaModule;
public PsiJavaStubModelRoot(Module module) {
myIdeaModule = module;
}
/**
* Equals is defined only by our ideaModule, all the state is not taken into acount
* We should be careful when working with ModelRoots in collections (see AbstractModule.doUpdateModelSet)
*/
@Override
public boolean equals(Object root) {
if (!(root instanceof PsiJavaStubModelRoot)) {
return false;
}
return myIdeaModule.equals(((PsiJavaStubModelRoot) root).myIdeaModule);
}
@Override
public int hashCode() {
return myIdeaModule.hashCode();
}
@Override
public String getType() {
return TYPE;
}
@Override
public String getPresentation() {
return "Java PSI stubs";
}
@Override
public SModel getModel(SModelId id) {
// TODO
return null;
}
@Override
public void attach() {
super.attach();
// start to listen
PsiChangesWatcher w = myIdeaModule.getProject().getComponent(PsiChangesWatcher.class);
w.addListener(this);
}
@Override
public void dispose() {
super.dispose();
PsiChangesWatcher w = myIdeaModule.getProject().getComponent(PsiChangesWatcher.class);
w.removeListener(this);
}
@Override
public Iterable<SModel> loadModels() {
Map<SModelReference, List<PsiDirectory>> packageToDirs = MapSequence.fromMap(new HashMap<SModelReference, List<PsiDirectory>>());
final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(myIdeaModule).getSourceRoots(false);
PsiManager psiMgr = PsiManager.getInstance(myIdeaModule.getProject());
for (VirtualFile root : sourceRoots) {
PsiDirectory dir = psiMgr.findDirectory(root);
// judging by RootModelBase.getSourceRoots() only valid source roots will be returned, but we'll be paranoid
if (dir == null) {
continue;
}
collectPackagesInDir(dir, dir, packageToDirs);
}
List<SModel> models = ListSequence.fromList(new ArrayList<SModel>());
for (IMapping<SModelReference, List<PsiDirectory>> pair : MapSequence.fromMap(packageToDirs)) {
SModelReference modelRef = pair.key();
List<PsiDirectory> dirs = pair.value();
ListSequence.fromList(models).addElement(makeModelDescriptor(modelRef, dirs));
}
return models;
}
private void collectPackagesInDir(PsiDirectory sourceRoot, PsiDirectory dir, Map<SModelReference, List<PsiDirectory>> result) {
if (Sequence.fromIterable(Sequence.fromArray(dir.getFiles())).ofType(PsiJavaFile.class).isNotEmpty()) {
SModelReference modelRef = makeModelReference(sourceRoot, dir);
if (modelRef != null) {
List<PsiDirectory> dirs = MapSequence.fromMap(result).get(modelRef);
if (dirs == null) {
dirs = ListSequence.fromList(new ArrayList<PsiDirectory>());
MapSequence.fromMap(result).put(modelRef, dirs);
}
ListSequence.fromList(dirs).addElement(dir);
}
}
for (PsiDirectory subDir : dir.getSubdirectories()) {
collectPackagesInDir(sourceRoot, subDir, result);
}
}
private PsiJavaStubModelDescriptor makeModelDescriptor(SModelReference modelRef, Iterable<PsiDirectory> dirs) {
MultiplePsiJavaStubDataSource ds = new MultiplePsiJavaStubDataSource(myIdeaModule, dirs);
PsiJavaStubModelDescriptor md = new PsiJavaStubModelDescriptor(modelRef, ds);
md.setModelRoot(this);
return md;
}
private SModelReference makeModelReference(PsiDirectory sourceRoot, PsiDirectory dir) {
int skipPrefix = sourceRoot.toString().length();
String relativeDirName = dir.toString().substring(skipPrefix);
String packageName = relativeDirName.replace('/', '.').replace('\\', '.');
if ((packageName == null || packageName.length() == 0)) {
return null;
}
if (packageName.length() > 0 && packageName.charAt(0) == '.') {
packageName = packageName.substring(1);
}
return new JavaPackageNameStub(packageName).asModelReference(getModule().getModuleReference());
}
public boolean isReadOnly() {
return true;
}
@Override
public boolean canCreateModel(String modelName) {
return false;
}
@Override
public SModel createModel(String modelName) {
return null;
}
@Override
public void save(Memento memento) {
throw new UnsupportedOperationException("JavaPsiStubs: unsupported for now");
}
@Override
public void load(Memento memento) {
throw new UnsupportedOperationException("JavaPsiStubs: unsupported for now");
}
@Override
public void psiChanged(JavaPsiListener.PsiEvent event) {
// TODO re-write to sequences and any
// here we simply decide if we have to update
for (PsiFileSystemItem fsItem : event.getCreated()) {
if (importantFsItem(fsItem)) {
update();
return;
}
}
for (PsiFileSystemItem fsItem : event.getRemoved()) {
if (importantFsItem(fsItem)) {
update();
return;
}
}
for (JavaPsiListener.FSRename rename : event.getRenamed()) {
if (importantFsItem(rename.item)) {
update();
return;
}
}
for (JavaPsiListener.FSMove move : event.getMoved()) {
if (importantFsItem(move.item)) {
update();
return;
}
}
}
private boolean importantFsItem(PsiFileSystemItem fsItem) {
return (fsItem instanceof PsiDirectory || fsItem instanceof PsiJavaFile) && findOurSourceRoot(fsItem) != null;
}
private PsiDirectory findOurSourceRoot(PsiFileSystemItem item) {
for (VirtualFile sourceRoot : ModuleRootManager.getInstance(myIdeaModule).getSourceRoots()) {
String rootPath = sourceRoot.toString();
String itemPath = item.getVirtualFile().toString();
if (itemPath.startsWith(rootPath)) {
return PsiManager.getInstance(myIdeaModule.getProject()).findDirectory(sourceRoot);
}
}
return null;
}
}