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 }