blob: 9949e18d6f9bc3b6d71d35a2c66ee60870e6b00b [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.slicer;
import com.intellij.analysis.AnalysisUIOptions;
import com.intellij.ide.impl.ContentManagerWatcher;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.*;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.impl.content.BaseLabel;
import com.intellij.psi.*;
import com.intellij.refactoring.util.RefactoringDescriptionLocation;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import java.util.regex.Pattern;
@State(
name = "SliceManager",
storages = {@Storage( file = StoragePathMacros.WORKSPACE_FILE)}
)
public class SliceManager implements PersistentStateComponent<SliceManager.StoredSettingsBean> {
private final Project myProject;
private ContentManager myBackContentManager;
private ContentManager myForthContentManager;
private final StoredSettingsBean myStoredSettings = new StoredSettingsBean();
private static final String BACK_TOOLWINDOW_ID = "Analyze Dataflow to";
private static final String FORTH_TOOLWINDOW_ID = "Analyze Dataflow from";
public static class StoredSettingsBean {
public boolean showDereferences = true; // to show in dataflow/from dialog
public AnalysisUIOptions analysisUIOptions = new AnalysisUIOptions();
}
public static SliceManager getInstance(@NotNull Project project) {
return ServiceManager.getService(project, SliceManager.class);
}
public SliceManager(@NotNull Project project, PsiManager psiManager) {
myProject = project;
}
@NotNull
private Disposable addPsiListener(@NotNull final ProgressIndicator indicator) {
Disposable disposable = Disposer.newDisposable();
PsiManager.getInstance(myProject).addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
@Override
public void beforeChildAddition(@NotNull PsiTreeChangeEvent event) {
indicator.cancel();
}
@Override
public void beforeChildRemoval(@NotNull PsiTreeChangeEvent event) {
indicator.cancel();
}
@Override
public void beforeChildReplacement(@NotNull PsiTreeChangeEvent event) {
indicator.cancel();
}
@Override
public void beforeChildMovement(@NotNull PsiTreeChangeEvent event) {
indicator.cancel();
}
@Override
public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) {
indicator.cancel();
}
@Override
public void beforePropertyChange(@NotNull PsiTreeChangeEvent event) {
indicator.cancel();
}
}, disposable);
return disposable;
}
private ContentManager getContentManager(boolean dataFlowToThis) {
if (dataFlowToThis) {
if (myBackContentManager == null) {
ToolWindow backToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(BACK_TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, myProject);
myBackContentManager = backToolWindow.getContentManager();
new ContentManagerWatcher(backToolWindow, myBackContentManager);
}
return myBackContentManager;
}
if (myForthContentManager == null) {
ToolWindow forthToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(FORTH_TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, myProject);
myForthContentManager = forthToolWindow.getContentManager();
new ContentManagerWatcher(forthToolWindow, myForthContentManager);
}
return myForthContentManager;
}
public void slice(@NotNull PsiElement element, boolean dataFlowToThis, @NotNull SliceHandler handler) {
String dialogTitle = getElementDescription((dataFlowToThis ? BACK_TOOLWINDOW_ID : FORTH_TOOLWINDOW_ID) + " ", element, null);
dialogTitle = Pattern.compile("(<style>.*</style>)|<[^<>]*>").matcher(dialogTitle).replaceAll("");
SliceAnalysisParams params = handler.askForParams(element, dataFlowToThis, myStoredSettings, dialogTitle);
if (params == null) return;
SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(), SliceUsage.createRootUsage(element, params));
createToolWindow(dataFlowToThis, rootNode, false, getElementDescription(null, element, null));
}
public void createToolWindow(boolean dataFlowToThis, @NotNull SliceRootNode rootNode, boolean splitByLeafExpressions, @NotNull String displayName) {
final SliceToolwindowSettings sliceToolwindowSettings = SliceToolwindowSettings.getInstance(myProject);
final ContentManager contentManager = getContentManager(dataFlowToThis);
final Content[] myContent = new Content[1];
ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(dataFlowToThis ? BACK_TOOLWINDOW_ID : FORTH_TOOLWINDOW_ID);
final SlicePanel slicePanel = new SlicePanel(myProject, dataFlowToThis, rootNode, splitByLeafExpressions, toolWindow) {
@Override
protected void close() {
super.close();
contentManager.removeContent(myContent[0], true);
}
@Override
public boolean isAutoScroll() {
return sliceToolwindowSettings.isAutoScroll();
}
@Override
public void setAutoScroll(boolean autoScroll) {
sliceToolwindowSettings.setAutoScroll(autoScroll);
}
@Override
public boolean isPreview() {
return sliceToolwindowSettings.isPreview();
}
@Override
public void setPreview(boolean preview) {
sliceToolwindowSettings.setPreview(preview);
}
};
myContent[0] = contentManager.getFactory().createContent(slicePanel, displayName, true);
contentManager.addContent(myContent[0]);
contentManager.setSelectedContent(myContent[0]);
toolWindow.activate(null);
}
public static String getElementDescription(String prefix, PsiElement element, String suffix) {
PsiElement elementToSlice = element;
if (element instanceof PsiReferenceExpression) elementToSlice = ((PsiReferenceExpression)element).resolve();
if (elementToSlice == null) elementToSlice = element;
String desc = ElementDescriptionUtil.getElementDescription(elementToSlice, RefactoringDescriptionLocation.WITHOUT_PARENT);
return "<html><head>" + UIUtil.getCssFontDeclaration(BaseLabel.getLabelFont()) + "</head><body>" +
(prefix == null ? "" : prefix) + StringUtil.first(desc, 100, true)+(suffix == null ? "" : suffix) +
"</body></html>";
}
public void runInterruptibly(@NotNull ProgressIndicator progress,
@NotNull Runnable onCancel,
@NotNull Runnable runnable) throws ProcessCanceledException {
Disposable disposable = addPsiListener(progress);
try {
progress.checkCanceled();
ProgressManager.getInstance().executeProcessUnderProgress(runnable, progress);
}
catch (ProcessCanceledException e) {
progress.cancel();
//reschedule for later
onCancel.run();
throw e;
}
finally {
Disposer.dispose(disposable);
}
}
@Override
public StoredSettingsBean getState() {
return myStoredSettings;
}
@Override
public void loadState(StoredSettingsBean state) {
myStoredSettings.analysisUIOptions.save(state.analysisUIOptions);
}
}