diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java index 7e5bcced180f..cac7c144a292 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java @@ -616,7 +616,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { final int fragmentWidth = metrics.stringWidth(fragment); final Color bgColor = attributes.getBgColor(); - if (isOpaque() && bgColor != null) { + if ((attributes.isOpaque() || isOpaque()) && bgColor != null) { g.setColor(bgColor); g.fillRect(offset, 0, fragmentWidth, getHeight()); } diff --git a/platform/platform-api/src/com/intellij/ui/SimpleTextAttributes.java b/platform/platform-api/src/com/intellij/ui/SimpleTextAttributes.java index 4f6efef3b25e..f84b570d03e8 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleTextAttributes.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleTextAttributes.java @@ -31,7 +31,7 @@ import java.awt.*; @SuppressWarnings({"PointlessBitwiseExpression"}) public final class SimpleTextAttributes { - @MagicConstant(flags = {STYLE_PLAIN, STYLE_BOLD, STYLE_ITALIC, STYLE_STRIKEOUT, STYLE_WAVED, STYLE_UNDERLINE, STYLE_BOLD_DOTTED_LINE, STYLE_SEARCH_MATCH, STYLE_SMALLER}) + @MagicConstant(flags = {STYLE_PLAIN, STYLE_BOLD, STYLE_ITALIC, STYLE_STRIKEOUT, STYLE_WAVED, STYLE_UNDERLINE, STYLE_BOLD_DOTTED_LINE, STYLE_SEARCH_MATCH, STYLE_SMALLER, STYLE_OPAQUE}) public @interface StyleAttributeConstant { } public static final int STYLE_PLAIN = Font.PLAIN; @@ -44,6 +44,7 @@ public final class SimpleTextAttributes { public static final int STYLE_BOLD_DOTTED_LINE = STYLE_UNDERLINE << 1; public static final int STYLE_SEARCH_MATCH = STYLE_BOLD_DOTTED_LINE << 1; public static final int STYLE_SMALLER = STYLE_SEARCH_MATCH << 1; + public static final int STYLE_OPAQUE = STYLE_SMALLER << 1; public static final SimpleTextAttributes REGULAR_ATTRIBUTES = new SimpleTextAttributes(STYLE_PLAIN, null); public static final SimpleTextAttributes REGULAR_BOLD_ATTRIBUTES = new SimpleTextAttributes(STYLE_BOLD, null); @@ -94,7 +95,8 @@ public final class SimpleTextAttributes { STYLE_UNDERLINE | STYLE_BOLD_DOTTED_LINE | STYLE_SEARCH_MATCH | - STYLE_SMALLER) & style) != 0) { + STYLE_SMALLER | + STYLE_OPAQUE) & style) != 0) { throw new IllegalArgumentException("Wrong style: " + style); } @@ -164,6 +166,10 @@ public final class SimpleTextAttributes { return (myStyle & STYLE_SMALLER) != 0; } + public boolean isOpaque() { + return (myStyle & STYLE_OPAQUE) != 0; + } + public static SimpleTextAttributes fromTextAttributes(TextAttributes attributes) { if (attributes == null) return REGULAR_ATTRIBUTES; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XDebuggerTreeActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XDebuggerTreeActionBase.java index 4f530660441d..c4ccbbd20128 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XDebuggerTreeActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XDebuggerTreeActionBase.java @@ -20,8 +20,6 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.xdebugger.frame.XValue; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; -import com.intellij.xdebugger.impl.ui.tree.nodes.WatchMessageNode; -import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,45 +32,29 @@ import javax.swing.tree.TreePath; public abstract class XDebuggerTreeActionBase extends AnAction { @Override public void actionPerformed(final AnActionEvent e) { - XDebuggerTreeNode node = getSelectionPathLastNode(e.getDataContext()); - if (node instanceof XValueNodeImpl) { - XValueNodeImpl valueNode = (XValueNodeImpl)node; - String nodeName = valueNode.getName(); + XValueNodeImpl node = getSelectedNode(e.getDataContext()); + if (node != null) { + String nodeName = node.getName(); if (nodeName != null) { - perform(valueNode, nodeName, e); + perform(node, nodeName, e); } } - else if (node instanceof WatchMessageNode) { - perform((WatchMessageNode)node, e); - } - } - - protected void perform(WatchMessageNode node, AnActionEvent e) { } protected abstract void perform(final XValueNodeImpl node, @NotNull String nodeName, final AnActionEvent e); @Override public void update(final AnActionEvent e) { - XDebuggerTreeNode node = getSelectionPathLastNode(e.getDataContext()); - if (node instanceof XValueNodeImpl) { - e.getPresentation().setEnabled(isEnabled((XValueNodeImpl)node)); - } - else { - e.getPresentation().setEnabled(node instanceof WatchMessageNode && isEnabled((WatchMessageNode)node)); - } + XValueNodeImpl node = getSelectedNode(e.getDataContext()); + e.getPresentation().setEnabled(node != null && isEnabled(node)); } protected boolean isEnabled(final XValueNodeImpl node) { return node.getName() != null; } - protected boolean isEnabled(WatchMessageNode node) { - return false; - } - @Nullable - private static XDebuggerTreeNode getSelectionPathLastNode(DataContext dataContext) { + public static XValueNodeImpl getSelectedNode(final DataContext dataContext) { XDebuggerTree tree = XDebuggerTree.getTree(dataContext); if (tree == null) return null; @@ -80,12 +62,6 @@ public abstract class XDebuggerTreeActionBase extends AnAction { if (path == null) return null; Object node = path.getLastPathComponent(); - return node instanceof XDebuggerTreeNode ? (XDebuggerTreeNode)node : null; - } - - @Nullable - public static XValueNodeImpl getSelectedNode(final DataContext dataContext) { - XDebuggerTreeNode node = getSelectionPathLastNode(dataContext); return node instanceof XValueNodeImpl ? (XValueNodeImpl)node : null; } @@ -94,4 +70,4 @@ public abstract class XDebuggerTreeActionBase extends AnAction { XValueNodeImpl node = getSelectedNode(dataContext); return node != null ? node.getValueContainer() : null; } -} +} \ No newline at end of file diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java index c1a0c6266a3d..e290d97a7c9a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java @@ -15,50 +15,115 @@ */ package com.intellij.xdebugger.impl.ui.tree.actions; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Alarm; +import com.intellij.util.SmartList; import com.intellij.util.concurrency.Semaphore; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.frame.XFullValueEvaluator; +import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; import com.intellij.xdebugger.impl.ui.tree.nodes.WatchMessageNode; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.tree.TreePath; import java.awt.*; +import java.util.List; -/** - * User: ksafonov - */ -public abstract class XFetchValueActionBase extends XDebuggerTreeActionBase { - - protected abstract void handle(final Project project, final String value); +public abstract class XFetchValueActionBase extends AnAction { + @Nullable + private static TreePath[] getSelectedNodes(DataContext dataContext) { + XDebuggerTree tree = XDebuggerTree.getTree(dataContext); + return tree == null ? null : tree.getSelectionPaths(); + } @Override - protected void perform(final XValueNodeImpl node, @NotNull final String nodeName, final AnActionEvent e) { - XFullValueEvaluator fullValueEvaluator = node.getFullValueEvaluator(); - if (fullValueEvaluator == null) { - String value = node.getValue(); - handle(node.getTree().getProject(), value); + public void update(AnActionEvent e) { + TreePath[] paths = getSelectedNodes(e.getDataContext()); + if (paths != null) { + for (TreePath path : paths) { + Object node = path.getLastPathComponent(); + if (node instanceof XValueNodeImpl) { + XValueNodeImpl valueNode = (XValueNodeImpl)node; + if (valueNode.getName() != null && valueNode.getValue() != null) { + e.getPresentation().setEnabled(true); + return; + } + } + else if (node instanceof WatchMessageNode) { + e.getPresentation().setEnabled(true); + return; + } + } + } + e.getPresentation().setEnabled(false); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + TreePath[] paths = getSelectedNodes(e.getDataContext()); + if (paths == null) { return; } - final XDebugSession session = node.getTree().getSession(); - startFetchingValue(fullValueEvaluator, session); + ValueCollector valueCollector = new ValueCollector(); + for (TreePath path : paths) { + Object node = path.getLastPathComponent(); + if (node instanceof XValueNodeImpl) { + XValueNodeImpl valueNode = (XValueNodeImpl)node; + XFullValueEvaluator fullValueEvaluator = valueNode.getFullValueEvaluator(); + if (fullValueEvaluator == null) { + valueCollector.add(StringUtil.notNullize(valueNode.getValue())); + } + else { + startFetchingValue(fullValueEvaluator, new CopyValueEvaluationCallback(valueNode.getTree().getSession(), valueCollector)); + } + } + else if (node instanceof WatchMessageNode) { + valueCollector.add(((WatchMessageNode)node).getExpression()); + } + } + valueCollector.processed = true; + valueCollector.finish(e.getProject()); } - @Override - protected void perform(WatchMessageNode node, AnActionEvent e) { - handle(e.getProject(), node.getExpression()); + private final class ValueCollector { + private final List values = new SmartList(); + private volatile boolean processed; + + public void add(@NotNull String value) { + values.add(value); + } + + public void finish(Project project) { + if (processed && !values.contains(null) && !project.isDisposed()) { + handle(project, StringUtil.join(values, "\n")); + } + } + + public int acquire() { + int index = values.size(); + values.add(null); + return index; + } + + public void evaluationComplete(int index, @NotNull String value, Project project) { + values.set(index, value); + finish(project); + } } - private void startFetchingValue(@NotNull XFullValueEvaluator fullValueEvaluator, - final @NotNull XDebugSession session) { - final CopyValueEvaluationCallback callback = new CopyValueEvaluationCallback(session); + protected abstract void handle(final Project project, final String value); + + private static void startFetchingValue(XFullValueEvaluator fullValueEvaluator, final CopyValueEvaluationCallback callback) { fullValueEvaluator.startEvaluation(callback); new Alarm().addRequest(new Runnable() { @Override @@ -68,32 +133,27 @@ public abstract class XFetchValueActionBase extends XDebuggerTreeActionBase { }, 500); } - @Override - protected boolean isEnabled(final XValueNodeImpl node) { - return super.isEnabled(node) && node.getValue() != null; - } + private static final class CopyValueEvaluationCallback implements XFullValueEvaluator.XFullValueEvaluationCallback { + private final XDebugSession session; - @Override - protected boolean isEnabled(WatchMessageNode node) { - return true; - } + private final int valueIndex; + private final ValueCollector valueCollector; - private class CopyValueEvaluationCallback implements XFullValueEvaluator.XFullValueEvaluationCallback { - private final XDebugSession mySession; - private volatile boolean myEvaluated; - private volatile boolean myCanceled; - private Semaphore mySemaphore; + private volatile boolean evaluated; + private volatile boolean canceled; + private final Semaphore semaphore; - public CopyValueEvaluationCallback(XDebugSession session) { - mySession = session; - mySemaphore = new Semaphore(); - mySemaphore.down(); + public CopyValueEvaluationCallback(XDebugSession session, ValueCollector valueCollector) { + this.session = session; + this.valueCollector = valueCollector; + valueIndex = valueCollector.acquire(); + semaphore = new Semaphore(); + semaphore.down(); } @Override public void evaluated(@NotNull String fullValue) { - handle(mySession.getProject(), fullValue); - evaluationComplete(); + evaluationComplete(fullValue); } @Override @@ -103,32 +163,41 @@ public abstract class XFetchValueActionBase extends XDebuggerTreeActionBase { @Override public void errorOccurred(@NotNull String errorMessage) { - mySession.reportError(XDebuggerBundle.message("load.value.task.error", errorMessage)); - evaluationComplete(); + try { + session.reportError(XDebuggerBundle.message("load.value.task.error", errorMessage)); + } + finally { + evaluationComplete(errorMessage); + } } - private void evaluationComplete() { - myEvaluated = true; - mySemaphore.up(); + private void evaluationComplete(String value) { + try { + evaluated = true; + semaphore.up(); + } + finally { + valueCollector.evaluationComplete(valueIndex, value, session.getProject()); + } } @Override public boolean isObsolete() { - return myCanceled; + return canceled; } public void showProgress() { - if (myEvaluated || mySession.isStopped()) return; + if (evaluated || session.isStopped()) return; - new Task.Backgroundable(mySession.getProject(), XDebuggerBundle.message("load.value.task.text")) { + new Task.Backgroundable(session.getProject(), XDebuggerBundle.message("load.value.task.text")) { @Override public void run(@NotNull ProgressIndicator indicator) { indicator.setIndeterminate(true); int i = 0; - while (!myCanceled && !myEvaluated) { + while (!canceled && !evaluated) { indicator.checkCanceled(); indicator.setFraction(((i++) % 100) * 0.01); - mySemaphore.waitFor(300); + semaphore.waitFor(300); } } @@ -139,7 +208,7 @@ public abstract class XFetchValueActionBase extends XDebuggerTreeActionBase { @Override public void onCancel() { - myCanceled = true; + canceled = true; } }.queue(); }