/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui.tools.components.composite; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.SwingConstants; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import com.rapidminer.gui.tools.Ionicon; import com.rapidminer.tools.I18N; /** * Composite button that allows to specify one primary and multiple secondary {@link Action}. The * button displays the primary action similar to a plain {@link JButton} but with a drop down * element on the left that opens a {@link JPopupMenu} containing the secondary actions. * * @author Michael Knopf * @since 7.0.0 */ public class SplitButton extends JPanel { private static final long serialVersionUID = 1L; /** Label used for the drop down button. */ private static final String DROPDOWN_LABEL = "<html><span style=\"color: 4F4F4F;\">" + Ionicon.ARROW_DOWN_B.getHtml() + "</span></html>"; /** Button to display the primary action. */ private JButton primaryButton; /** Button to access the secondary actions. */ private JButton dropDownButton; /** Popup menu associated with drop down button. */ private JPopupMenu popupMenu; /** Remember the last time the popup was closed. */ private long lastPopupCloseTime = 0; /** * Creates a new {@code SplitButton} with the given primary and secondary {@link Action}. * * @param primaryAction * the primary action * @param secondaryActions * one ore more secondary actions */ public SplitButton(Action primaryAction, Action... secondaryActions) { popupMenu = new JPopupMenu(); popupMenu.add(primaryAction); for (Action action : secondaryActions) { popupMenu.add(action); } initSplitButton(primaryAction); } /** * Creates a new {@link SplitButton} with the given primary {@link Action} and a custom * {@link JPopupMenu}. * * @param primaryAction * the primary action * @param popupMenu * the drop down menu */ public SplitButton(Action primaryAction, JPopupMenu popupMenu) { this.popupMenu = popupMenu; initSplitButton(primaryAction); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); primaryButton.setEnabled(enabled); dropDownButton.setEnabled(enabled); } public JPopupMenu getPopupMenu() { return popupMenu; } /** * @see AbstractButton#setHideActionText(boolean) */ public void SetHideActionText(boolean hideActionText) { primaryButton.setHideActionText(hideActionText); } private void initSplitButton(final Action primaryAction) { if (primaryAction == null) { throw new IllegalArgumentException("Primary action must not be null!"); } if (popupMenu == null) { throw new IllegalArgumentException("Popup menu must not be null!"); } popupMenu.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(final PopupMenuEvent e) {} @Override public void popupMenuWillBecomeInvisible(final PopupMenuEvent e) { lastPopupCloseTime = System.currentTimeMillis(); } @Override public void popupMenuCanceled(final PopupMenuEvent e) {} }); setOpaque(false); // simple composition of two buttons primaryButton = new CompositeButton(primaryAction, SwingConstants.LEFT); dropDownButton = new CompositeButton(DROPDOWN_LABEL, SwingConstants.RIGHT); dropDownButton.setToolTipText(I18N.getGUIMessage("gui.split_button.drop_down.tip")); // buttons might differ in their height Dimension primaryButtonSize = primaryButton.getPreferredSize(); Dimension dropDownButtonSize = dropDownButton.getPreferredSize(); if (primaryButtonSize.height > dropDownButtonSize.height) { dropDownButtonSize.height = primaryButtonSize.height; dropDownButton.setPreferredSize(dropDownButtonSize); } else { primaryButtonSize.height = dropDownButtonSize.height; primaryButton.setPreferredSize(primaryButtonSize); } // align buttons left to right with no padding FlowLayout layout = new FlowLayout(SwingConstants.LEFT); layout.setHgap(0); setLayout(layout); add(primaryButton); add(dropDownButton); // display pop up menu below drop down button (if possible) dropDownButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // hack to prevent filter popup from opening itself again // when you click the button to actually close it while it // is open if (System.currentTimeMillis() - lastPopupCloseTime < 250) { return; } popupMenu.show(dropDownButton, 0, primaryButton.getHeight() - 1); } }); } }