package com.intellij.flex.uiDesigner;
import com.intellij.AppTopics;
import com.intellij.flex.uiDesigner.mxml.ProjectComponentReferenceCounter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlFile;
import com.intellij.util.Consumer;
import gnu.trove.TObjectObjectProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.Info;
import org.jetbrains.io.InfoMap;
import java.util.List;
public class DocumentFactoryManager {
private final InfoMap<VirtualFile, DocumentInfo> files = new InfoMap<>();
public DocumentFactoryManager() {
ApplicationManager.getApplication().getMessageBus().connect(DesignerApplicationManager.getApplication())
.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new MyFileDocumentManagerListener());
}
public static DocumentFactoryManager getInstance() {
return DesignerApplicationManager.getService(DocumentFactoryManager.class);
}
public void unregister(final int[] ids) {
files.remove(ids, info -> info.disposeRangeMarkers());
}
public void unregister(final Project project) {
files.remove(new TObjectObjectProcedure<VirtualFile, DocumentInfo>() {
@Override
public boolean execute(VirtualFile file, DocumentInfo documentInfo) {
return ProjectUtil.guessProjectForFile(file) != project;
}
});
}
private static class MyFileDocumentManagerListener extends FileDocumentManagerAdapter {
@Override
public void beforeAllDocumentsSaving() {
final Document[] unsavedDocuments = FileDocumentManager.getInstance().getUnsavedDocuments();
if (unsavedDocuments.length <= 0) {
return;
}
ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().executeOnPooledThread(
() -> DesignerApplicationManager.getInstance().renderDocumentsAndCheckLocalStyleModification(unsavedDocuments)));
}
}
public boolean isRegistered(VirtualFile virtualFile) {
return files.contains(virtualFile);
}
public int getId(VirtualFile virtualFile) {
return getId(virtualFile, null, null);
}
public int getId(VirtualFile virtualFile, @Nullable XmlFile psiFile, @Nullable ProjectComponentReferenceCounter referenceCounter) {
return get(virtualFile, psiFile, referenceCounter).getId();
}
@Nullable
public DocumentInfo getNullableInfo(VirtualFile virtualFile) {
return files.getNullableInfo(virtualFile);
}
@Nullable
public DocumentInfo getNullableInfo(PsiFile psiFile) {
return files.getNullableInfo(psiFile.getVirtualFile());
}
public DocumentInfo get(VirtualFile virtualFile, @Nullable XmlFile psiFile, @Nullable ProjectComponentReferenceCounter referenceCounter) {
DocumentInfo info = files.getNullableInfo(virtualFile);
if (info != null) {
if (referenceCounter != null) {
referenceCounter.registered(info.getId());
}
return info;
}
info = new DocumentInfo(virtualFile);
files.add(info);
if (referenceCounter != null) {
referenceCounter.unregistered(info.getId(), psiFile);
}
return info;
}
@NotNull
public VirtualFile getFile(int id) {
return files.getElement(id);
}
@NotNull
public DocumentInfo getInfo(int id) {
return files.getInfo(id);
}
public static final class DocumentInfo extends Info<VirtualFile> {
public long documentModificationStamp;
private List<RangeMarker> rangeMarkers;
public RangeMarker getRangeMarker(int id) {
return rangeMarkers.get(id);
}
public DocumentInfo(@NotNull VirtualFile element) {
super(element);
}
public int rangeMarkerIndexOf(PsiElement element) {
for (int i = 0; i < rangeMarkers.size(); i++) {
RangeMarker rangeMarker = rangeMarkers.get(i);
if (rangeMarker.getStartOffset() == element.getTextOffset()) {
return i;
}
}
return -1;
}
public void setRangeMarkers(List<RangeMarker> rangeMarkers) {
disposeRangeMarkers();
this.rangeMarkers = rangeMarkers;
}
public void disposeRangeMarkers() {
if (rangeMarkers == null || rangeMarkers.isEmpty()) {
return;
}
for (RangeMarker rangeMarker : rangeMarkers) {
rangeMarker.dispose();
}
}
@Override
public boolean equals(Object obj) {
return this == obj || obj instanceof DocumentInfo && ((DocumentInfo)obj).getId() == getId();
}
}
}