// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: UifUtilities.java,v 1.35 2007/09/12 11:27:17 spyromus Exp $
//
package com.salas.bb.utils.uif;
import com.jgoodies.uif.application.Application;
import com.jgoodies.uif.util.ResourceUtils;
import com.salas.bb.utils.i18n.Strings;
import javax.swing.*;
import javax.swing.table.TableColumn;
import javax.swing.text.Document;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTMLDocument;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Collection of UIF utilities.
*/
public final class UifUtilities
{
private static final Logger LOG = Logger.getLogger(UifUtilities.class.getName());
private static final ThreadLocal<Boolean> EDT_FLAG = new ThreadLocal<Boolean>();
private static final JLabel FONT_LABEL = new JLabel();
/**
* Hidden utility class constructor.
*/
private UifUtilities()
{
}
/**
* Goes to the root of component hierarchy until finds Frame or null.
*
* @param obj object to start searching.
*
* @return owner frame.
*/
public static Frame findOwnerFrame(Object obj)
{
return (obj instanceof Component)
? findComponentOwnerFrame((Component)obj)
: findComponentOwnerFrame(null);
}
/**
* Goes to the root of component hierarchy until finds Frame or null.
*
* @param component start of search.
*
* @return owner frame.
*/
public static Frame findComponentOwnerFrame(Component component)
{
Frame owner;
if (component == null)
{
owner = Application.getDefaultParentFrame();
} else
{
if (component instanceof Frame)
{
owner = (Frame)component;
} else
{
owner = findComponentOwnerFrame(component.getParent());
}
}
return owner;
}
/**
* Returns TRUE if current thread is EDT.
*
* @return TRUE if current thread is EDT.
*/
public static boolean isEDT()
{
Boolean bool;
synchronized (EDT_FLAG)
{
bool = EDT_FLAG.get();
if (bool == null)
{
bool = SwingUtilities.isEventDispatchThread();
EDT_FLAG.set(bool);
}
}
return bool;
}
/**
* Sets the width of column to fixed value.
*
* @param table table.
* @param column index of column.
* @param width width value.
*
* @return column object.
*/
public static TableColumn setTableColWidth(JTable table, int column, int width)
{
TableColumn col = table.getColumnModel().getColumn(column);
col.setMinWidth(width);
col.setMaxWidth(width);
return col;
}
/**
* Takes current font of the component and makes it smaller.
*
* @param component component to adjust.
*
* @return smaller font.
*/
public static Font smallerFont(Component component)
{
Font font = component.getFont();
component.setFont(applyFontBias(font, -1));
return font;
}
/**
* Apply a bias to grow or shrink a given font and return a new one.
*
* @param font font to apply bias to.
* @param bias bias value in size points.
*
* @return returns the biased font.
*
* @throws NullPointerException if font is not specified.
*/
public static Font applyFontBias(Font font, int bias)
{
if (font == null) throw new NullPointerException(Strings.error("unspecified.font"));
if (bias != 0)
{
float oldSize = font.getSize2D();
font = font.deriveFont(oldSize + bias);
}
return font;
}
/**
* Sends event to parent in it's coordinate space.
*
* @param component component to get parent from.
* @param e event to send.
*/
public static void delegateEventToParent(Component component, MouseEvent e)
{
delegateEventToParent(component, e, false);
}
/**
* Sends event to parent in it's coordinate space (if <code>direct</code> isn't set).
*
* @param component component to get parent from.
* @param e event to send.
* @param direct <code>TRUE</code> for direct delegation (no conversion to parent coord. space).
*/
public static void delegateEventToParent(Component component, MouseEvent e, boolean direct)
{
Component parent = component.getParent();
delegateEventToParent(component, parent, e, direct);
}
/**
* Sends event to parent in it's coordinate space (if <code>direct</code> isn't set).
*
* @param component component to get parent from.
* @param parent parent component.
* @param e event to send.
* @param direct <code>TRUE</code> for direct delegation (no conversion to parent coord. space).
*/
public static void delegateEventToParent(Component component, Component parent, MouseEvent e, boolean direct)
{
if (parent != null)
{
if (direct)
{
e = new MouseEvent(component, e.getID(), e.getWhen(), e.getModifiers(),
e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger(), e.getButton());
} else
{
Point point = e.getPoint();
SwingUtilities.convertPointToScreen(point, component);
SwingUtilities.convertPointFromScreen(point, parent);
e = new MouseEvent(parent, e.getID(), e.getWhen(), e.getModifiers(),
(int)point.getX(), (int)point.getY(), e.getClickCount(), e.isPopupTrigger(),
e.getButton());
}
parent.dispatchEvent(e);
}
}
/**
* Sends event to parent.
*
* @param component component to get parent from.
* @param e event to send.
*/
public static void delegateEventToParent(Component component, AWTEvent e)
{
Component parent = component.getParent();
if (parent != null) parent.dispatchEvent(e);
}
/**
* Sets preferred width of the component.
*
* @param comp component.
* @param width width.
*/
public static void setPreferredWidth(JComponent comp, int width)
{
Dimension size = comp.getPreferredSize();
size.width = width;
comp.setPreferredSize(size);
}
/**
* Estimates the width of the message being printed using the given font.
*
* @param font font used.
* @param msg the message.
*
* @return width.
*/
public static int estimateWidth(Font font, String msg)
{
return FONT_LABEL.getFontMetrics(font).stringWidth(msg);
}
/**
* Paints the antialised text only if "swing.aatext" property is defined and the graphics
* context is subclass of {@link Graphics2D}.
*
* @param g context.
* @param text text.
* @param x x.
* @param y y.
*/
public static void drawAAString(Graphics g, String text, int x, int y)
{
Graphics2D g2 = (System.getProperty("swing.aatext") != null && g instanceof Graphics2D)
? (Graphics2D)g : null;
Object oldAAValue = null;
if (g2 != null)
{
oldAAValue = g2.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
g.drawString(text, x, y);
if (g2 != null)
{
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, oldAAValue);
}
}
/**
* Returns string signature of the font.
*
* @param fnt font.
*
* @return signature.
*/
public static String fontToString(Font fnt)
{
String str = null;
if (fnt != null)
{
String strStyle;
if (fnt.isBold())
{
strStyle = fnt.isItalic() ? "bolditalic" : "bold";
} else
{
strStyle = fnt.isItalic() ? "italic" : "plain";
}
str = fnt.getFamily() + "-" + strStyle + "-" + fnt.getSize();
}
return str;
}
/**
* Converts color to HEX representation, like "#0012a5".
*
* @param color color.
*
* @return HEX or empty string if color is <code>NULL</code>.
*/
public static String colorToHex(Color color)
{
if (color == null) return "";
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
StringBuffer str = new StringBuffer("#");
if (red < 16) str.append("0");
str.append(Integer.toHexString(red));
if (green < 16) str.append("0");
str.append(Integer.toHexString(green));
if (blue < 16) str.append("0");
str.append(Integer.toHexString(blue));
return str.toString();
}
public static void setTextColor(HTMLDocument doc, String styleName, Color color)
{
StyleConstants.setForeground(doc.getStyle(styleName), color);
}
public static void setFontAttributes(HTMLDocument doc, String styleName, Font font)
{
setFontAttributes(doc.getStyle(styleName), font);
String css = "ul, ol { font: normal " + font.getSize() + "pt " + font.getFamily() + " }";
loadStyles(doc, css);
}
private static void loadStyles(HTMLDocument doc, String css)
{
try
{
doc.getStyleSheet().loadRules(new StringReader(css), null);
} catch (IOException e)
{
LOG.log(Level.SEVERE, "Couldn't load new stylesheet", e);
}
}
/**
* Assigns given font to the style.
*
* @param style style.
* @param font font.
*/
public static void setFontAttributes(Style style, Font font)
{
StyleConstants.setFontFamily(style, font.getFontName());
style.addAttribute(StyleConstants.CharacterConstants.Size,
Integer.toString(font.getSize()));
}
/**
* Puts the text style over the text in current document.
*
* @param control text control.
* @param styleName style name.
*/
public static void installTextStyle(JEditorPane control, String styleName)
{
HTMLDocument doc = (HTMLDocument)control.getDocument();
doc.setCharacterAttributes(0, control.getDocument().getLength(),
doc.getStyle(styleName), false);
}
/**
* Invokes the task and waits for the completion. Reports no failure.
*
* @param task task to invoke.
*
* @return TRUE if completed without errors.
*/
public static boolean invokeAndWait(Runnable task)
{
return invokeAndWait(task, null, null);
}
/**
* Invokes the task and waits for the completion.
*
* @param task task to invoke.
* @param failMessage message to output if failed.
* @param failureLevel level of failure.
*
* @return TRUE if completed without errors.
*/
public static boolean invokeAndWait(Runnable task, String failMessage, Level failureLevel)
{
boolean errorless = false;
if (UifUtilities.isEDT())
{
task.run();
} else
{
try
{
SwingUtilities.invokeAndWait(task);
errorless = true;
} catch (Throwable e)
{
if (failMessage != null && failureLevel != null) LOG.log(failureLevel, failMessage, e);
}
}
return errorless;
}
/**
* Adds dependancy between two check boxes, so that the slave is enabled only when master is checked.
*
* @param master master.
* @param slave slave.
*/
public static void setDependency(final JCheckBox master, final JCheckBox slave)
{
if (master == null || slave == null) return;
slave.setEnabled(master.isSelected());
master.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
slave.setEnabled(master.isSelected());
}
});
}
/**
* Sets editor font.
*
* @param font font.
* @param editor editor to set font of.
*/
public static void setEditorFont(JEditorPane editor, Font font)
{
Document document = editor.getDocument();
if (document instanceof HTMLDocument)
{
HTMLDocument htmlDocument = (HTMLDocument)document;
String css = "body { font: normal " + font.getSize() + "pt " + font.getFamily() + " }";
loadStyles(htmlDocument, css);
}
}
/**
* Creates a basic plan icon component.
*
* @param visible <code>TRUE</code> if it should be visible.
*
* @return component.
*/
public static JLabel makeBasicPlanIcon(boolean visible)
{
return makePlanIcon(visible, "plan.basic.icon", "ptb.prefs.basic.tooltip");
}
/**
* Creates a publisher plan icon component.
*
* @param visible <code>TRUE</code> if it should be visible.
*
* @return component.
*/
public static JLabel makePublisherPlanIcon(boolean visible)
{
return makePlanIcon(visible, "plan.publisher.icon", "ptb.prefs.pub.tooltip");
}
private static JLabel makePlanIcon(boolean visible, String rsIcon, String rsTooltip)
{
JLabel icn;
if (visible)
{
icn = new JLabel(ResourceUtils.getIcon(rsIcon));
icn.setToolTipText(Strings.message(rsTooltip));
} else icn = new JLabel("");
return icn;
}
/**
* Every list component during construction registers a special handler that
* lets the user type letters and select elements in the list. When you
* don't need this functionality, there's no way to disable it other than
* remove the listener in a kluggie way.
*
* @param list component to operate.
*/
public static void removeTypeSelectionListener(JList list)
{
KeyListener[] kls = list.getListeners(KeyListener.class);
for (KeyListener kl : kls)
{
String name = kl.getClass().getName();
if (name.endsWith("BasicListUI$Handler")) list.removeKeyListener(kl);
}
}
/**
* Updates a font in a component to be bold.
*
* @param component component.
*
* @return component for chaining
*/
public static JComponent boldFont(JComponent component)
{
if (component == null) return null;
component.setFont(component.getFont().deriveFont(Font.BOLD));
return component;
}
}