001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2008-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.guitools.controlpanel.ui.components; 028 029import java.awt.Color; 030import java.awt.Dimension; 031import java.awt.Font; 032import java.awt.Graphics; 033import java.awt.event.ActionEvent; 034import java.awt.event.MouseEvent; 035 036import javax.swing.BorderFactory; 037import javax.swing.JButton; 038import javax.swing.SwingConstants; 039import javax.swing.SwingUtilities; 040import javax.swing.UIManager; 041import javax.swing.border.Border; 042import javax.swing.border.EmptyBorder; 043 044import org.forgerock.i18n.LocalizableMessage; 045import org.opends.guitools.controlpanel.datamodel.Action; 046import org.opends.guitools.controlpanel.datamodel.Category; 047import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 048 049/** 050 * A basic extension of a button that changes its rendering so that the looks 051 * are more similar to a row in a list. It is used in the actions on the left 052 * of the main Control Center dialog (in actions like 'Manage Entries...', 053 * 'Import from LDIF...' etc. 054 */ 055public class ActionButton extends JButton 056{ 057 private static final long serialVersionUID = -1898192406268037714L; 058 059 private static final Border buttonBorder; 060 private static final Border focusBorder; 061 private final Action action; 062 private boolean isBeingPressed; 063 private boolean hasMouseOver; 064 static 065 { 066 //Calculate border based on category settings 067 Category cat = new Category(); 068 cat.setName(LocalizableMessage.EMPTY); 069 CategoryButton b = new CategoryButton(cat); 070 int n = b.getIconTextGap() + b.getIcon().getIconWidth() + 071 b.getBorder().getBorderInsets(b).left; 072 buttonBorder = new EmptyBorder(5, n, 5, 25); 073 Border highlightBorder = 074 UIManager.getBorder("List.focusCellHighlightBorder"); 075 // This is required (see issue 076 // https://opends.dev.java.net/issues/show_bug.cgi?id=4400) 077 // since in OpenJDK the CompoundBorder class does not handle properly 078 // null insets. 079 if (highlightBorder != null) 080 { 081 try 082 { 083 b.setBorder(BorderFactory.createCompoundBorder( 084 highlightBorder, buttonBorder)); 085 } 086 catch (Throwable t) 087 { 088 highlightBorder = null; 089 } 090 } 091 if (highlightBorder == null) 092 { 093 highlightBorder = 094 new javax.swing.plaf.BorderUIResource.LineBorderUIResource( 095 ColorAndFontConstants.pressedForeground, 1); 096 } 097 focusBorder = BorderFactory.createCompoundBorder( 098 highlightBorder, buttonBorder); 099 } 100 101 private static final Color defaultBackground = 102 ColorAndFontConstants.background; 103 104 private static final Color defaultForeground = 105 ColorAndFontConstants.foreground; 106 107 private static final Color mouseOverBackground = 108 ColorAndFontConstants.mouseOverBackground; 109 110 private static final Color mouseOverForeground = 111 ColorAndFontConstants.mouseOverForeground; 112 113 private static final Color pressedBackground = 114 ColorAndFontConstants.pressedBackground; 115 116 private static final Color pressedForeground = 117 ColorAndFontConstants.pressedForeground; 118 119 private static final Font actionFont = ColorAndFontConstants.defaultFont; 120 121 122 /** 123 * Creates a button associated with the provided action. 124 * @param action the action. 125 */ 126 public ActionButton(Action action) { 127 super(); 128 this.action = action; 129 setText(action.getName().toString()); 130 setIconTextGap(0); 131 setHorizontalTextPosition(SwingConstants.TRAILING); 132 setHorizontalAlignment(SwingConstants.LEADING); 133 setOpaque(true); 134 135 setBorder(buttonBorder); 136 setFont(actionFont); 137 138 setFocusPainted(true); 139 setContentAreaFilled(false); 140 setToolTipText(action.getName().toString()); 141 setRolloverEnabled(false); 142 143 Dimension d1 = getPreferredSize(); 144 setBorder(focusBorder); 145 Dimension d2 = getPreferredSize(); 146 setPreferredSize(new Dimension(Math.max(d1.width,d2.width), 147 Math.max(d1.height, d2.height))); 148 setBorder(buttonBorder); 149 } 150 151 /** 152 * Callback when an action has been performed. 153 * 154 * @param ev 155 * the action event 156 */ 157 public void actionPerformed(ActionEvent ev) 158 { 159 isBeingPressed = true; 160 final boolean[] hadMouseOver = {hasMouseOver}; 161 hasMouseOver = true; 162 repaint(); 163 SwingUtilities.invokeLater(new Runnable() 164 { 165 @Override 166 public void run() 167 { 168 isBeingPressed = false; 169 hasMouseOver = hadMouseOver[0]; 170 repaint(); 171 } 172 }); 173 } 174 175 /** 176 * Callback when a mouse button has been pressed. 177 * 178 * @param e 179 * the mouse event 180 */ 181 public void mousePressed(MouseEvent e) 182 { 183 isBeingPressed = true; 184 } 185 186 /** 187 * Callback when a mouse button has been released. 188 * 189 * @param e 190 * the mouse event 191 */ 192 public void mouseReleased(MouseEvent e) 193 { 194 isBeingPressed = false; 195 } 196 197 /** 198 * Callback when mouse exited a component. 199 * 200 * @param e 201 * the mouse event 202 */ 203 public void mouseExited(MouseEvent e) 204 { 205 hasMouseOver = false; 206 repaint(); 207 } 208 209 /** 210 * Callback when mouse entered a component. 211 * 212 * @param e 213 * the mouse event 214 */ 215 public void mouseEntered(MouseEvent e) 216 { 217 hasMouseOver = true; 218 repaint(); 219 } 220 221 /** {@inheritDoc} */ 222 @Override 223 public void updateUI() { 224 super.updateUI(); 225 // some look and feels replace our border, so take it back 226 setBorder(buttonBorder); 227 } 228 229 /** {@inheritDoc} */ 230 @Override 231 protected void paintComponent(Graphics g) { 232 setBorder(hasFocus() ? focusBorder : buttonBorder); 233 if (isBeingPressed && hasMouseOver) 234 { 235 setColors(g, pressedBackground, pressedForeground); 236 } 237 else if (hasMouseOver) 238 { 239 setColors(g, mouseOverBackground, mouseOverForeground); 240 } 241 else { 242 setColors(g, defaultBackground, defaultForeground); 243 } 244 super.paintComponent(g); 245 } 246 247 private void setColors(Graphics g, Color backgroundColor, Color foregroundColor) 248 { 249 setBackground(backgroundColor); 250 g.setColor(backgroundColor); 251 Dimension size = getSize(); 252 g.fillRect(0, 0, size.width, size.height); 253 setForeground(foregroundColor); 254 } 255 256 /** 257 * Returns the action associated with this button. 258 * @return the action associated with this button. 259 */ 260 public Action getActionObject() { 261 return action; 262 } 263}