refactor as prepare to fix WI-12979

extract LookupSynchronizerFactory
extract document watcher from AutoTestManager
This commit is contained in:
Vladimir Krivosheev
2012-09-04 20:58:44 +04:00
parent b579aab18b
commit 5632706c66
5 changed files with 166 additions and 64 deletions
@@ -19,4 +19,4 @@ public abstract class WebServerManager implements ApplicationComponent {
public abstract int getPort();
public abstract void addClosingListener(ChannelFutureListener listener);
}
}
@@ -0,0 +1,142 @@
package com.intellij.execution;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileAdapter;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.util.Alarm;
import com.intellij.util.Consumer;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class AutoExecutor implements Runnable {
private final Project project;
private final Alarm alarm;
private final Consumer<VirtualFile[]> consumer;
private final int delay;
private final MyDocumentAdapter listener;
private boolean listenerAttached;
private final Set<VirtualFile> changedFiles = new THashSet<VirtualFile>();
private boolean wasRequested;
private final Condition<VirtualFile> documentChangedFilter;
public AutoExecutor(Project project, Alarm alarm, int delay, Consumer<VirtualFile[]> consumer, Condition<VirtualFile> documentChangedFilter) {
this.project = project;
this.alarm = alarm;
this.delay = delay;
this.consumer = consumer;
this.documentChangedFilter = documentChangedFilter;
listener = new MyDocumentAdapter();
project.getMessageBus().connect().subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
@Override
public void before(@NotNull List<? extends VFileEvent> events) {
}
@Override
public void after(@NotNull List<? extends VFileEvent> events) {
for (VFileEvent event : events) {
if (event instanceof VFileDeleteEvent) {
synchronized (changedFiles) {
changedFiles.remove(event.getFile());
}
}
}
}
});
}
private void addVfsListener() {
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() {
@Override
public void fileDeleted(VirtualFileEvent event) {
synchronized (changedFiles) {
changedFiles.remove(event.getFile());
}
}
});
}
@Override
public void run() {
final VirtualFile[] files;
synchronized (changedFiles) {
wasRequested = false;
files = changedFiles.toArray(new VirtualFile[changedFiles.size()]);
changedFiles.clear();
}
final WolfTheProblemSolver problemSolver = WolfTheProblemSolver.getInstance(project);
for (VirtualFile file : files) {
if (problemSolver.hasSyntaxErrors(file)) {
// threat any other file in queue as dependency of this file — don't flush if some of the queued file is invalid
// Vladimir.Krivosheev AutoTestManager behavior behavior is preserved.
// LiveEdit version used another strategy (flush all valid files), but now we use AutoTestManager-inspired strategy
synchronized (changedFiles) {
Collections.addAll(changedFiles, files);
}
return;
}
}
consumer.consume(files);
}
public Project getProject() {
return project;
}
public void activate() {
if (!listenerAttached) {
listenerAttached = true;
EditorFactory.getInstance().getEventMulticaster().addDocumentListener(listener, project);
}
}
public void deactivate() {
if (listenerAttached) {
listenerAttached = false;
EditorFactory.getInstance().getEventMulticaster().removeDocumentListener(listener);
}
}
private class MyDocumentAdapter extends DocumentAdapter {
public void documentChanged(DocumentEvent event) {
final Document document = event.getDocument();
final VirtualFile file = FileDocumentManager.getInstance().getFile(document);
if (file == null || !documentChangedFilter.value(file)) {
return;
}
synchronized (changedFiles) {
// changedFiles contains is not enough, because it can contain not-flushed files from prev request (which are not flushed because some is invalid)
if (!changedFiles.add(file) && wasRequested) {
return;
}
}
alarm.cancelRequest(AutoExecutor.this);
alarm.addRequest(AutoExecutor.this, delay);
}
}
}
@@ -72,4 +72,4 @@ class WebServerManagerImpl extends WebServerManager {
public String getComponentName() {
return getClass().getName();
}
}
}
@@ -1,21 +1,17 @@
package com.intellij.execution.testframework.autotest;
import com.intellij.execution.AutoExecutor;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunContentManagerImpl;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.impl.PsiAwareFileEditorManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.content.Content;
import com.intellij.util.Alarm;
import com.intellij.util.Consumer;
import com.intellij.util.containers.WeakList;
import java.util.Collection;
@@ -24,14 +20,9 @@ import java.util.Collection;
* @author yole
*/
public class AutoTestManager {
private final Project myProject;
private final PsiAwareFileEditorManagerImpl myManager;
private final Alarm myAutoTestAlarm;
private final AutoExecutor myAutoExecutor;
private static final int AUTOTEST_DELAY = 10000;
private final Runnable myRunTestsRunnable;
private boolean myListenerAttached;
private final MyDocumentAdapter myListener;
public static AutoTestManager getInstance(Project project) {
return ServiceManager.getService(project, AutoTestManager.class);
@@ -39,18 +30,21 @@ public class AutoTestManager {
private final Collection<Content> myEnabledDescriptors = new WeakList<Content>();
public AutoTestManager(Project project, FileEditorManager manager) {
myProject = project;
myManager = manager instanceof PsiAwareFileEditorManagerImpl ?
(PsiAwareFileEditorManagerImpl)manager :
null;
myAutoTestAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, project);
myRunTestsRunnable = new Runnable() {
public void run() {
runAutoTests();
public AutoTestManager(Project project) {
myAutoExecutor = new AutoExecutor(project, new Alarm(Alarm.ThreadToUse.SWING_THREAD, project), AUTOTEST_DELAY, new Consumer<VirtualFile[]>() {
@Override
public void consume(VirtualFile[] files) {
for (Content content : myEnabledDescriptors) {
runAutoTest(content);
}
}
};
myListener = new MyDocumentAdapter();
}, new Condition<VirtualFile>() {
@Override
public boolean value(VirtualFile file) {
// Vladimir.Krivosheev — I don't know, why AutoTestManager checks it, but old behavior is preserved
return FileEditorManager.getInstance(myAutoExecutor.getProject()).isFileOpen(file);
}
});
}
public void setAutoTestEnabled(RunContentDescriptor descriptor, boolean enabled) {
@@ -59,16 +53,12 @@ public class AutoTestManager {
if (!myEnabledDescriptors.contains(content)) {
myEnabledDescriptors.add(content);
}
if (!myListenerAttached) {
myListenerAttached = true;
EditorFactory.getInstance().getEventMulticaster().addDocumentListener(myListener, myProject);
}
myAutoExecutor.activate();
}
else {
myEnabledDescriptors.remove(content);
if (myEnabledDescriptors.isEmpty() && myListenerAttached) {
myListenerAttached = false;
EditorFactory.getInstance().getEventMulticaster().removeDocumentListener(myListener);
if (myEnabledDescriptors.isEmpty()) {
myAutoExecutor.deactivate();
}
}
}
@@ -77,20 +67,6 @@ public class AutoTestManager {
return myEnabledDescriptors.contains(descriptor.getAttachedContent());
}
public void runAutoTests() {
if (myManager != null) {
for (FileEditor editor : myManager.getAllEditors()) {
final VirtualFile file = myManager.getFile(editor);
if (file != null && myManager.isProblem(file)) {
return;
}
}
}
for (Content content : myEnabledDescriptors) {
runAutoTest(content);
}
}
private static void runAutoTest(Content content) {
RunContentDescriptor descriptor = RunContentManagerImpl.getRunContentDescriptorByContent(content);
if (descriptor == null) {
@@ -106,18 +82,4 @@ public class AutoTestManager {
}
restarter.run();
}
private class MyDocumentAdapter extends DocumentAdapter {
public void documentChanged(DocumentEvent event) {
final Document document = event.getDocument();
final VirtualFile vFile = FileDocumentManager.getInstance().getFile(document);
if (vFile != null) {
final FileEditor[] editors = FileEditorManager.getInstance(myProject).getEditors(vFile);
if (editors.length > 0) {
myAutoTestAlarm.cancelAllRequests();
myAutoTestAlarm.addRequest(myRunTestsRunnable, AUTOTEST_DELAY);
}
}
}
}
}
@@ -21,9 +21,7 @@ public class ToggleAutoTestAction extends ToggleAction {
public boolean isSelected(AnActionEvent e) {
Project project = e.getData(PlatformDataKeys.PROJECT);
RunContentDescriptor descriptor = e.getData(RunContentManager.RUN_CONTENT_DESCRIPTOR);
return project == null || descriptor == null
? false
: AutoTestManager.getInstance(project).isAutoTestEnabled(descriptor);
return !(project == null || descriptor == null) && AutoTestManager.getInstance(project).isAutoTestEnabled(descriptor);
}
@Override