package com.limegroup.gnutella.gui; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JLabel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.plaf.metal.MetalLabelUI; import com.limegroup.gnutella.version.UpdateInformation; final class UpdatePanel extends JLabel implements RefreshListener { private final String labelString = GUIMediator.getStringResource("UPDATE_MESSAGE_SMALL"); /** * Whether a new update is available. */ private volatile boolean _updateAvailable; /** * The most recent UpdateInformation we know about. */ private UpdateInformation _info; /** * Cached UpdateDialog. Written to only from the awt thread, read from other threads. */ private UpdateDialog _dialog; UpdatePanel() { super(GUIMediator.getStringResource("UPDATE_MESSAGE_SMALL"), SwingConstants.CENTER); //make the font so that it looks like a link setUI(new LinkLabelUI()); FontMetrics fm = getFontMetrics(getFont()); int width = fm.stringWidth(labelString); Dimension dim = new Dimension(width, fm.getHeight()); //link color, could grab system attribute as well setForeground(Color.red); setPreferredSize(dim); setMaximumSize(dim); //add a mouse listener addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { UpdatePanel.this.handleClick(); } //change cursor, we are on a link public void mouseEntered(MouseEvent e) { if(_updateAvailable) e.getComponent().setCursor (Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } //change back to normal public void mouseExited(MouseEvent e) { if(_updateAvailable) e.getComponent().setCursor(Cursor.getDefaultCursor()); } }); //add the link GUIMediator.addRefreshListener(this); //keep it invisible setVisible(false); _updateAvailable = false; } public void makeVisible(boolean popup, UpdateInformation info) { // update the dialog and dispose the old one Runnable disposer = null; synchronized(this) { _updateAvailable = true; _info = info; final UpdateDialog currentDialog = _dialog; if (_info != null ) _dialog = new UpdateDialog(_info); if (currentDialog != null) { disposer = new Runnable() { public void run() { currentDialog.setVisible(false); currentDialog.dispose(); } }; } } if (disposer != null) GUIMediator.safeInvokeLater(disposer); super.setVisible(true); // if we blink, notify the user immediately if (popup) { GUIMediator.safeInvokeLater(new Runnable() { public void run() { handleClick(); } }); } } /** * Returns true if this update panel should be shown; namely, if * an update is available. */ public boolean shouldBeShown() { return _updateAvailable; } private void handleClick() { if(!_updateAvailable) //not visible? no update yet return; synchronized(this) { if(_info != null) _dialog.setVisible(true); } } public void refresh() { if (!_updateAvailable) return; Color currCol = getForeground(); if (currCol.equals(Color.red)) setForeground(Color.black); if (currCol.equals(Color.black)) setForeground(Color.red); } private class LinkLabelUI extends MetalLabelUI { /** * Paint clippedText at textX, textY with the labels foreground color. * * @see #paint * @see #paintDisabledText */ protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) { super.paintEnabledText(l, g, s, textX, textY); if (getText() == null) return; FontMetrics fm = g.getFontMetrics(); g.fillRect(textX, fm.getAscent()+2, fm.stringWidth(getText()) - getInsets().right, 1); //X,Y,WIDTH,HEIGHT } } }