*/
package com.intellij.execution;
-import com.google.common.collect.ImmutableSet;
import com.intellij.AppTopics;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
private final Project myProject;
private final Alarm myAlarm;
private final int myDelayMillis;
- private final Consumer<Set<VirtualFile>> myConsumer;
+ private final Consumer<Integer> myModificationStampConsumer;
private final Condition<VirtualFile> myChangedFileFilter;
private final MyDocumentAdapter myListener;
private final Runnable myAlarmRunnable;
private final Set<VirtualFile> myChangedFiles = new THashSet<VirtualFile>();
private boolean myDocumentSavingInProgress = false;
private MessageBusConnection myConnection;
- private int myEventCount = 0;
+ private int myModificationStamp = 0;
public DelayedDocumentWatcher(@NotNull Project project,
int delayMillis,
- @NotNull Consumer<Set<VirtualFile>> consumer,
+ @NotNull Consumer<Integer> modificationStampConsumer,
@Nullable Condition<VirtualFile> changedFileFilter) {
myProject = project;
myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, myProject);
myDelayMillis = delayMillis;
- myConsumer = consumer;
+ myModificationStampConsumer = modificationStampConsumer;
myChangedFileFilter = changedFileFilter;
myListener = new MyDocumentAdapter();
myAlarmRunnable = new MyRunnable();
}
}
+ public boolean isUpToDate(int modificationStamp) {
+ return myModificationStamp == modificationStamp;
+ }
+
private class MyDocumentAdapter extends DocumentAdapter {
@Override
public void documentChanged(DocumentEvent event) {
myAlarm.cancelRequest(myAlarmRunnable);
myAlarm.addRequest(myAlarmRunnable, myDelayMillis);
- myEventCount++;
+ myModificationStamp++;
}
}
private class MyRunnable implements Runnable {
@Override
public void run() {
- final int oldEventCount = myEventCount;
- final Set<VirtualFile> copy = ImmutableSet.copyOf(myChangedFiles);
- asyncCheckErrors(copy, new Consumer<Boolean>() {
+ final int oldModificationStamp = myModificationStamp;
+ asyncCheckErrors(myChangedFiles, new Consumer<Boolean>() {
@Override
public void consume(Boolean errorsFound) {
- if (myEventCount != oldEventCount) {
+ if (myModificationStamp != oldModificationStamp) {
// 'documentChanged' event was raised during async checking files for errors
// Do nothing in that case, this method will be invoked subsequently.
return;
return;
}
myChangedFiles.clear();
- myConsumer.consume(copy);
+ myModificationStampConsumer.consume(myModificationStamp);
}
});
}
}
return WolfTheProblemSolver.getInstance(myProject).hasSyntaxErrors(file);
}
-
}
package com.intellij.execution.testframework.autotest;
import com.intellij.execution.DelayedDocumentWatcher;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.process.ProcessListener;
import com.intellij.execution.runners.ExecutionUtil;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.ide.DataManager;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.ui.content.Content;
import com.intellij.util.Consumer;
import com.intellij.util.containers.WeakHashMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collections;
public class AutoTestManager {
static final Key<Boolean> AUTOTESTABLE = Key.create("auto.test.manager.supported");
public static final String AUTO_TEST_MANAGER_DELAY = "auto.test.manager.delay";
+ private static final Key<ProcessListener> ON_TERMINATION_RESTARTER_KEY = Key.create("auto.test.manager.on.termination.restarter");
private final Project myProject;
}
private DelayedDocumentWatcher createWatcher() {
- return new DelayedDocumentWatcher(myProject, myDelay, new Consumer<Set<VirtualFile>>() {
+ return new DelayedDocumentWatcher(myProject, myDelay, new Consumer<Integer>() {
@Override
- public void consume(Set<VirtualFile> files) {
+ public void consume(Integer modificationStamp) {
for (Content content : myEnabledDescriptors) {
- runAutoTest(content);
+ runAutoTest(content, modificationStamp, myDocumentWatcher);
}
}
}, new Condition<VirtualFile>() {
});
}
- public void setAutoTestEnabled(RunContentDescriptor descriptor, boolean enabled) {
+ public void setAutoTestEnabled(@NotNull RunContentDescriptor descriptor, boolean enabled) {
Content content = descriptor.getAttachedContent();
if (enabled) {
myEnabledDescriptors.add(content);
myDocumentWatcher.activate();
}
else {
+ clearRestarterListener(descriptor.getProcessHandler());
myEnabledDescriptors.remove(content);
if (myEnabledDescriptors.isEmpty()) {
myDocumentWatcher.deactivate();
}
}
+ private static void clearRestarterListener(@Nullable ProcessHandler processHandler) {
+ if (processHandler != null) {
+ ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler, null);
+ if (restarterListener != null) {
+ processHandler.removeProcessListener(restarterListener);
+ ON_TERMINATION_RESTARTER_KEY.set(processHandler, null);
+ }
+ }
+ }
+
public boolean isAutoTestEnabled(RunContentDescriptor descriptor) {
return myEnabledDescriptors.contains(descriptor.getAttachedContent());
}
- private static void runAutoTest(Content content) {
+ private static void runAutoTest(@NotNull Content content, int modificationStamp, @NotNull DelayedDocumentWatcher documentWatcher) {
JComponent component = content.getComponent();
if (component != null) {
DataContext dataContext = DataManager.getInstance().getDataContext(component);
if (descriptor != null) {
ProcessHandler processHandler = descriptor.getProcessHandler();
if (processHandler != null && !processHandler.isProcessTerminated()) {
- return;
+ scheduleRestartOnTermination(descriptor, content, processHandler, modificationStamp, documentWatcher);
+ }
+ else {
+ restart(descriptor, content);
}
-
- descriptor.setActivateToolWindowWhenAdded(false);
- descriptor.setReuseToolWindowActivation(true);
- ExecutionUtil.restart(content);
}
}
}
+ private static void scheduleRestartOnTermination(@NotNull final RunContentDescriptor descriptor,
+ @NotNull final Content content,
+ @NotNull final ProcessHandler processHandler,
+ final int modificationStamp,
+ @NotNull final DelayedDocumentWatcher documentWatcher) {
+ ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler);
+ if (restarterListener != null) {
+ return;
+ }
+ restarterListener = new ProcessAdapter() {
+ @Override
+ public void processTerminated(ProcessEvent event) {
+ clearRestarterListener(processHandler);
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ if (documentWatcher.isUpToDate(modificationStamp)) {
+ restart(descriptor, content);
+ }
+ }
+ }, ModalityState.any());
+ }
+ };
+ ON_TERMINATION_RESTARTER_KEY.set(processHandler, restarterListener);
+ processHandler.addProcessListener(restarterListener);
+ }
+
+ private static void restart(@NotNull RunContentDescriptor descriptor, @NotNull Content content) {
+ descriptor.setActivateToolWindowWhenAdded(false);
+ descriptor.setReuseToolWindowActivation(true);
+ ExecutionUtil.restart(content);
+ }
+
int getDelay() {
return myDelay;
}