001 /* 002 * $Id: BasicHyperlinkUI.java,v 1.5 2005/10/10 18:02:52 rbair Exp $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 package org.jdesktop.swingx.plaf.basic; 022 023 import java.awt.Color; 024 import java.awt.Cursor; 025 import java.awt.Font; 026 import java.awt.FontMetrics; 027 import java.awt.Graphics; 028 import java.awt.Insets; 029 import java.awt.Rectangle; 030 import java.awt.event.MouseAdapter; 031 import java.awt.event.MouseEvent; 032 import java.awt.event.MouseListener; 033 034 import javax.swing.AbstractButton; 035 import javax.swing.BorderFactory; 036 import javax.swing.ButtonModel; 037 import javax.swing.JComponent; 038 import javax.swing.JToolBar; 039 import javax.swing.SwingUtilities; 040 import javax.swing.UIManager; 041 import javax.swing.plaf.ComponentUI; 042 import javax.swing.plaf.basic.BasicButtonUI; 043 import javax.swing.plaf.basic.BasicGraphicsUtils; 044 import javax.swing.plaf.basic.BasicHTML; 045 import javax.swing.text.View; 046 047 /** 048 * Basic implementation of the <code>JXHyperlink</code> UI. <br> 049 * This is copied from org.jdesktop.jdnc.plaf.basic.BasicLinkButtonUI 050 */ 051 public class BasicHyperlinkUI extends BasicButtonUI { 052 053 public static ComponentUI createUI(JComponent c) { 054 return new BasicHyperlinkUI(); 055 } 056 057 private static Rectangle viewRect = new Rectangle(); 058 059 private static Rectangle textRect = new Rectangle(); 060 061 private static Rectangle iconRect = new Rectangle(); 062 063 private static MouseListener handCursorListener = new HandCursor(); 064 065 protected int dashedRectGapX; 066 067 protected int dashedRectGapY; 068 069 protected int dashedRectGapWidth; 070 071 protected int dashedRectGapHeight; 072 073 private Color focusColor; 074 075 protected void installDefaults(AbstractButton b) { 076 super.installDefaults(b); 077 078 b.setOpaque(false); 079 b.setBorderPainted(false); 080 b.setRolloverEnabled(true); 081 b.setBorder(BorderFactory.createEmptyBorder()); 082 083 dashedRectGapX = UIManager.getInt("ButtonUI.dashedRectGapX"); 084 dashedRectGapY = UIManager.getInt("ButtonUI.dashedRectGapY"); 085 dashedRectGapWidth = UIManager.getInt("ButtonUI.dashedRectGapWidth"); 086 dashedRectGapHeight = UIManager.getInt("ButtonUI.dashedRectGapHeight"); 087 focusColor = UIManager.getColor("ButtonUI.focus"); 088 089 b.setHorizontalAlignment(AbstractButton.LEADING); 090 } 091 092 protected void installListeners(AbstractButton b) { 093 super.installListeners(b); 094 b.addMouseListener(handCursorListener); 095 } 096 097 protected void uninstallListeners(AbstractButton b) { 098 super.uninstallListeners(b); 099 b.removeMouseListener(handCursorListener); 100 } 101 102 protected Color getFocusColor() { 103 return focusColor; 104 } 105 106 public void paint(Graphics g, JComponent c) { 107 AbstractButton b = (AbstractButton) c; 108 ButtonModel model = b.getModel(); 109 110 FontMetrics fm = g.getFontMetrics(); 111 112 Insets i = c.getInsets(); 113 114 viewRect.x = i.left; 115 viewRect.y = i.top; 116 viewRect.width = b.getWidth() - (i.right + viewRect.x); 117 viewRect.height = b.getHeight() - (i.bottom + viewRect.y); 118 119 textRect.x = textRect.y = textRect.width = textRect.height = 0; 120 iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0; 121 122 Font f = c.getFont(); 123 g.setFont(f); 124 125 // layout the text and icon 126 String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(), b 127 .getIcon(), b.getVerticalAlignment(), b 128 .getHorizontalAlignment(), b.getVerticalTextPosition(), b 129 .getHorizontalTextPosition(), viewRect, iconRect, textRect, b 130 .getText() == null ? 0 : b.getIconTextGap()); 131 132 clearTextShiftOffset(); 133 134 // perform UI specific press action, e.g. Windows L&F shifts text 135 if (model.isArmed() && model.isPressed()) { 136 paintButtonPressed(g, b); 137 } 138 139 // Paint the Icon 140 if (b.getIcon() != null) { 141 paintIcon(g, c, iconRect); 142 } 143 144 // Composite oldComposite = ((Graphics2D) g).getComposite(); 145 // 146 // if (model.isRollover()) { 147 // ((Graphics2D) g).setComposite(AlphaComposite.getInstance( 148 // AlphaComposite.SRC_OVER, 0.5f)); 149 // } 150 151 if (text != null && !text.equals("")) { 152 View v = (View) c.getClientProperty(BasicHTML.propertyKey); 153 if (v != null) { 154 textRect.x += getTextShiftOffset(); 155 textRect.y += getTextShiftOffset(); 156 v.paint(g, textRect); 157 textRect.x -= getTextShiftOffset(); 158 textRect.y -= getTextShiftOffset(); 159 } else { 160 paintText(g, b, textRect, text); 161 } 162 } 163 164 if (b.isFocusPainted() && b.hasFocus()) { 165 // paint UI specific focus 166 paintFocus(g, b, viewRect, textRect, iconRect); 167 } 168 169 // ((Graphics2D) g).setComposite(oldComposite); 170 } 171 172 protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, 173 String text) { 174 super.paintText(g, b, textRect, text); 175 if (b.getModel().isRollover()) { 176 paintUnderline(g, b, textRect, text); 177 } 178 } 179 180 private void paintUnderline(Graphics g, AbstractButton b, Rectangle rect, 181 String text) { 182 // JW: copied from JXTable.LinkRenderer 183 FontMetrics fm = g.getFontMetrics(); 184 int descent = fm.getDescent(); 185 186 // REMIND(aim): should we be basing the underline on 187 // the font's baseline instead of the text bounds? 188 g.drawLine(rect.x + getTextShiftOffset(), 189 (rect.y + rect.height) - descent + 1 + getTextShiftOffset(), 190 rect.x + rect.width + getTextShiftOffset(), 191 (rect.y + rect.height) - descent + 1 + getTextShiftOffset()); 192 } 193 194 protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, 195 Rectangle textRect, Rectangle iconRect) { 196 if (b.getParent() instanceof JToolBar) { 197 // Windows doesn't draw the focus rect for buttons in a toolbar. 198 return; 199 } 200 201 // focus painted same color as text 202 int width = b.getWidth(); 203 int height = b.getHeight(); 204 g.setColor(getFocusColor()); 205 BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY, 206 width - dashedRectGapWidth, height - dashedRectGapHeight); 207 } 208 209 protected void paintButtonPressed(Graphics g, AbstractButton b) { 210 // setTextShiftOffset(); 211 } 212 213 static class HandCursor extends MouseAdapter { 214 public void mouseEntered(MouseEvent e) { 215 e.getComponent().setCursor( 216 Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 217 } 218 219 public void mouseExited(MouseEvent e) { 220 e.getComponent().setCursor(Cursor.getDefaultCursor()); 221 } 222 } 223 }