/* * Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Flamingo Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.flamingo.internal.ui.common; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.*; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.pushingpixels.flamingo.api.common.*; import org.pushingpixels.flamingo.api.common.model.PopupButtonModel; /** * Listener to track user interaction with the command buttons. * * @author Kirill Grouchnikov */ public class BasicCommandButtonListener implements MouseListener, MouseMotionListener, FocusListener, ChangeListener { /* * (non-Javadoc) * * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent) */ @Override public void focusLost(FocusEvent e) { AbstractCommandButton b = (AbstractCommandButton) e.getSource(); // System.err.println(e.getComponent() + "\n\tlost " // + (e.isTemporary() ? "temporary" : "permanent") // + " focus to \n\t" + e.getOppositeComponent()); b.getActionModel().setArmed(false); b.getActionModel().setPressed(false); if (b instanceof JCommandButton) { PopupButtonModel popupModel = ((JCommandButton) b).getPopupModel(); popupModel.setPressed(false); popupModel.setArmed(false); } } /* * (non-Javadoc) * * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent) */ @Override public void focusGained(FocusEvent e) { AbstractCommandButton b = (AbstractCommandButton) e.getSource(); b.repaint(); } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) */ @Override public void mousePressed(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { AbstractCommandButton b = (AbstractCommandButton) e.getSource(); JScrollablePanel scrollable = (JScrollablePanel) SwingUtilities .getAncestorOfClass(JScrollablePanel.class, b); if (scrollable != null) { // scroll the viewport of the scrollable panel so that // the button is fully viewed. Point loc = SwingUtilities.convertPoint(b.getParent(), b .getLocation(), scrollable.getView()); if (scrollable.getScrollType() == JScrollablePanel.ScrollType.HORIZONTALLY) { scrollable.scrollToIfNecessary(loc.x, b.getWidth()); } else { scrollable.scrollToIfNecessary(loc.y, b.getHeight()); } } if (b.contains(e.getX(), e.getY())) { CommandButtonUI ui = b.getUI(); Rectangle actionRect = ui.getLayoutInfo().actionClickArea; Rectangle popupRect = ui.getLayoutInfo().popupClickArea; if ((actionRect != null) && actionRect.contains(e.getPoint())) { ButtonModel actionModel = b.getActionModel(); if (actionModel.isEnabled()) { actionModel.setArmed(true); actionModel.setPressed(true); } } else { if ((popupRect != null) && popupRect.contains(e.getPoint())) { PopupButtonModel popupModel = ((JCommandButton) b) .getPopupModel(); if (popupModel.isEnabled()) { popupModel.setArmed(true); popupModel.setPressed(true); } } } // System.err.println(b.getText() + " - hasFocus():" // + b.hasFocus() + ", isRequestFocusEnabled():" // + b.isRequestFocusEnabled()); if (!b.hasFocus() && b.isRequestFocusEnabled()) { b.requestFocusInWindow(); } } } }; /* * (non-Javadoc) * * @see * java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) */ @Override public void mouseReleased(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { AbstractCommandButton b = (AbstractCommandButton) e.getSource(); b.getActionModel().setPressed(false); if (b instanceof JCommandButton) { ((JCommandButton) b).getPopupModel().setPressed(false); } b.getActionModel().setArmed(false); if (b instanceof JCommandButton) { ((JCommandButton) b).getPopupModel().setArmed(false); } } }; /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */ @Override public void mouseClicked(MouseEvent e) { } /* * (non-Javadoc) * * @see * java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent * ) */ @Override public void mouseDragged(MouseEvent e) { } /* * (non-Javadoc) * * @see * java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) */ @Override public void mouseMoved(MouseEvent e) { this.syncMouseMovement(e); } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */ @Override public void mouseEntered(MouseEvent e) { this.syncMouseMovement(e); } /** * Synchronizes the action and popup models of the command button with the * specified mouse event. * * @param e * Mouse event for the model synchronization. */ private void syncMouseMovement(MouseEvent e) { AbstractCommandButton b = (AbstractCommandButton) e.getSource(); ButtonModel actionModel = b.getActionModel(); PopupButtonModel popupModel = (b instanceof JCommandButton) ? ((JCommandButton) b) .getPopupModel() : null; CommandButtonUI ui = b.getUI(); Rectangle actionRect = ui.getLayoutInfo().actionClickArea; Rectangle popupRect = ui.getLayoutInfo().popupClickArea; if ((actionRect != null) && actionRect.contains(e.getPoint())) { if (actionModel.isEnabled()) { if (!SwingUtilities.isLeftMouseButton(e)) actionModel.setRollover(true); if (actionModel.isPressed()) actionModel.setArmed(true); } if (popupModel != null && !SwingUtilities.isLeftMouseButton(e)) popupModel.setRollover(false); } else { if ((popupRect != null) && popupRect.contains(e.getPoint())) { if ((popupModel != null) && popupModel.isEnabled()) { if (!SwingUtilities.isLeftMouseButton(e)) popupModel.setRollover(true); if (popupModel.isPressed()) popupModel.setArmed(true); } if (!SwingUtilities.isLeftMouseButton(e)) actionModel.setRollover(false); } } }; /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */ @Override public void mouseExited(MouseEvent e) { AbstractCommandButton b = (AbstractCommandButton) e.getSource(); ButtonModel actionModel = b.getActionModel(); PopupButtonModel popupModel = (b instanceof JCommandButton) ? ((JCommandButton) b) .getPopupModel() : null; actionModel.setRollover(false); actionModel.setArmed(false); if (popupModel != null) { popupModel.setRollover(false); popupModel.setArmed(false); } }; /* * (non-Javadoc) * * @see * javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent * ) */ @Override public void stateChanged(ChangeEvent e) { AbstractCommandButton b = (AbstractCommandButton) e.getSource(); b.repaint(); } /** * Installs keyboard action (space / enter keys) on the specified command * button. * * @param button * Command button. */ public void installKeyboardActions(AbstractCommandButton button) { ActionMap map = new ActionMap(); map.put(PressAction.PRESS, new PressAction(button)); map.put(ReleaseAction.RELEASE, new ReleaseAction(button)); SwingUtilities.replaceUIActionMap(button, map); InputMap km = LookAndFeel.makeInputMap(new Object[] { "SPACE", "pressed", "released SPACE", "released", "ENTER", "pressed", "released ENTER", "released" }); SwingUtilities.replaceUIInputMap(button, JComponent.WHEN_FOCUSED, km); } /** * Button press action. * * @author Kirill Grouchnikov */ private static class PressAction extends AbstractAction { /** * Press action name. */ private static final String PRESS = "pressed"; /** * Associated command button. */ AbstractCommandButton button; /** * Creates a new press action. * * @param button * Associated command button. */ PressAction(AbstractCommandButton button) { super(PRESS); this.button = button; } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent * ) */ @Override public void actionPerformed(ActionEvent e) { ButtonModel model = button.getActionModel(); model.setArmed(true); model.setPressed(true); if (!button.hasFocus()) { button.requestFocus(); } } /* * (non-Javadoc) * * @see javax.swing.AbstractAction#isEnabled() */ @Override public boolean isEnabled() { return button.getActionModel().isEnabled(); } } /** * Button release action. * * @author Kirill Grouchnikov */ private static class ReleaseAction extends AbstractAction { /** * Release action name. */ private static final String RELEASE = "released"; /** * Associated command button. */ AbstractCommandButton button; /** * Creates a new release action. * * @param button * Associated command button. */ ReleaseAction(AbstractCommandButton button) { super(RELEASE); this.button = button; } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent * ) */ @Override public void actionPerformed(ActionEvent e) { ButtonModel model = button.getActionModel(); model.setPressed(false); model.setArmed(false); } /* * (non-Javadoc) * * @see javax.swing.AbstractAction#isEnabled() */ @Override public boolean isEnabled() { return button.getActionModel().isEnabled(); } } /** * Uninstalls keyboard action (space / enter keys) from the specified * command button. * * @param button * Command button. */ public void uninstallKeyboardActions(AbstractCommandButton button) { SwingUtilities.replaceUIInputMap(button, JComponent.WHEN_IN_FOCUSED_WINDOW, null); SwingUtilities.replaceUIInputMap(button, JComponent.WHEN_FOCUSED, null); SwingUtilities.replaceUIActionMap(button, null); } }