/* * Copyright 2000-2016 JetBrains s.r.o. * Copyright 2013-2016 consulo.io * * 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.openapi.wm.impl.welcomeScreen; import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.internal.statistic.UsageTrigger; import com.intellij.notification.NotificationType; import com.intellij.notification.impl.IdeNotificationArea; import com.intellij.notification.impl.NotificationsManagerImpl; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.ClickListener; import com.intellij.ui.JBColor; import com.intellij.ui.components.labels.ActionLink; import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.popup.PopupFactoryImpl; import com.intellij.util.ParameterizedRunnable; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.MouseEventAdapter; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.accessibility.AccessibleContextDelegate; import consulo.annotations.RequiredDispatchThread; import consulo.ide.welcomeScreen.BaseWelcomeScreenPanel; import consulo.spash.AnimatedLogoLabel; import consulo.util.SandboxUtil; 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.*; import java.awt.event.*; import java.util.List; /** * @author Konstantin Bulenkov */ public abstract class FlatWelcomePanel extends BaseWelcomeScreenPanel<Void> { private FlatWelcomeFrame myFlatWelcomeFrame; public ParameterizedRunnable<List<NotificationType>> myEventListener; public Computable<Point> myEventLocation; @RequiredDispatchThread public FlatWelcomePanel(FlatWelcomeFrame flatWelcomeFrame) { super(flatWelcomeFrame, null); myFlatWelcomeFrame = flatWelcomeFrame; final JList projectsList = UIUtil.findComponentOfType(myLeftComponent, JList.class); if (projectsList != null) { projectsList.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { projectsList.repaint(); } @Override public void focusLost(FocusEvent e) { projectsList.repaint(); } }); } } @RequiredDispatchThread public abstract JComponent createActionPanel(); @NotNull @Override protected JComponent createLeftComponent(@NotNull Disposable parentDisposable, Void param) { return new NewRecentProjectPanel(parentDisposable); } @RequiredDispatchThread @Override @NotNull protected JComponent createRightComponent(Void param) { JPanel panel = new JPanel(new BorderLayout()); JPanel logoPanel = new JPanel(new BorderLayout()); logoPanel.setBorder(JBUI.Borders.empty(53, 66, 45, 0)); AnimatedLogoLabel animatedLogoLabel = new AnimatedLogoLabel(8, false); animatedLogoLabel.setForeground(SandboxUtil.isInsideSandbox() ? JBColor.WHITE : JBColor.GRAY); logoPanel.add(animatedLogoLabel, BorderLayout.CENTER); panel.add(logoPanel, BorderLayout.NORTH); panel.add(createActionPanel(), BorderLayout.CENTER); panel.add(createSettingsAndDocs(), BorderLayout.SOUTH); return panel; } private JComponent createSettingsAndDocs() { JPanel panel = new NonOpaquePanel(new BorderLayout()); NonOpaquePanel toolbar = new NonOpaquePanel(); toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS)); if (NotificationsManagerImpl.newEnabled()) { toolbar.add(createEventsLink()); } toolbar.add(createActionLink("Configure", IdeActions.GROUP_WELCOME_SCREEN_CONFIGURE, AllIcons.General.GearPlain, true)); toolbar.add(createActionLink("Get Help", IdeActions.GROUP_WELCOME_SCREEN_DOC, null, false)); panel.add(toolbar, BorderLayout.EAST); panel.setBorder(JBUI.Borders.empty(0, 0, 8, 11)); return panel; } private JComponent createEventsLink() { final Ref<ActionLink> actionLinkRef = new Ref<ActionLink>(); final JComponent panel = createActionLink("Events", AllIcons.Ide.Notification.NoEvents, actionLinkRef, new AnAction() { @RequiredDispatchThread @Override public void actionPerformed(@NotNull AnActionEvent e) { ((WelcomeBalloonLayoutImpl)myFlatWelcomeFrame.myBalloonLayout).showPopup(); } }); panel.setVisible(false); myEventListener = new ParameterizedRunnable<List<NotificationType>>() { @Override public void run(List<NotificationType> types) { NotificationType type1 = null; for (NotificationType t : types) { if (NotificationType.ERROR == t) { type1 = NotificationType.ERROR; break; } if (NotificationType.WARNING == t) { type1 = NotificationType.WARNING; } else if (type1 == null && NotificationType.INFORMATION == t) { type1 = NotificationType.INFORMATION; } } actionLinkRef.get().setIcon(IdeNotificationArea.createIconWithNotificationCount(actionLinkRef.get(), type1, types.size())); panel.setVisible(true); } }; myEventLocation = new Computable<Point>() { @Override public Point compute() { Point location = SwingUtilities.convertPoint(panel, 0, 0, getRootPane().getLayeredPane()); return new Point(location.x, location.y + 5); } }; return panel; } private JComponent createActionLink(final String text, final String groupId, Icon icon, boolean focusListOnLeft) { final Ref<ActionLink> ref = new Ref<ActionLink>(null); AnAction action = new AnAction() { @RequiredDispatchThread @Override public void actionPerformed(@NotNull AnActionEvent e) { ActionGroup configureGroup = (ActionGroup)ActionManager.getInstance().getAction(groupId); final PopupFactoryImpl.ActionGroupPopup popup = (PopupFactoryImpl.ActionGroupPopup)JBPopupFactory.getInstance() .createActionGroupPopup(null, new IconsFreeActionGroup(configureGroup), e.getDataContext(), JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false, ActionPlaces.WELCOME_SCREEN); popup.showUnderneathOfLabel(ref.get()); UsageTrigger.trigger("welcome.screen." + groupId); } }; JComponent panel = createActionLink(text, icon, ref, action); installFocusable(panel, action, KeyEvent.VK_UP, KeyEvent.VK_DOWN, focusListOnLeft); return panel; } private JComponent createActionLink(String text, Icon icon, Ref<ActionLink> ref, AnAction action) { ActionLink link = new ActionLink(text, icon, action); ref.set(link); // Don't allow focus, as the containing panel is going to focusable. link.setFocusable(false); link.setPaintUnderline(false); link.setNormalColor(FlatWelcomeFrame.getLinkNormalColor()); JActionLinkPanel panel = new JActionLinkPanel(link); panel.setBorder(JBUI.Borders.empty(4, 6, 4, 6)); panel.add(createArrow(link), BorderLayout.EAST); return panel; } /** * Wraps an {@link com.intellij.ui.components.labels.ActionLink} component and delegates accessibility support to it. */ public static class JActionLinkPanel extends JPanel { @NotNull private ActionLink myActionLink; public JActionLinkPanel(@NotNull ActionLink actionLink) { super(new BorderLayout()); myActionLink = actionLink; add(myActionLink); NonOpaquePanel.setTransparent(this); } @Override public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new JActionLinkPanel.AccessibleJActionLinkPanel(myActionLink.getAccessibleContext()); } return accessibleContext; } protected class AccessibleJActionLinkPanel extends AccessibleContextDelegate { public AccessibleJActionLinkPanel(AccessibleContext context) { super(context); } @Override public Accessible getAccessibleParent() { if (getParent() instanceof Accessible) { return (Accessible)getParent(); } return super.getAccessibleParent(); } @Override public AccessibleRole getAccessibleRole() { return AccessibleRole.PUSH_BUTTON; } } } public static JLabel createArrow(final ActionLink link) { JLabel arrow = new JLabel(AllIcons.General.Combo3); arrow.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); arrow.setVerticalAlignment(SwingConstants.BOTTOM); new ClickListener() { @Override public boolean onClick(@NotNull MouseEvent e, int clickCount) { final MouseEvent newEvent = MouseEventAdapter.convert(e, link, e.getX(), e.getY()); link.doClick(newEvent); return true; } }.installOn(arrow); return arrow; } public void installFocusable(final JComponent comp, final AnAction action, final int prevKeyCode, final int nextKeyCode, final boolean focusListOnLeft) { comp.setFocusable(true); comp.setFocusTraversalKeysEnabled(true); comp.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { final JList list = UIUtil.findComponentOfType(myFlatWelcomeFrame.getComponent(), JList.class); if (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_SPACE) { InputEvent event = e; if (e.getComponent() instanceof JComponent) { ActionLink link = UIUtil.findComponentOfType((JComponent)e.getComponent(), ActionLink.class); if (link != null) { event = new MouseEvent(link, MouseEvent.MOUSE_CLICKED, e.getWhen(), e.getModifiers(), 0, 0, 1, false, MouseEvent.BUTTON1); } } action.actionPerformed(AnActionEvent.createFromAnAction(action, event, ActionPlaces.WELCOME_SCREEN, DataManager.getInstance().getDataContext())); } else if (e.getKeyCode() == prevKeyCode) { focusPrev(comp); } else if (e.getKeyCode() == nextKeyCode) { focusNext(comp); } else if (e.getKeyCode() == KeyEvent.VK_LEFT) { if (focusListOnLeft) { if (list != null) { IdeFocusManager.getGlobalInstance().doForceFocusWhenFocusSettlesDown(list); } } else { focusPrev(comp); } } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) { focusNext(comp); } } }); comp.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { comp.setOpaque(true); comp.setBackground(FlatWelcomeFrame.getActionLinkSelectionColor()); } @Override public void focusLost(FocusEvent e) { comp.setOpaque(false); // comp.setBackground(FlatWelcomeFrame.getMainBackground()); } }); } protected void focusPrev(JComponent comp) { FocusTraversalPolicy policy = myFlatWelcomeFrame.getFocusTraversalPolicy(); if (policy != null) { Component prev = policy.getComponentBefore(myFlatWelcomeFrame, comp); if (prev != null) { IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> { IdeFocusManager.getGlobalInstance().requestFocus(prev, true); }); } } } protected void focusNext(JComponent comp) { FocusTraversalPolicy policy = myFlatWelcomeFrame.getFocusTraversalPolicy(); if (policy != null) { Component next = policy.getComponentAfter(myFlatWelcomeFrame, comp); if (next != null) { IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> { IdeFocusManager.getGlobalInstance().requestFocus(next, true); }); } } } private class IconsFreeActionGroup extends ActionGroup { private final ActionGroup myGroup; public IconsFreeActionGroup(ActionGroup group) { super(group.getTemplatePresentation().getText(), group.getTemplatePresentation().getDescription(), null); myGroup = group; } @Override public boolean isPopup() { return myGroup.isPopup(); } @NotNull @Override public AnAction[] getChildren(@Nullable AnActionEvent e) { AnAction[] children = myGroup.getChildren(e); AnAction[] patched = new AnAction[children.length]; for (int i = 0; i < children.length; i++) { patched[i] = patch(children[i]); } return patched; } private AnAction patch(final AnAction child) { if (child instanceof ActionGroup) { return new IconsFreeActionGroup((ActionGroup)child); } Presentation presentation = child.getTemplatePresentation(); return new AnAction(presentation.getText(), presentation.getDescription(), null) { @RequiredDispatchThread @Override public void actionPerformed(@NotNull AnActionEvent e) { child.actionPerformed(e); UsageTrigger.trigger("welcome.screen." + e.getActionManager().getId(child)); } @RequiredDispatchThread @Override public void update(@NotNull AnActionEvent e) { child.update(e); e.getPresentation().setIcon(null); } @Override public boolean isDumbAware() { return child.isDumbAware(); } }; } } }