mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
platform: extract BaseContentCloseListener
This commit is contained in:
@@ -2,23 +2,15 @@
|
||||
package com.intellij.build;
|
||||
|
||||
import com.intellij.build.process.BuildProcessHandler;
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.TerminateRemoteProcessDialog;
|
||||
import com.intellij.execution.runners.ExecutionUtil;
|
||||
import com.intellij.execution.ui.BaseContentCloseListener;
|
||||
import com.intellij.execution.ui.RunContentManagerImpl;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.GeneralSettings;
|
||||
import com.intellij.ide.impl.ContentManagerWatcher;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.VetoableProjectManagerListener;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
@@ -29,9 +21,10 @@ import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowAnchor;
|
||||
import com.intellij.openapi.wm.ToolWindowId;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.ui.content.*;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentManager;
|
||||
import com.intellij.ui.content.TabbedContent;
|
||||
import com.intellij.util.ContentUtilEx;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -77,7 +70,7 @@ public class BuildContentManagerImpl implements BuildContentManager {
|
||||
|
||||
StartupManager.getInstance(project).runWhenProjectIsInitialized(() -> {
|
||||
ToolWindow toolWindow = ToolWindowManager.getInstance(project)
|
||||
.registerToolWindow(ToolWindowId.BUILD, true, ToolWindowAnchor.BOTTOM, project, true);
|
||||
.registerToolWindow(ToolWindowId.BUILD, true, ToolWindowAnchor.BOTTOM, project, true);
|
||||
toolWindow.setIcon(AllIcons.Toolwindows.ToolWindowBuild);
|
||||
toolWindow.setAvailable(true, null);
|
||||
toolWindow.hide(null);
|
||||
@@ -99,7 +92,7 @@ public class BuildContentManagerImpl implements BuildContentManager {
|
||||
});
|
||||
new ContentManagerWatcher(toolWindow, contentManager);
|
||||
|
||||
for (Runnable postponedRunnable: myPostponedRunnables) {
|
||||
for (Runnable postponedRunnable : myPostponedRunnables) {
|
||||
postponedRunnable.run();
|
||||
}
|
||||
myPostponedRunnables.clear();
|
||||
@@ -143,7 +136,7 @@ public class BuildContentManagerImpl implements BuildContentManager {
|
||||
final Content[] existingContents = contentManager.getContents();
|
||||
if (idx != -1) {
|
||||
final MultiMap<String, String> existingCategoriesNames = MultiMap.createSmart();
|
||||
for (Content existingContent: existingContents) {
|
||||
for (Content existingContent : existingContents) {
|
||||
String tabName = existingContent.getTabName();
|
||||
existingCategoriesNames.putValue(StringUtil.trimEnd(StringUtil.split(tabName, " ").get(0), ':'), tabName);
|
||||
}
|
||||
@@ -162,7 +155,7 @@ public class BuildContentManagerImpl implements BuildContentManager {
|
||||
contentManager.addContent(content);
|
||||
}
|
||||
|
||||
for (Content existingContent: existingContents) {
|
||||
for (Content existingContent : existingContents) {
|
||||
existingContent.setDisplayName(existingContent.getTabName());
|
||||
}
|
||||
String tabName = content.getTabName();
|
||||
@@ -284,41 +277,17 @@ public class BuildContentManagerImpl implements BuildContentManager {
|
||||
});
|
||||
}
|
||||
|
||||
private class CloseListener extends ContentManagerAdapter implements VetoableProjectManagerListener, Disposable {
|
||||
@Nullable
|
||||
private Content myContent;
|
||||
private class CloseListener extends BaseContentCloseListener {
|
||||
@Nullable
|
||||
private BuildProcessHandler myProcessHandler;
|
||||
|
||||
private CloseListener(@NotNull final Content content, @NotNull BuildProcessHandler processHandler) {
|
||||
myContent = content;
|
||||
ContentManager contentManager = content.getManager();
|
||||
if (contentManager != null) {
|
||||
contentManager.addContentManagerListener(this);
|
||||
}
|
||||
ProjectManager.getInstance().addProjectManagerListener(myProject, this);
|
||||
super(content, myProject);
|
||||
myProcessHandler = processHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentRemoved(@NotNull final ContentManagerEvent event) {
|
||||
final Content content = event.getContent();
|
||||
if (content == myContent) {
|
||||
Disposer.dispose(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (myContent == null) return;
|
||||
|
||||
final Content content = myContent;
|
||||
ContentManager contentManager = content.getManager();
|
||||
if (contentManager != null) {
|
||||
contentManager.removeContentManagerListener(this);
|
||||
}
|
||||
ProjectManager.getInstance().removeProjectManagerListener(myProject, this);
|
||||
myContent = null;
|
||||
protected void disposeContent(@NotNull Content content) {
|
||||
if (myProcessHandler instanceof Disposable) {
|
||||
Disposer.dispose((Disposable)myProcessHandler);
|
||||
}
|
||||
@@ -326,124 +295,20 @@ public class BuildContentManagerImpl implements BuildContentManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentRemoveQuery(@NotNull final ContentManagerEvent event) {
|
||||
if (event.getContent() == myContent) {
|
||||
final boolean canClose = closeQuery(false);
|
||||
if (!canClose) {
|
||||
event.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectClosed(@NotNull final Project project) {
|
||||
if (myContent != null && project == myProject) {
|
||||
ContentManager contentManager = myContent.getManager();
|
||||
if (contentManager != null) {
|
||||
contentManager.removeContent(myContent, true);
|
||||
}
|
||||
Disposer.dispose(this); // Dispose content even if content manager refused to.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canClose(@NotNull Project project) {
|
||||
if (project != myProject) return true;
|
||||
|
||||
if (myContent == null) return true;
|
||||
|
||||
final boolean canClose = closeQuery(true);
|
||||
// Content could be removed during close query
|
||||
if (canClose && myContent != null) {
|
||||
ContentManager contentManager = myContent.getManager();
|
||||
if (contentManager != null) contentManager.removeContent(myContent, true);
|
||||
myContent = null;
|
||||
}
|
||||
return canClose;
|
||||
}
|
||||
|
||||
private boolean closeQuery(boolean modal) {
|
||||
protected boolean closeQuery(@NotNull Content content, boolean modal) {
|
||||
if (myProcessHandler == null || myProcessHandler.isProcessTerminated() || myProcessHandler.isProcessTerminating()) {
|
||||
return true;
|
||||
}
|
||||
myProcessHandler.putUserData(RunContentManagerImpl.ALWAYS_USE_DEFAULT_STOPPING_BEHAVIOUR_KEY, Boolean.TRUE);
|
||||
GeneralSettings.ProcessCloseConfirmation rc =
|
||||
TerminateRemoteProcessDialog.show(myProject, myProcessHandler.getExecutionName(), myProcessHandler);
|
||||
if(myProcessHandler == null) { // process finished before the dialog close
|
||||
return true;
|
||||
}
|
||||
if (rc == null) { // cancel
|
||||
return false;
|
||||
}
|
||||
boolean destroyProcess = rc == GeneralSettings.ProcessCloseConfirmation.TERMINATE;
|
||||
if (destroyProcess) {
|
||||
myProcessHandler.destroyProcess();
|
||||
}
|
||||
else {
|
||||
myProcessHandler.detachProcess();
|
||||
}
|
||||
waitForProcess(modal, myProcessHandler);
|
||||
return true;
|
||||
final String sessionName = myProcessHandler.getExecutionName();
|
||||
final WaitForProcessTask task = new WaitForProcessTask(myProcessHandler, sessionName, modal, myProject) {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
// stop waiting for the process
|
||||
myProcessHandler.forceProcessDetach();
|
||||
}
|
||||
};
|
||||
return askUserAndWait(myProcessHandler, sessionName, task);
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForProcess(final boolean modal, BuildProcessHandler processHandler) {
|
||||
String title = ExecutionBundle.message("terminating.process.progress.title", processHandler.getExecutionName());
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, title, true) {
|
||||
|
||||
@Override
|
||||
public boolean isConditionalModal() {
|
||||
return modal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStartInBackground() {
|
||||
return !modal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator progressIndicator) {
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
try {
|
||||
processHandler.waitFor();
|
||||
}
|
||||
finally {
|
||||
semaphore.up();
|
||||
}
|
||||
});
|
||||
|
||||
progressIndicator.setText(ExecutionBundle.message("waiting.for.vm.detach.progress.text"));
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
if (progressIndicator.isCanceled() || !progressIndicator.isRunning()) {
|
||||
semaphore.up();
|
||||
break;
|
||||
}
|
||||
try {
|
||||
//noinspection SynchronizeOnThis
|
||||
synchronized (this) {
|
||||
//noinspection SynchronizeOnThis
|
||||
wait(2000L);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
semaphore.waitFor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
// stop waiting for the process
|
||||
processHandler.forceProcessDetach();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.execution.ui;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.TerminateRemoteProcessDialog;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.ide.GeneralSettings;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.VetoableProjectManagerListener;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentManager;
|
||||
import com.intellij.ui.content.ContentManagerAdapter;
|
||||
import com.intellij.ui.content.ContentManagerEvent;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class BaseContentCloseListener extends ContentManagerAdapter implements VetoableProjectManagerListener, Disposable {
|
||||
private Content myContent;
|
||||
private final Project myProject;
|
||||
|
||||
public BaseContentCloseListener(@NotNull final Content content, @NotNull final Project project) {
|
||||
myContent = content;
|
||||
myProject = project;
|
||||
final ContentManager contentManager = content.getManager();
|
||||
if (contentManager != null) {
|
||||
contentManager.addContentManagerListener(this);
|
||||
}
|
||||
ProjectManager.getInstance().addProjectManagerListener(myProject, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentRemoved(@NotNull final ContentManagerEvent event) {
|
||||
final Content content = event.getContent();
|
||||
if (content == myContent) {
|
||||
Disposer.dispose(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (myContent == null) return;
|
||||
|
||||
final Content content = myContent;
|
||||
try {
|
||||
disposeContent(content);
|
||||
}
|
||||
finally {
|
||||
final ContentManager contentManager = content.getManager();
|
||||
if (contentManager != null) {
|
||||
contentManager.removeContentManagerListener(this);
|
||||
}
|
||||
ProjectManager.getInstance().removeProjectManagerListener(myProject, this);
|
||||
content.release(); // don't invoke myContent.release() because myContent can becomes null
|
||||
myContent = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void disposeContent(@NotNull Content content);
|
||||
|
||||
@Override
|
||||
public void contentRemoveQuery(@NotNull final ContentManagerEvent event) {
|
||||
if (event.getContent() == myContent) {
|
||||
final boolean canClose = closeQuery(myContent, false);
|
||||
if (!canClose) {
|
||||
event.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectClosed(@NotNull final Project project) {
|
||||
if (myContent == null || project != myProject) return;
|
||||
ContentManager contentManager = myContent.getManager();
|
||||
if (contentManager != null) {
|
||||
contentManager.removeContent(myContent, true);
|
||||
}
|
||||
Disposer.dispose(this); // Dispose content even if content manager refused to.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canClose(@NotNull Project project) {
|
||||
if (myContent == null || project != myProject) return true;
|
||||
|
||||
final boolean canClose = closeQuery(myContent, true);
|
||||
// Content could be removed during close query
|
||||
if (canClose && myContent != null) {
|
||||
myContent.getManager().removeContent(myContent, true);
|
||||
myContent = null;
|
||||
}
|
||||
return canClose;
|
||||
}
|
||||
|
||||
protected boolean askUserAndWait(@NotNull ProcessHandler processHandler, @NotNull String sessionName, @NotNull WaitForProcessTask task) {
|
||||
GeneralSettings.ProcessCloseConfirmation rc = TerminateRemoteProcessDialog.show(myProject, sessionName, processHandler);
|
||||
if (rc == null) { // cancel
|
||||
return false;
|
||||
}
|
||||
boolean destroyProcess = rc == GeneralSettings.ProcessCloseConfirmation.TERMINATE;
|
||||
if (destroyProcess) {
|
||||
processHandler.destroyProcess();
|
||||
}
|
||||
else {
|
||||
processHandler.detachProcess();
|
||||
}
|
||||
ProgressManager.getInstance().run(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract boolean closeQuery(@NotNull Content content, boolean modal);
|
||||
|
||||
protected abstract static class WaitForProcessTask extends Task.Backgroundable {
|
||||
final ProcessHandler myProcessHandler;
|
||||
final boolean myModal;
|
||||
|
||||
protected WaitForProcessTask(@NotNull ProcessHandler processHandler,
|
||||
@NotNull String processName,
|
||||
boolean modal,
|
||||
@Nullable Project project) {
|
||||
super(project, ExecutionBundle.message("terminating.process.progress.title", processName));
|
||||
myProcessHandler = processHandler;
|
||||
myModal = modal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConditionalModal() {
|
||||
return myModal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStartInBackground() {
|
||||
return !myModal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator progressIndicator) {
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
try {
|
||||
myProcessHandler.waitFor();
|
||||
}
|
||||
finally {
|
||||
semaphore.up();
|
||||
}
|
||||
});
|
||||
progressIndicator.setText(ExecutionBundle.message("waiting.for.vm.detach.progress.text"));
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
if (progressIndicator.isCanceled() || !progressIndicator.isRunning()) {
|
||||
semaphore.up();
|
||||
break;
|
||||
}
|
||||
try {
|
||||
//noinspection SynchronizeOnThis
|
||||
synchronized (this) {
|
||||
//noinspection SynchronizeOnThis
|
||||
wait(2000L);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
semaphore.waitFor();
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract public void onCancel(); //force user to override
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.execution.ui;
|
||||
|
||||
import com.intellij.execution.*;
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.ExecutorRegistry;
|
||||
import com.intellij.execution.KillableProcess;
|
||||
import com.intellij.execution.configurations.RunConfiguration;
|
||||
import com.intellij.execution.dashboard.RunDashboardManager;
|
||||
import com.intellij.execution.process.ProcessAdapter;
|
||||
@@ -11,19 +14,13 @@ import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.runners.ExecutionUtil;
|
||||
import com.intellij.execution.ui.layout.impl.DockableGridContainerFactory;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.GeneralSettings;
|
||||
import com.intellij.ide.impl.ContentManagerWatcher;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.VetoableProjectManagerListener;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowAnchor;
|
||||
@@ -34,7 +31,6 @@ import com.intellij.ui.AppUIUtil;
|
||||
import com.intellij.ui.content.*;
|
||||
import com.intellij.ui.docking.DockManager;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import gnu.trove.THashMap;
|
||||
@@ -605,80 +601,26 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
|
||||
return null;
|
||||
}
|
||||
|
||||
private class CloseListener extends ContentManagerAdapter implements VetoableProjectManagerListener, Disposable {
|
||||
private Content myContent;
|
||||
private class CloseListener extends BaseContentCloseListener {
|
||||
private final Executor myExecutor;
|
||||
|
||||
private CloseListener(@NotNull final Content content, @NotNull Executor executor) {
|
||||
myContent = content;
|
||||
content.getManager().addContentManagerListener(this);
|
||||
ProjectManager.getInstance().addProjectManagerListener(myProject, this);
|
||||
private CloseListener(@NotNull final Content content, @NotNull final Executor executor) {
|
||||
super(content, myProject);
|
||||
myExecutor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentRemoved(@NotNull final ContentManagerEvent event) {
|
||||
final Content content = event.getContent();
|
||||
if (content == myContent) {
|
||||
Disposer.dispose(this);
|
||||
protected void disposeContent(@NotNull Content content) {
|
||||
RunContentDescriptor descriptor = getRunContentDescriptorByContent(content);
|
||||
getSyncPublisher().contentRemoved(descriptor, myExecutor);
|
||||
if (descriptor != null) {
|
||||
Disposer.dispose(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (myContent == null) return;
|
||||
|
||||
final Content content = myContent;
|
||||
try {
|
||||
RunContentDescriptor descriptor = getRunContentDescriptorByContent(content);
|
||||
getSyncPublisher().contentRemoved(descriptor, myExecutor);
|
||||
if (descriptor != null) {
|
||||
Disposer.dispose(descriptor);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
content.getManager().removeContentManagerListener(this);
|
||||
ProjectManager.getInstance().removeProjectManagerListener(myProject, this);
|
||||
content.release(); // don't invoke myContent.release() because myContent becomes null after destroyProcess()
|
||||
myContent = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentRemoveQuery(@NotNull final ContentManagerEvent event) {
|
||||
if (event.getContent() == myContent) {
|
||||
final boolean canClose = closeQuery(false);
|
||||
if (!canClose) {
|
||||
event.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectClosed(@NotNull final Project project) {
|
||||
if (myContent != null && project == myProject) {
|
||||
myContent.getManager().removeContent(myContent, true);
|
||||
Disposer.dispose(this); // Dispose content even if content manager refused to.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canClose(@NotNull Project project) {
|
||||
if (project != myProject) return true;
|
||||
|
||||
if (myContent == null) return true;
|
||||
|
||||
final boolean canClose = closeQuery(true);
|
||||
// Content could be removed during close query
|
||||
if (canClose && myContent != null) {
|
||||
myContent.getManager().removeContent(myContent, true);
|
||||
myContent = null;
|
||||
}
|
||||
return canClose;
|
||||
}
|
||||
|
||||
private boolean closeQuery(boolean modal) {
|
||||
final RunContentDescriptor descriptor = getRunContentDescriptorByContent(myContent);
|
||||
protected boolean closeQuery(@NotNull Content content, boolean modal) {
|
||||
final RunContentDescriptor descriptor = getRunContentDescriptorByContent(content);
|
||||
if (descriptor == null) {
|
||||
return true;
|
||||
}
|
||||
@@ -687,96 +629,27 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
|
||||
if (processHandler == null || processHandler.isProcessTerminated() || processHandler.isProcessTerminating()) {
|
||||
return true;
|
||||
}
|
||||
GeneralSettings.ProcessCloseConfirmation rc = TerminateRemoteProcessDialog.show(
|
||||
myProject, descriptor.getDisplayName(), processHandler);
|
||||
if (rc == null) { // cancel
|
||||
return false;
|
||||
}
|
||||
boolean destroyProcess = rc == GeneralSettings.ProcessCloseConfirmation.TERMINATE;
|
||||
if (destroyProcess) {
|
||||
processHandler.destroyProcess();
|
||||
}
|
||||
else {
|
||||
processHandler.detachProcess();
|
||||
}
|
||||
waitForProcess(descriptor, modal);
|
||||
return true;
|
||||
final String sessionName = descriptor.getDisplayName();
|
||||
final WaitForProcessTask task = new WaitForProcessTask(processHandler, sessionName, modal, myProject) {
|
||||
final boolean killable =
|
||||
!modal && (processHandler instanceof KillableProcess) && ((KillableProcess)processHandler).canKillProcess();
|
||||
|
||||
{
|
||||
if (killable) {
|
||||
String cancelText = ExecutionBundle.message("terminating.process.progress.kill");
|
||||
setCancelText(cancelText);
|
||||
setCancelTooltipText(cancelText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
if (killable && !processHandler.isProcessTerminated()) {
|
||||
((KillableProcess)processHandler).killProcess();
|
||||
}
|
||||
}
|
||||
};
|
||||
return askUserAndWait(processHandler, sessionName, task);
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForProcess(final RunContentDescriptor descriptor, final boolean modal) {
|
||||
final ProcessHandler processHandler = descriptor.getProcessHandler();
|
||||
final boolean killable = !modal && (processHandler instanceof KillableProcess) && ((KillableProcess)processHandler).canKillProcess();
|
||||
|
||||
String title = ExecutionBundle.message("terminating.process.progress.title", descriptor.getDisplayName());
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, title, true) {
|
||||
|
||||
{
|
||||
if (killable) {
|
||||
String cancelText= ExecutionBundle.message("terminating.process.progress.kill");
|
||||
setCancelText(cancelText);
|
||||
setCancelTooltipText(cancelText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConditionalModal() {
|
||||
return modal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStartInBackground() {
|
||||
return !modal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator progressIndicator) {
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
final ProcessHandler processHandler1 = descriptor.getProcessHandler();
|
||||
try {
|
||||
if (processHandler1 != null) {
|
||||
processHandler1.waitFor();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
semaphore.up();
|
||||
}
|
||||
});
|
||||
|
||||
progressIndicator.setText(ExecutionBundle.message("waiting.for.vm.detach.progress.text"));
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
if (progressIndicator.isCanceled() || !progressIndicator.isRunning()) {
|
||||
semaphore.up();
|
||||
break;
|
||||
}
|
||||
try {
|
||||
//noinspection SynchronizeOnThis
|
||||
synchronized (this) {
|
||||
//noinspection SynchronizeOnThis
|
||||
wait(2000L);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
semaphore.waitFor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
if (killable && !processHandler.isProcessTerminated()) {
|
||||
((KillableProcess)processHandler).killProcess();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user