IDEA-153874 apply changes from AndroidStudio

This commit is contained in:
Anton Tarasov
2016-03-30 13:08:45 +03:00
parent 4bd022c0af
commit 40a35baa42
30 changed files with 574 additions and 33 deletions
@@ -185,7 +185,7 @@ public class AutoPopupController implements Disposable {
if (editor.isDisposed() || !editor.getComponent().isShowing()) return;
int lbraceOffset = editor.getCaretModel().getOffset() - 1;
try {
ShowParameterInfoHandler.invoke(myProject, editor, file1, lbraceOffset, highlightedMethod);
ShowParameterInfoHandler.invoke(myProject, editor, file1, lbraceOffset, highlightedMethod, false);
}
catch (IndexNotReadyException ignored) { //anything can happen on alarm
}
@@ -40,6 +40,10 @@ public class DaemonTooltipUtil {
}
public static void showInfoTooltip(@NotNull final HighlightInfo info, @NotNull Editor editor, final int defaultOffset, final int currentWidth) {
showInfoTooltip(info, editor, defaultOffset, currentWidth, false);
}
public static void showInfoTooltip(@NotNull final HighlightInfo info, @NotNull Editor editor, final int defaultOffset, final int currentWidth, final boolean requestFocus) {
if (info.getToolTip() == null) return;
Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
@@ -56,7 +60,11 @@ public class DaemonTooltipUtil {
editor.getComponent().getRootPane().getLayeredPane()
);
TooltipController.getInstance().showTooltip(editor, p, info.getToolTip(), currentWidth, false, DAEMON_INFO_GROUP, new HintHint(editor, bestPoint).setAwtTooltip(true).setHighlighterType(true).setCalloutShift(
editor.getLineHeight() / 2 - 1));
HintHint hintHint = new HintHint(editor, bestPoint)
.setAwtTooltip(true)
.setHighlighterType(true)
.setRequestFocus(requestFocus)
.setCalloutShift(editor.getLineHeight() / 2 - 1);
TooltipController.getInstance().showTooltip(editor, p, info.getToolTip(), currentWidth, false, DAEMON_INFO_GROUP, hintHint);
}
}
@@ -25,9 +25,11 @@ import org.jetbrains.annotations.NotNull;
public class ShowErrorDescriptionHandler implements CodeInsightActionHandler {
private final int myWidth;
private final boolean myRequestFocus;
public ShowErrorDescriptionHandler(final int width) {
public ShowErrorDescriptionHandler(final int width, final boolean requestFocus) {
myWidth = width;
myRequestFocus = requestFocus;
}
@Override
@@ -36,7 +38,7 @@ public class ShowErrorDescriptionHandler implements CodeInsightActionHandler {
DaemonCodeAnalyzer codeAnalyzer = DaemonCodeAnalyzer.getInstance(project);
HighlightInfo info = ((DaemonCodeAnalyzerImpl)codeAnalyzer).findHighlightByOffset(editor.getDocument(), offset, false);
if (info != null) {
DaemonTooltipUtil.showInfoTooltip(info, editor, editor.getCaretModel().getOffset(), myWidth);
DaemonTooltipUtil.showInfoTooltip(info, editor, editor.getCaretModel().getOffset(), myWidth, myRequestFocus);
}
}
@@ -30,12 +30,16 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiFile;
import com.intellij.util.ui.accessibility.ScreenReader;
import org.jetbrains.annotations.NotNull;
import java.awt.event.KeyEvent;
public class ShowErrorDescriptionAction extends BaseCodeInsightAction implements DumbAware {
private static int width;
private static boolean shouldShowDescription = false;
private static boolean descriptionShown = true;
private boolean myRequestFocus = false;
public ShowErrorDescriptionAction() {
setEnabledInModalContext(true);
@@ -44,7 +48,7 @@ public class ShowErrorDescriptionAction extends BaseCodeInsightAction implements
@NotNull
@Override
protected CodeInsightActionHandler getHandler() {
return new ShowErrorDescriptionHandler(shouldShowDescription ? width : 0);
return new ShowErrorDescriptionHandler(shouldShowDescription ? width : 0, myRequestFocus);
}
@Override
@@ -62,6 +66,8 @@ public class ShowErrorDescriptionAction extends BaseCodeInsightAction implements
@Override
public void beforeActionPerformedUpdate(@NotNull final AnActionEvent e) {
super.beforeActionPerformedUpdate(e);
// The tooltip gets the focus if using a screen reader and invocation through a keyboard shortcut.
myRequestFocus = ScreenReader.isActive() && (e.getInputEvent() instanceof KeyEvent);
changeState();
}
@@ -29,6 +29,7 @@ import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SideBorder;
import com.intellij.util.Function;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.AccessibleContextUtil;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -73,6 +74,7 @@ public class ParameterInfoComponent extends JPanel {
return -1;
}
};
private boolean myRequestFocus;
@TestOnly
public static ParameterInfoUIContextEx createContext(Object[] objects, Editor editor, @NotNull ParameterInfoHandler handler, int currentParameterIndex) {
@@ -112,6 +114,9 @@ public class ParameterInfoComponent extends JPanel {
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0));
}
if (myRequestFocus) {
AccessibleContextUtil.setName(this, "Parameter Info. Press TAB to navigate through each element. Press ESC to close.");
}
final JScrollPane pane = ScrollPaneFactory.createScrollPane(panel);
pane.setBorder(null);
@@ -137,6 +142,14 @@ public class ParameterInfoComponent extends JPanel {
return myHighlighted;
}
public void setRequestFocus(boolean requestFocus) {
myRequestFocus = requestFocus;
}
public boolean isRequestFocus() {
return myRequestFocus;
}
class MyParameterContext implements ParameterInfoUIContextEx {
private int i;
private Function<String, String> myEscapeFunction;
@@ -370,6 +383,8 @@ public class ParameterInfoComponent extends JPanel {
myLabel.setOpaque(true);
myLabel.setFont(NORMAL_FONT);
if (myRequestFocus)
myLabel.setFocusable(true);
add(myLabel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0));
@@ -468,4 +483,4 @@ public class ParameterInfoComponent extends JPanel {
isDisabledBeforeHighlight = true;
}
}
}
}
@@ -48,6 +48,7 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
private final int myParameterListStart;
private PsiElement myHighlightedElement;
private Object[] myItems;
private boolean myRequestFocus;
public ShowParameterInfoContext(final Editor editor, final Project project,
final PsiFile file, int offset, int parameterListStart) {
@@ -108,7 +109,7 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
public void showHint(PsiElement element, int offset, ParameterInfoHandler handler) {
final Object[] itemsToShow = getItemsToShow();
if (itemsToShow == null || itemsToShow.length == 0) return;
showMethodInfo(getProject(), getEditor(), element, getHighlightedElement(), itemsToShow, offset, handler);
showMethodInfo(getProject(), getEditor(), element, getHighlightedElement(), itemsToShow, offset, handler, myRequestFocus);
}
private static void showParameterHint(final PsiElement element,
@@ -117,12 +118,14 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
final Project project,
@Nullable PsiElement highlighted,
final int elementStart,
final ParameterInfoHandler handler) {
final ParameterInfoHandler handler,
final boolean requestFocus) {
if (ParameterInfoController.isAlreadyShown(editor, elementStart)) return;
if (editor.isDisposed() || !editor.getComponent().isVisible()) return;
final ParameterInfoComponent component = new ParameterInfoComponent(descriptors, editor,handler);
component.setParameterOwner(element);
component.setRequestFocus(requestFocus);
if (highlighted != null) {
component.setHighlightedParameter(highlighted);
}
@@ -143,6 +146,7 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
HintHint hintHint = HintManagerImpl.createHintHint(editor, pos.getFirst(), hint, pos.getSecond());
hintHint.setExplicitClose(true);
hintHint.setRequestFocus(requestFocus);
Editor editorToShow = editor instanceof EditorWindow ? ((EditorWindow)editor).getDelegate() : editor;
// is case of injection we need to calculate position for EditorWindow
@@ -157,9 +161,10 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
PsiElement highlighted,
Object[] candidates,
int offset,
ParameterInfoHandler handler
ParameterInfoHandler handler,
boolean requestFocus
) {
showParameterHint(list, editor, candidates, project, candidates.length > 1 ? highlighted : null, offset, handler);
showParameterHint(list, editor, candidates, project, candidates.length > 1 ? highlighted : null, offset, handler, requestFocus);
}
/**
@@ -222,6 +227,14 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
HintManager.ABOVE);
}
public void setRequestFocus(boolean requestFocus) {
myRequestFocus = requestFocus;
}
public boolean isRequestFocus() {
return myRequestFocus;
}
static class MyBestLocationPointProvider implements ShowParameterInfoHandler.BestLocationPointProvider {
private final Editor myEditor;
private int previousOffset = -1;
@@ -40,9 +40,19 @@ import java.awt.*;
import java.util.Set;
public class ShowParameterInfoHandler implements CodeInsightActionHandler {
private boolean myRequestFocus;
public ShowParameterInfoHandler() {
this(false);
}
public ShowParameterInfoHandler(boolean requestFocus) {
myRequestFocus = requestFocus;
}
@Override
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
invoke(project, editor, file, -1, null);
invoke(project, editor, file, -1, null, myRequestFocus);
}
@Override
@@ -57,7 +67,7 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
return element;
}
public static void invoke(final Project project, final Editor editor, PsiFile file, int lbraceOffset, PsiElement highlightedElement) {
public static void invoke(final Project project, final Editor editor, PsiFile file, int lbraceOffset, PsiElement highlightedElement, boolean requestFocus) {
ApplicationManager.getApplication().assertIsDispatchThread();
PsiDocumentManager.getInstance(project).commitAllDocuments();
@@ -74,6 +84,7 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
);
context.setHighlightedElement(highlightedElement);
context.setRequestFocus(requestFocus);
final Language language = psiElement.getLanguage();
ParameterInfoHandler[] handlers = getHandlers(project, language, file.getViewProvider().getBaseLanguage());
@@ -20,22 +20,35 @@ import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.actions.BaseCodeInsightAction;
import com.intellij.codeInsight.hint.ShowParameterInfoHandler;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.ui.accessibility.ScreenReader;
import org.jetbrains.annotations.NotNull;
import java.awt.event.KeyEvent;
public class ShowParameterInfoAction extends BaseCodeInsightAction implements DumbAware {
private boolean myRequestFocus = false;
public ShowParameterInfoAction() {
setEnabledInModalContext(true);
}
@Override
public void beforeActionPerformedUpdate(@NotNull AnActionEvent e) {
super.beforeActionPerformedUpdate(e);
// The tooltip gets the focus if using a screen reader and invocation through a keyboard shortcut.
myRequestFocus = ScreenReader.isActive() && (e.getInputEvent() instanceof KeyEvent);
}
@NotNull
@Override
protected CodeInsightActionHandler getHandler() {
return new ShowParameterInfoHandler();
return new ShowParameterInfoHandler(myRequestFocus);
}
@Override
@@ -48,4 +61,4 @@ public class ShowParameterInfoAction extends BaseCodeInsightAction implements Du
protected boolean isValidForLookup() {
return true;
}
}
}
@@ -36,6 +36,7 @@ import com.intellij.ui.GuiUtils;
import com.intellij.ui.UIBundle;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.ScreenReader;
import com.intellij.util.ui.update.LazyUiDisposable;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -71,11 +72,14 @@ public class ComponentWithBrowseButton<Comp extends JComponent> extends JPanel i
add(wrapWithoutResize(myBrowseButton), BorderLayout.EAST);
myBrowseButton.setToolTipText(UIBundle.message("component.with.browse.button.browse.button.tooltip.text"));
// FixedSizeButton isn't focusable but it should be selectable via keyboard.
if (ApplicationManager.getApplication() != null) { // avoid crash at design time
new MyDoClickAction(myBrowseButton).registerShortcut(myComponent);
}
if (ScreenReader.isActive()) {
myBrowseButton.setFocusable(true);
myBrowseButton.getAccessibleContext().setAccessibleName("Browse");
}
}
private static JPanel wrapWithoutResize(JComponent component) {
@@ -95,6 +95,9 @@ public interface BalloonBuilder {
@NotNull
BalloonBuilder setBlockClicksThroughBalloon(boolean block);
@NotNull
BalloonBuilder setRequestFocus(boolean requestFocus);
/**
* Links target balloon life cycle to the given object. I.e. current balloon will be auto-hide and collected as soon
* as given anchor is disposed.
@@ -109,4 +112,4 @@ public interface BalloonBuilder {
@NotNull
Balloon createBalloon();
}
}
@@ -17,23 +17,27 @@ package com.intellij.ui;
import com.intellij.openapi.ui.popup.IconButton;
import com.intellij.openapi.util.Pass;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.ui.BaseButtonBehavior;
import com.intellij.util.ui.CenteredIcon;
import com.intellij.util.ui.TimedDeadzone;
import com.intellij.util.ui.UIUtil;
import javax.accessibility.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class InplaceButton extends JComponent implements ActiveComponent {
public class InplaceButton extends JComponent implements ActiveComponent, Accessible {
private boolean myPainting = true;
private boolean myActive = true;
private BaseButtonBehavior myBehavior;
private ActionListener myListener;
private CenteredIcon myRegular;
private CenteredIcon myHovered;
@@ -62,9 +66,11 @@ public class InplaceButton extends JComponent implements ActiveComponent {
}
public InplaceButton(IconButton source, final ActionListener listener, final Pass<MouseEvent> me, TimedDeadzone.Length mouseDeadzone) {
myListener = listener;
myBehavior = new BaseButtonBehavior(this, mouseDeadzone) {
@Override
protected void execute(final MouseEvent e) {
listener.actionPerformed(new ActionEvent(e, ActionEvent.ACTION_PERFORMED, "execute", e.getModifiers()));
doClick(e);
}
@Override
@@ -91,12 +97,22 @@ public class InplaceButton extends JComponent implements ActiveComponent {
protected void doRepaintComponent(Component c) {
c.repaint();
}
public void doClick() {
RelativePoint point = new RelativePoint(this, new Point(this.getWidth() / 2, this.getHeight() / 2));
doClick(point.toMouseEvent());
}
public void doClick(final MouseEvent e) {
if (myListener != null) {
myListener.actionPerformed(new ActionEvent(e, ActionEvent.ACTION_PERFORMED, "execute", e.getModifiers()));
}
}
public void setMouseDeadzone(final TimedDeadzone.Length deadZone) {
myBehavior.setMouseDeadzone(deadZone);
}
public void setIcons(IconButton source) {
setIcons(source.getRegular(), source.getInactive(), source.getHovered());
}
@@ -132,6 +148,7 @@ public class InplaceButton extends JComponent implements ActiveComponent {
repaint();
}
@Override
public void setActive(final boolean active) {
myActive = active;
repaint();
@@ -141,10 +158,12 @@ public class InplaceButton extends JComponent implements ActiveComponent {
setIcons(icon, icon, icon);
}
@Override
public JComponent getComponent() {
return this;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
@@ -188,8 +207,120 @@ public class InplaceButton extends JComponent implements ActiveComponent {
}
public boolean isActive() {
return myActive;
}
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleInplaceButton();
}
return accessibleContext;
}
/**
* The Accessible implementation of InplaceButton is a subset of AccessibleAbstractButton.
*/
protected class AccessibleInplaceButton extends AccessibleJComponent implements AccessibleAction, AccessibleExtendedComponent {
@Override
public String getAccessibleName() {
String name = accessibleName;
if (name == null) {
name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
}
if (name == null) {
name = InplaceButton.this.getToolTipText();
}
if (name == null) {
name = super.getAccessibleName();
}
return name;
}
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.PUSH_BUTTON;
}
@Override
public int getAccessibleActionCount() {
return 1;
}
@Override
public String getAccessibleActionDescription(int i) {
if (i == 0) {
return "Click";
} else {
return null;
}
}
@Override
public boolean doAccessibleAction(int i) {
if (i == 0) {
doClick();
return true;
} else {
return false;
}
}
@Override
public AccessibleAction getAccessibleAction() {
return this;
}
@Override
public AccessibleIcon[] getAccessibleIcon() {
Icon[] icons = {myRegular, myInactive, myHovered};
ArrayList<AccessibleIcon> accessibleIconList = new ArrayList<AccessibleIcon>();
for (Icon icon : icons) {
if (icon instanceof Accessible) {
AccessibleContext ac = ((Accessible)icon).getAccessibleContext();
if (ac != null && ac instanceof AccessibleIcon) {
accessibleIconList.add((AccessibleIcon)ac);
}
}
}
if (accessibleIconList.size() == 0) {
return null;
}
return accessibleIconList.toArray(new AccessibleIcon[accessibleIconList.size()]);
}
@Override
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet states = super.getAccessibleStateSet();
if (isFocusOwner()) {
states.add(AccessibleState.FOCUSED);
}
return states;
}
// ----- AccessibleExtendedComponent
@SuppressWarnings("unused")
AccessibleExtendedComponent getAccessibleExtendedComponent() {
return this;
}
@Override
public String getToolTipText() {
return InplaceButton.this.getToolTipText();
}
@Override
public String getTitledBorderText() {
return null;
}
@Override
public AccessibleKeyBinding getAccessibleKeyBinding() {
return null;
}
}
}
@@ -29,6 +29,7 @@ import com.intellij.ui.LightweightHint;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.util.ui.Html;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.ScreenReader;
import com.intellij.util.ui.update.ComparableObject;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NonNls;
@@ -38,6 +39,7 @@ import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
@@ -101,6 +103,10 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
scrollPane.setViewportBorder(null);
if (hintHint.isRequestFocus()) {
pane.setFocusable(true);
}
final Ref<AnAction> actionRef = new Ref<AnAction>();
final LightweightHint hint = new LightweightHint(scrollPane) {
@Override
@@ -123,6 +129,8 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
@Override
public void actionPerformed(final AnActionEvent e) {
// The tooltip gets the focus if using a screen reader and invocation through a keyboard shortcut.
hintHint.setRequestFocus(ScreenReader.isActive() && (e.getInputEvent() instanceof KeyEvent));
expand(hint, editor, p, pane, alignToRight, group, hintHint);
}
});
@@ -36,6 +36,7 @@ public class IdeTooltip extends ComparableObject.Impl {
private boolean myToCenter = false;
private boolean myToCenterIfSmall = true;
private boolean myHighlighter;
private boolean myRequestFocus;
private Color myTextBackground;
private Color myTextForeground;
@@ -263,6 +264,15 @@ public class IdeTooltip extends ComparableObject.Impl {
return myUi != null && myUi.isInside(target);
}
public boolean isRequestFocus() {
return myRequestFocus;
}
public IdeTooltip setRequestFocus(boolean requestFocus) {
myRequestFocus = requestFocus;
return this;
}
public interface Ui {
boolean isInside(RelativePoint target);
@@ -311,6 +311,7 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener
.setPositionChangeYShift(tooltip.getPositionChangeY())
.setHideOnKeyOutside(!tooltip.isExplicitClose())
.setHideOnAction(!tooltip.isExplicitClose())
.setRequestFocus(tooltip.isRequestFocus())
.setLayer(tooltip.getLayer());
tooltip.getTipComponent().setForeground(fg);
tooltip.getTipComponent().setBorder(new EmptyBorder(1, 3, 2, 3));
@@ -55,10 +55,12 @@ import com.intellij.ui.mac.MacMainFrameDecorator;
import com.intellij.util.Alarm;
import com.intellij.util.io.storage.HeavyProcessLatch;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.AccessibleContextAccessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.PowerSupplyKit;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
@@ -72,7 +74,7 @@ import java.io.File;
* @author Anton Katilin
* @author Vladimir Kondratyev
*/
public class IdeFrameImpl extends JFrame implements IdeFrameEx, DataProvider {
public class IdeFrameImpl extends JFrame implements IdeFrameEx, AccessibleContextAccessor, DataProvider {
public static final Key<Boolean> SHOULD_OPEN_IN_FULL_SCREEN = Key.create("should.open.in.full.screen");
private static final String FULL_SCREEN = "FullScreen";
@@ -354,6 +356,11 @@ public class IdeFrameImpl extends JFrame implements IdeFrameEx, DataProvider {
((IdeRootPane)getRootPane()).updateNorthComponents();
}
@Override
public AccessibleContext getCurrentAccessibleContext() {
return accessibleContext;
}
private static final class Builder {
public StringBuilder sb = new StringBuilder();
@@ -601,4 +608,29 @@ public class IdeFrameImpl extends JFrame implements IdeFrameEx, DataProvider {
return ActionCallback.DONE;
}
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleIdeFrameImpl();
}
return accessibleContext;
}
protected class AccessibleIdeFrameImpl extends AccessibleJFrame {
@Override
public String getAccessibleName() {
final StringBuilder builder = new StringBuilder();
if (myProject != null) {
builder.append(myProject.getName());
builder.append(" - ");
}
final String applicationName = ((ApplicationInfoEx)ApplicationInfo.getInstance()).getFullApplicationName();
builder.append(applicationName);
return builder.toString();
}
}
}
@@ -42,6 +42,9 @@ import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.swing.*;
import javax.swing.event.HyperlinkListener;
import java.awt.*;
@@ -53,7 +56,7 @@ import java.util.List;
/**
* User: spLeaner
*/
public class IdeStatusBarImpl extends JComponent implements StatusBarEx {
public class IdeStatusBarImpl extends JComponent implements Accessible, StatusBarEx {
private static final int MIN_ICON_HEIGHT = 18 + 1 + 1;
private final InfoAndProgressPanel myInfoAndProgressPanel;
private IdeFrame myFrame;
@@ -883,4 +886,19 @@ public class IdeStatusBarImpl extends JComponent implements StatusBarEx {
public IdeFrame getFrame() {
return myFrame;
}
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleIdeStatusBarImpl();
}
return accessibleContext;
}
protected class AccessibleIdeStatusBarImpl extends AccessibleJComponent {
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.PANEL;
}
}
}
@@ -39,6 +39,8 @@ import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
@@ -243,4 +245,18 @@ class StatusPanel extends JPanel {
return myTextPanel.getText();
}
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleStatusPanel();
}
return accessibleContext;
}
protected class AccessibleStatusPanel extends AccessibleJPanel {
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.STATUS_BAR;
}
}
}
@@ -24,10 +24,13 @@ import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.swing.*;
import java.awt.*;
public class TextPanel extends JComponent {
public class TextPanel extends JComponent implements Accessible {
@Nullable private String myText;
@Nullable private Color myCustomColor;
@@ -135,7 +138,20 @@ public class TextPanel extends JComponent {
return;
}
String oldAccessibleName = null;
if (accessibleContext != null) {
oldAccessibleName = accessibleContext.getAccessibleName();
}
myText = text;
if ((accessibleContext != null) && !StringUtil.equals(accessibleContext.getAccessibleName(), oldAccessibleName)) {
accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
oldAccessibleName,
accessibleContext.getAccessibleName());
}
setPreferredSize(getPanelDimensionFromFontMetrics(myText));
revalidate();
repaint();
@@ -227,4 +243,24 @@ public class TextPanel extends JComponent {
return new Dimension(size.width + 3, size.height);
}
}
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleTextPanel();
}
return accessibleContext;
}
protected class AccessibleTextPanel extends AccessibleJComponent {
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.LABEL;
}
@Override
public String getAccessibleName() {
return myText;
}
}
}
@@ -53,10 +53,12 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.MouseEventAdapter;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.AccessibleContextAccessor;
import com.intellij.util.ui.accessibility.AccessibleContextUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
@@ -73,7 +75,7 @@ import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public class FlatWelcomeFrame extends JFrame implements IdeFrame {
public class FlatWelcomeFrame extends JFrame implements IdeFrame, AccessibleContextAccessor {
private static final String ACTION_GROUP_KEY = "ACTION_GROUP_KEY";
private static final String WELCOME_TITLE = "Welcome to " + ApplicationNamesInfo.getInstance().getFullProductName();
private final BalloonLayout myBalloonLayout;
@@ -176,6 +178,11 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame {
return new JBColor(Gray.xEC, new Color(72, 75, 78));
}
@Override
public AccessibleContext getCurrentAccessibleContext() {
return accessibleContext;
}
private class FlatWelcomeScreen extends JPanel implements WelcomeScreen {
private JBSlidingPanel mySlidingPanel = new JBSlidingPanel();
@@ -43,15 +43,17 @@ import com.intellij.ui.AppUIUtil;
import com.intellij.ui.BalloonLayout;
import com.intellij.ui.BalloonLayoutImpl;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.AccessibleContextAccessor;
import org.jetbrains.annotations.Nullable;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
public class WelcomeFrame extends JFrame implements IdeFrame {
public class WelcomeFrame extends JFrame implements IdeFrame, AccessibleContextAccessor {
public static final ExtensionPointName<WelcomeFrameProvider> EP = ExtensionPointName.create("com.intellij.welcomeFrameProvider");
static final String DIMENSION_KEY = "WELCOME_SCREEN";
private static IdeFrame ourInstance;
@@ -234,4 +236,9 @@ public class WelcomeFrame extends JFrame implements IdeFrame {
public JComponent getComponent() {
return getRootPane();
}
@Override
public AccessibleContext getCurrentAccessibleContext() {
return accessibleContext;
}
}
@@ -268,6 +268,8 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
private boolean myHideOnMouse;
private final boolean myHideOnKey;
private final boolean myHideOnAction;
private final boolean myRequestFocus;
private Component myOriginalFocusOwner;
private final boolean myEnableButtons;
public BalloonImpl(@NotNull JComponent content,
@@ -294,7 +296,8 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
boolean shadow,
boolean smallVariant,
boolean blockClicks,
Layer layer) {
Layer layer,
boolean requestFocus) {
myBorderColor = borderColor;
myBorderInsets = borderInsets != null ? borderInsets : new Insets(3, 3, 3, 3);
myFillColor = fillColor;
@@ -315,6 +318,7 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
myTitle = title;
myLayer = layer != null ? layer : Layer.normal;
myBlockClicks = blockClicks;
myRequestFocus = requestFocus;
MnemonicHelper.init(content);
if (!myDialogMode) {
@@ -468,6 +472,22 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
}
});
}
if (myRequestFocus) {
myFocusManager.doWhenFocusSettlesDown(new ExpirableRunnable() {
@Override
public boolean isExpired() {
return isDisposed();
}
@Override
public void run() {
myOriginalFocusOwner = myFocusManager.getFocusOwner();
// Set the focus to "myContent"
myFocusManager.requestFocus(getContentToFocus(), true);
}
});
}
myLayeredPane.addComponentListener(myComponentListener);
@@ -588,6 +608,32 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
}
}
/**
* Figure out the component to focus inside the {@link myContent} field.
*/
@NotNull
private Component getContentToFocus() {
Component focusComponent = myContent;
while (true) {
// Setting focus to a JScrollPane is not very useful. Better setting focus to the
// contained view. This is useful for Tooltip popups, for example.
if (focusComponent instanceof JScrollPane) {
JViewport viewport = ((JScrollPane)focusComponent).getViewport();
if (viewport == null)
break;
Component child = viewport.getView();
if (child == null)
break;
focusComponent = child;
continue;
}
// Done if we can't find anything to dive into
break;
}
return focusComponent;
}
private Rectangle getRecForPosition(AbstractPosition position, boolean adjust) {
Dimension size = getContentSizeFor(position);
Rectangle rec = new Rectangle(new Point(0, 0), size);
@@ -888,6 +934,11 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
@Override
public void run() {
myFadedOut = true;
if (myRequestFocus) {
if (myOriginalFocusOwner != null) {
myFocusManager.requestFocus(myOriginalFocusOwner, false);
}
}
for (JBPopupListener each : myListeners) {
each.onClosed(new LightweightWindowEvent(BalloonImpl.this, ok));
@@ -50,6 +50,7 @@ public class HintHint {
private int myPositionChangeY;
private boolean myShowImmediately = false;
private boolean myAnimationEnabled;
private boolean myRequestFocus;
public HintHint() {
}
@@ -282,4 +283,13 @@ public class HintHint {
myAnimationEnabled = enabled;
return this;
}
public boolean isRequestFocus() {
return myRequestFocus;
}
public HintHint setRequestFocus(boolean requestFocus) {
myRequestFocus = requestFocus;
return this;
}
}
@@ -183,6 +183,7 @@ public class LightweightHint extends UserDataHolderBase implements Hint {
.setCalloutShift(hintHint.getCalloutShift())
.setPositionChangeShift(hintHint.getPositionChangeX(), hintHint.getPositionChangeY())
.setExplicitClose(hintHint.isExplicitClose())
.setRequestFocus(hintHint.isRequestFocus())
.setHint(true);
myComponent.validate();
myCurrentIdeTooltip = IdeTooltipManager.getInstance().show(tooltip, hintHint.isShowImmediately(), hintHint.isAnimationEnabled());
@@ -19,10 +19,14 @@ import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SystemProperties;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.WideSelectionTreeUI;
import org.jetbrains.annotations.NonNls;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.swing.*;
import javax.swing.plaf.TreeUI;
import javax.swing.tree.DefaultMutableTreeNode;
@@ -34,7 +38,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
public abstract class MultilineTreeCellRenderer extends JComponent implements TreeCellRenderer {
public abstract class MultilineTreeCellRenderer extends JComponent implements Accessible, TreeCellRenderer {
private boolean myWrapsCalculated = false;
private boolean myTooSmall = false;
@@ -473,5 +477,42 @@ public abstract class MultilineTreeCellRenderer extends JComponent implements Tr
// return myDelegatee.getScrollableTracksViewportHeight();
// }
// }
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleMultilineTreeCellRenderer();
}
return accessibleContext;
}
protected class AccessibleMultilineTreeCellRenderer extends AccessibleJComponent {
@Override
public String getAccessibleName() {
String name = accessibleName;
if (name == null) {
name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
}
if (name == null) {
StringBuilder sb = new StringBuilder();
for (String aLine : myLines) {
sb.append(aLine);
sb.append(SystemProperties.getLineSeparator());
}
if (sb.length() > 0) name = sb.toString();
}
if (name == null) {
name = super.getAccessibleName();
}
return name;
}
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.LABEL;
}
}
}
@@ -68,6 +68,7 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
private Balloon.Layer myLayer;
private boolean myBlockClicks = false;
private boolean myRequestFocus = false;
public BalloonPopupBuilderImpl(@Nullable Map<Disposable, List<Balloon>> storage, @NotNull final JComponent content) {
myStorage = storage;
@@ -144,6 +145,13 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
return this;
}
@NotNull
@Override
public BalloonBuilder setRequestFocus(boolean requestFocus) {
myRequestFocus = requestFocus;
return this;
}
@NotNull
@Override
public BalloonBuilder setAnimationCycle(int time) {
@@ -250,7 +258,7 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
myContent, myBorder, myBorderInsets, myFill, myHideOnMouseOutside, myHideOnKeyOutside, myHideOnAction, myShowCallout, myCloseButtonEnabled,
myFadeoutTime, myHideOnFrameResize, myHideOnLinkClick, myClickHandler, myCloseOnClick, myAnimationCycle, myCalloutShift,
myPositionChangeXShift, myPositionChangeYShift, myDialogMode, myTitle, myContentInsets, myShadow, mySmallVariant, myBlockClicks,
myLayer);
myLayer, myRequestFocus);
if (myStorage != null && myAnchor != null) {
List<Balloon> balloons = myStorage.get(myAnchor);
@@ -134,7 +134,7 @@ public interface PopupComponent {
@Override
public void windowClosed(WindowEvent e) {
super.windowClosed(e);
A11YFix.invokeFocusGained(myDialog);
//A11YFix.invokeFocusGained(myDialog);
}
});
}
@@ -60,7 +60,7 @@ public class BalloonTest {
balloon.set(new BalloonImpl(
new JLabel("Content"), Color.black, null , MessageType.ERROR.getPopupBackground(), true, true, true, true, true, 0, true, false, null,
false, 500, 25, 0, 0, false, "This is the title", new Insets(2, 2, 2, 2), true, false, false, Balloon.Layer.normal));
false, 500, 25, 0, 0, false, "This is the title", new Insets(2, 2, 2, 2), true, false, false, Balloon.Layer.normal, false));
balloon.get().setShowPointer(true);
if (e.isShiftDown()) {
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* 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.util.ui.accessibility;
import javax.accessibility.AccessibleContext;
/**
* Interface allowing direct access to the {@link AccessibleContext} instance
* of a component.
*/
public interface AccessibleContextAccessor {
/**
* Same as {@link javax.accessibility.Accessible#getAccessibleContext}, except that the returned
* {@link AccessibleContext} is null if it has not been created yet.
*/
AccessibleContext getCurrentAccessibleContext();
}
@@ -22,6 +22,10 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class AccessibleContextUtil {
public static void setName(@NotNull JComponent component, @NotNull String name) {
component.getAccessibleContext().setAccessibleName(name);
}
public static void setName(@NotNull JComponent component, @NotNull JComponent source) {
String name = source.getAccessibleContext().getAccessibleName();
if (name != null) {
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* 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.util.ui.accessibility;
import com.intellij.util.SystemProperties;
import javax.accessibility.AccessibleContext;
import java.awt.*;
/**
* Expose system-wide screen reader status for accessibility features.
*/
public class ScreenReader {
public static String SYSTEM_PROPERTY_KEY = "screenreader";
/**
* Components that need to customize their behavior in the presence of a external screen reader
* application should call this method to determine the presence of such screen reader.
*
* For example, this can be used to determine if components should to be focusable via keyboard
* as opposed to accessible only via the mouse pointer.
*
* @return <code>true</code> if a screen reader is currently active, or has been active
* since the start of the application.
*/
public static boolean isActive() {
// Return system property value if it is set
if (SystemProperties.has(SYSTEM_PROPERTY_KEY)) {
return SystemProperties.is(SYSTEM_PROPERTY_KEY);
}
// Auto-detect if system property not set.
for (Frame frame: Frame.getFrames()) {
if (frame instanceof AccessibleContextAccessor) {
AccessibleContext frameContext = ((AccessibleContextAccessor)frame).getCurrentAccessibleContext();
if (frameContext != null)
return true;
}
}
return false;
}
}