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