package jetbrains.mps.idea.java.psiStubs;
/*Generated by MPS */
import jetbrains.mps.extapi.persistence.DataSourceBase;
import jetbrains.mps.idea.java.psi.JavaPsiListener;
import com.intellij.openapi.module.Module;
import com.intellij.psi.PsiDirectory;
import java.util.List;
import org.jetbrains.mps.openapi.persistence.DataSourceListener;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import java.util.Iterator;
import jetbrains.mps.idea.java.psi.PsiChangesWatcher;
import com.intellij.psi.PsiJavaFile;
import jetbrains.mps.internal.collections.runtime.Sequence;
import java.util.Collections;
import java.util.Set;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import java.util.HashSet;
import com.intellij.psi.PsiFileSystemItem;
public class PsiJavaStubDataSource extends DataSourceBase implements JavaFilesHolder, JavaPsiListener {
private final Object LOCK = new Object();
private Module myModule;
private PsiDirectory myDirectory;
private List<DataSourceListener> myListeners = ListSequence.fromList(new ArrayList<DataSourceListener>());
public PsiJavaStubDataSource(Module module, PsiDirectory dir) {
myModule = module;
myDirectory = dir;
}
public void psiChanged(final JavaPsiListener.PsiEvent event) {
// this is a guard against the situation when our directory has been removed
// we don't notify our listeners about anything in this case
// they should be removed anyways
if (!(isValid())) {
return;
}
// we've been told something has changed in PSI
// let's see what matters to us
PsiJavaStubEvent ourEvent = new PsiJavaStubDataSource.OurEvent(event);
synchronized (LOCK) {
{
Iterator<DataSourceListener> listener_it = ListSequence.fromList(myListeners).iterator();
DataSourceListener listener_var;
while (listener_it.hasNext()) {
listener_var = listener_it.next();
if (listener_var instanceof PsiJavaStubListener) {
((PsiJavaStubListener) listener_var).changed(this, ourEvent);
} else {
listener_var.changed(this);
}
}
}
}
}
@Override
public void addListener(DataSourceListener listener) {
synchronized (LOCK) {
if (ListSequence.fromList(myListeners).isEmpty()) {
startListening();
}
ListSequence.fromList(myListeners).addElement(listener);
}
}
@Override
public void removeListener(DataSourceListener listener) {
synchronized (LOCK) {
ListSequence.fromList(myListeners).removeElement(listener);
if (ListSequence.fromList(myListeners).isEmpty()) {
stopListening();
}
}
}
/*package*/ void startListening() {
myModule.getProject().getComponent(PsiChangesWatcher.class).addListener(this);
}
/*package*/ void stopListening() {
myModule.getProject().getComponent(PsiChangesWatcher.class).removeListener(this);
}
public PsiDirectory getDirectory() {
return myDirectory;
}
public Iterable<PsiJavaFile> getJavaFiles() {
if (!(isValid())) {
return Sequence.fromIterable(Collections.<PsiJavaFile>emptyList());
}
return Sequence.fromIterable(Sequence.fromArray(myDirectory.getFiles())).ofType(PsiJavaFile.class);
}
private boolean isValid() {
return myDirectory.isValid() && !(myModule.getProject().isDisposed());
}
private class OurEvent extends PsiJavaStubEvent {
private Set<PsiJavaFile> removed = SetSequence.fromSet(new HashSet<PsiJavaFile>());
private Set<JavaPsiListener.FSRename> renamed = SetSequence.fromSet(new HashSet<JavaPsiListener.FSRename>());
private Set<PsiJavaFile> reparse = SetSequence.fromSet(new HashSet<PsiJavaFile>());
/*package*/ OurEvent(JavaPsiListener.PsiEvent psiEvent) {
// here we fill our data structures based on psi event
// we do filtering based on whether items are related to this data source (i.e. this psiDirectory)
for (PsiFileSystemItem fsItem : psiEvent.getRemoved()) {
if (!(isOurJavaFile(fsItem))) {
continue;
}
SetSequence.fromSet(removed).addElement(((PsiJavaFile) fsItem));
}
for (JavaPsiListener.FSMove fsMove : psiEvent.getMoved()) {
if (!(fsMove.item instanceof PsiJavaFile)) {
continue;
}
if (myDirectory.equals(fsMove.to)) {
SetSequence.fromSet(reparse).addElement(((PsiJavaFile) fsMove.item));
} else if (myDirectory.equals(fsMove.from)) {
SetSequence.fromSet(removed).addElement(((PsiJavaFile) fsMove.item));
}
}
for (JavaPsiListener.FSRename fsRename : psiEvent.getRenamed()) {
// FIXME the case when a java file was renamed to a non-java file is not handled
// in this case we have to record the file as removed
if (!(isOurJavaFile(fsRename.item))) {
continue;
}
SetSequence.fromSet(renamed).addElement(fsRename);
}
for (PsiFileSystemItem fsItem : psiEvent.getChanged()) {
if (!(isOurJavaFile(fsItem))) {
continue;
}
SetSequence.fromSet(reparse).addElement(((PsiJavaFile) fsItem));
}
for (PsiFileSystemItem fsItem : psiEvent.getCreated()) {
if (!(isOurJavaFile(fsItem))) {
continue;
}
SetSequence.fromSet(reparse).addElement(((PsiJavaFile) fsItem));
}
}
public Iterable<PsiJavaFile> removed() {
return removed;
}
public Set<PsiJavaFile> needReparse() {
return reparse;
}
public Set<JavaPsiListener.FSRename> renamed() {
return renamed;
}
private boolean isOurJavaFile(PsiFileSystemItem fsItem) {
if (!(fsItem instanceof PsiJavaFile)) {
return false;
}
if (!(fsItem.isValid())) {
return false;
}
if (!(myDirectory.equals(fsItem.getParent()))) {
return false;
}
return true;
}
}
}