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    }