util.ui.UiUtilities.java Source code

Java tutorial

Introduction

Here is the source code for util.ui.UiUtilities.java

Source

/*
 * TV-Browser
 * Copyright (C) 04-2003 Martin Oberhauser (martin_oat@yahoo.de)
 *
 * 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.
 *
 * CVS information:
 *  $RCSfile$
 *   $Source$
 *     $Date: 2010-11-14 17:44:44 +0100 (Sun, 14 Nov 2010) $
 *   $Author: bananeweizen $
 * $Revision: 6823 $
 */

package util.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.border.Border;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;

import org.apache.commons.lang.StringUtils;

import tvbrowser.ui.mainframe.MainFrame;
import util.browserlauncher.Launch;
import util.misc.OperatingSystem;

/**
 * Provides utilities for UI stuff.
 *
 * @author Til Schneider, www.murfman.de
 */
/**
 * @author MadMan
 *
 */
public class UiUtilities {

    /** The helper label. */
    private static final JLabel HELPER_LABEL = new JLabel();

    /** The border to use for dialogs. */
    public static final Border DIALOG_BORDER = BorderFactory.createEmptyBorder(10, 10, 0, 10);

    public static final Insets ZERO_INSETS = new Insets(0, 0, 0, 0);

    /**
     * Centers a window to its parent frame and shows it.
     * <p>
     * If the window has no parent frame it will be centered to the screen.
     *
     * @param win
     *          The window to center and show.
     */
    public static void centerAndShow(Window win) {
        Dimension wD = win.getSize();
        Dimension frameD;
        Point framePos;
        Frame frame = JOptionPane.getFrameForComponent(win);

        // Should this window be centered to its parent frame?
        boolean centerToParentFrame = (frame != null) && (frame != win) && frame.isShowing();

        // Center to parent frame or to screen
        if (centerToParentFrame) {
            frameD = frame.getSize();
            framePos = frame.getLocation();
        } else {
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            // dual head, use first screen
            if (ge.getScreenDevices().length > 1) {
                try {
                    GraphicsDevice gd = ge.getDefaultScreenDevice();
                    GraphicsConfiguration config = gd.getConfigurations()[0];
                    frameD = config.getBounds().getSize();
                    framePos = config.getBounds().getLocation();
                } catch (RuntimeException e) {
                    frameD = Toolkit.getDefaultToolkit().getScreenSize();
                    framePos = new Point(0, 0);
                }
            }
            // single screen only
            else {
                frameD = Toolkit.getDefaultToolkit().getScreenSize();
                framePos = new Point(0, 0);
            }
        }

        Point wPos = new Point(framePos.x + (frameD.width - wD.width) / 2,
                framePos.y + (frameD.height - wD.height) / 2);
        wPos.x = Math.max(0, wPos.x); // Make x > 0
        wPos.y = Math.max(0, wPos.y); // Make y > 0
        win.setLocation(wPos);
        win.setVisible(true);
    }

    /**
     * @param parent
     *          A component in the component tree where the dialog should be
     *          created for.
     * @param modal
     *          Should the new dialog be modal?
     * @return A new JDialog.
     */
    public static JDialog createDialog(Component parent, boolean modal) {
        Window parentWin = getBestDialogParent(parent);
        final JDialog result = new JDialog(parentWin);
        result.setModal(modal);
        return result;
    }

    /**
     * Gets the best dialog parent for a new JDialog. The best parent is the last
     * visible modal dialog in the component tree.
     * <p>
     * If there is no visible modal dialog the root frame will be returned.
     *
     * @param parent
     *          One component of the component tree.
     * @return the best dialog parent for a new JDialog.
     */
    public static Window getBestDialogParent(Component parent) {
        Frame root = JOptionPane.getFrameForComponent(parent);
        return getLastModalChildOf(root);
    }

    /**
     * Gets the last visible modal child dialog of the specified window.
     * <p>
     * If there is no visible modal child the window itself will be returned.
     *
     * @param parent
     *          The window to get the child from.
     * @return the last visible modal child dialog of the specified window.
     */
    public static Window getLastModalChildOf(Window parent) {
        Window[] children = parent.getOwnedWindows();
        for (Window child : children) {
            if (child instanceof Dialog) {
                Dialog dlg = (Dialog) child;
                if (dlg.isVisible() && dlg.isModal()) {
                    return getLastModalChildOf(dlg);
                }
            }
        }

        // this is the last window
        return parent;
    }

    /**
     * Gets if a dialog child of the given window is modal.
     *
     * @param parent
     *          The window to check the children of.
     * @return <code>True</code> if a child is modal, <code>false</code>
     *         otherwise.
     *
     * @since 2.7
     */
    public static boolean containsModalDialogChild(Window parent) {
        Window[] children = parent.getOwnedWindows();

        for (Window child : children) {
            if (containsModalDialogChild(child)) {
                return true;
            }
        }

        return (parent instanceof JDialog && parent.isVisible() && ((JDialog) parent).isModal());
    }

    /**
     * Gibt einen Button mit Icon und Schrift zurck, der so initialisiert ist,
     * da man ihn gut fr Symbolleisten nutzen kann (Rahmen nur bei Rollover
     * sichtbar usw.).
     * <P>
     * Wenn text und iconDateiname angegeben sind, dann wird text als TooltipText
     * gesetzt.
     *
     * @param text
     *          Der Text des Buttons (Kann null sein, wenn der Button keinen Text
     *          enthalten soll)
     * @param icon
     *          Das Icon des Buttons (Kann ebenfalls null sein, wenn der Button
     *          kein Icon enthalten soll).
     * @return button
     */
    public static JButton createToolBarButton(String text, Icon icon) {
        final JButton btn;
        if (icon == null) {
            btn = new JButton(text);
        } else {
            btn = new JButton(icon);
            btn.setToolTipText(text);
            btn.setBorderPainted(false);
            btn.setMargin(ZERO_INSETS);

            btn.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseEntered(MouseEvent e) {
                    if (btn.isEnabled()) {
                        btn.setBorderPainted(true);
                    }
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    btn.setBorderPainted(false);
                }
            });
        }
        btn.setFocusPainted(false);

        return btn;
    }

    /**
     * Gets the width of the specified String.
     *
     * @param str
     *          The String to get the width for.
     * @param font
     *          The font being the base of the measure.
     * @return the width of the specified String.
     */
    public static int getStringWidth(Font font, String str) {
        if (str == null) {
            return 0;
        }

        FontMetrics metrics = HELPER_LABEL.getFontMetrics(font);
        return metrics.stringWidth(str);
    }

    /**
     * Gets the width of the specified char array.
     *
     * @param chars
     *          The char array to get the width for.
     * @param offset
     *          The offset where to start.
     * @param length
     *          The length of the measure.
     * @param font
     *          The font being the base of the measure.
     * @return the width of the specified char array.
     */
    public static int getCharsWidth(Font font, char[] chars, int offset, int length) {
        if (chars == null) {
            return 0;
        }

        FontMetrics metrics = HELPER_LABEL.getFontMetrics(font);
        return metrics.charsWidth(chars, offset, length);
    }

    /**
     * Creates a text area that holds a help text.
     *
     * @param msg
     *          The help text.
     * @return A text area containing the help text.
     */
    public static JTextArea createHelpTextArea(String msg) {
        JTextArea descTA = new JTextArea(msg);
        descTA.setBorder(BorderFactory.createEmptyBorder());
        descTA.setFont(new JLabel().getFont());
        descTA.setEditable(false);
        descTA.setOpaque(false);
        descTA.setWrapStyleWord(true);
        descTA.setLineWrap(true);
        descTA.setFocusable(false);

        Color bg = new JPanel().getBackground();

        descTA.setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));

        return descTA;
    }

    /**
     * Creates a Html EditorPane that holds a HTML-Help Text
     *
     * Links will be displayed and are clickable
     *
     * @param html
     *          HTML-Text to display
     * @return EditorPane that holds a Help Text
     * @since 2.2
     */
    public static JEditorPane createHtmlHelpTextArea(String html) {
        return createHtmlHelpTextArea(html, new JPanel().getBackground());
    }

    /**
     * Creates a Html EditorPane that holds a HTML-Help Text
     *
     * Links will be displayed and are clickable
     *
     * @param html
     *          HTML-Text to display
     * @param background The color for the background.
     * @return EditorPane that holds a Help Text
     * @since 2.7.2
     */
    public static JEditorPane createHtmlHelpTextArea(String html, Color background) {
        return createHtmlHelpTextArea(html, new HyperlinkListener() {
            private String mTooltip;

            public void hyperlinkUpdate(HyperlinkEvent evt) {
                JEditorPane pane = (JEditorPane) evt.getSource();
                if (evt.getEventType() == HyperlinkEvent.EventType.ENTERED) {
                    mTooltip = pane.getToolTipText();
                    pane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                    if (evt.getURL() != null) {
                        pane.setToolTipText(evt.getURL().toExternalForm());
                    }
                }
                if (evt.getEventType() == HyperlinkEvent.EventType.EXITED) {
                    pane.setCursor(Cursor.getDefaultCursor());
                    pane.setToolTipText(mTooltip);
                }
                if (evt.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
                    URL url = evt.getURL();
                    if (url != null) {
                        Launch.openURL(url.toString());
                    }
                }
            }
        }, background);
    }

    /**
     * Creates a Html EditorPane that holds a HTML-Help Text.
     *
     * Add a Listener if you want to have clickable Links
     *
     * @param html
     *          HTML-Text to display
     * @param listener
     *          Link-Listener for this HelpText
     * @return EditorPane that holds a Help Text
     * @since 2.2
     */
    public static JEditorPane createHtmlHelpTextArea(String html, HyperlinkListener listener) {
        return createHtmlHelpTextArea(html, listener, new JPanel().getBackground());
    }

    /**
     * Creates a Html EditorPane that holds a HTML-Help Text.
     *
     * Add a Listener if you want to have clickable Links
     *
     * @param html
     *          HTML-Text to display
     * @param listener
     *          Link-Listener for this HelpText
     * @param background The color for the background.
     * @return EditorPane that holds a Help Text
     * @since 2.7.2
     */
    public static JEditorPane createHtmlHelpTextArea(String html, HyperlinkListener listener, Color background) {
        // Quick "hack". Remove HTML-Code and replace it with Code that includes the
        // correct Font
        if (html.indexOf("<html>") >= 0) {
            html = StringUtils.substringBetween(html, "<html>", "</html>");
        }
        JLabel label = new JLabel();
        Font font = label.getFont();
        html = "<html><div style=\"color:" + UiUtilities.getHTMLColorCode(label.getForeground()) + ";font-family:"
                + font.getName() + "; font-size:" + font.getSize() + ";background-color:rgb(" + background.getRed()
                + "," + background.getGreen() + "," + background.getBlue() + ");\">" + html + "</div></html>";

        final JEditorPane pane = new JEditorPane("text/html", html);
        pane.setBorder(BorderFactory.createEmptyBorder());
        pane.setEditable(false);
        pane.setFont(font);
        pane.setOpaque(false);
        pane.setFocusable(false);

        if (listener != null) {
            pane.addHyperlinkListener(listener);
        }
        return pane;
    }

    /**
     * returns a color code as used in HTML, e.g. #FF0000 for pure red
     * @param color
     * @return HTML color code
     */
    public static String getHTMLColorCode(Color color) {
        return '#' + StringUtils.leftPad(Integer.toString(color.getRed(), 16), 2, '0')
                + StringUtils.leftPad(Integer.toString(color.getGreen(), 16), 2, '0')
                + StringUtils.leftPad(Integer.toString(color.getBlue(), 16), 2, '0');
    }

    /**
     * Moves Selected Items from one List to another
     *
     * @param fromList
     *          Move from this List
     * @param toList
     *          Move into this List
     * @return Moved Elements
     */
    public static Object[] moveSelectedItems(JList fromList, JList toList) {
        DefaultListModel fromModel = (DefaultListModel) fromList.getModel();
        DefaultListModel toModel = (DefaultListModel) toList.getModel();

        // get the selection
        int[] selection = fromList.getSelectedIndices();

        if (selection.length == 0) {
            return new Object[] {};
        }

        Object[] objects = new Object[selection.length];
        for (int i = 0; i < selection.length; i++) {
            objects[i] = fromModel.getElementAt(selection[i]);
        }

        // get the target insertion position
        int targetPos = toList.getMaxSelectionIndex();
        if (targetPos == -1) {
            targetPos = toModel.getSize();
        } else {
            targetPos++;
        }

        // suppress updates on both lists
        if (selection.length >= 5) {
            fromList.setModel(new DefaultListModel());
            toList.setModel(new DefaultListModel());
        }

        // move the elements
        for (int i = selection.length - 1; i >= 0; i--) {
            Object value = fromModel.remove(selection[i]);
            toModel.add(targetPos, value);
        }

        if (selection.length >= 5) {
            fromList.setModel(fromModel);
            toList.setModel(toModel);
        }

        // change selection of the fromList
        if (fromModel.getSize() > 0) {
            int newSelection = selection[0];
            if (newSelection >= fromModel.getSize()) {
                newSelection = fromModel.getSize() - 1;
            }
            fromList.setSelectedIndex(newSelection);
        }

        if (selection.length >= 5) {
            fromList.repaint();
            fromList.revalidate();
            toList.repaint();
            toList.revalidate();
        }

        // change selection of the toList
        toList.setSelectionInterval(targetPos, targetPos + selection.length - 1);

        // ensure the selection is visible
        toList.ensureIndexIsVisible(toList.getMaxSelectionIndex());
        toList.ensureIndexIsVisible(toList.getMinSelectionIndex());

        return objects;
    }

    /**
     * Moves Selected Items from one List to another
     *
     * @param fromList
     *          Move from this List
     * @param toList
     *          Move into this List
     * @param row
     *          The target row where to insert
     * @return Moved Elements
     */
    public static Object[] moveSelectedItems(JList fromList, JList toList, int row) {
        DefaultListModel fromModel = (DefaultListModel) fromList.getModel();
        DefaultListModel toModel = (DefaultListModel) toList.getModel();

        // get the selection
        int[] selection = fromList.getSelectedIndices();

        if (selection.length == 0) {
            return new Object[] {};
        }

        Object[] objects = new Object[selection.length];
        for (int i = 0; i < selection.length; i++) {
            objects[i] = fromModel.getElementAt(selection[i]);
        }

        // move the elements
        for (int i = selection.length - 1; i >= 0; i--) {
            Object value = fromModel.remove(selection[i]);
            toModel.insertElementAt(value, row);
        }

        // change selection of the fromList
        if (fromModel.getSize() > 0) {
            int newSelection = selection[0];
            if (newSelection >= fromModel.getSize()) {
                newSelection = fromModel.getSize() - 1;
            }
            // fromList.setSelectedIndex(-1);
        }

        // change selection of the toList
        toList.setSelectionInterval(row, row + selection.length - 1);

        // ensure the selection is visible
        toList.ensureIndexIsVisible(toList.getMaxSelectionIndex());
        toList.ensureIndexIsVisible(toList.getMinSelectionIndex());

        return objects;
    }

    /**
     * Move selected Items in the JList
     *
     * @param list
     *          Move Items in this List
     * @param row
     *          The target row where to insert
     * @param sort
     *          Dummy parameter, does nothing
     */
    public static void moveSelectedItems(JList list, int row, boolean sort) {
        DefaultListModel model = (DefaultListModel) list.getModel();

        // get the selection
        int[] selection = list.getSelectedIndices();
        if (selection.length == 0) {
            return;
        }

        boolean lower = false;
        // Remove the selected items
        Object[] items = new Object[selection.length];
        for (int i = selection.length - 1; i >= 0; i--) {
            if (selection[i] < row && !lower) {
                row = row - i - 1;
                lower = true;
            }
            items[i] = model.remove(selection[i]);
        }

        for (int i = items.length - 1; i >= 0; i--) {
            model.insertElementAt(items[i], row);
        }

        // change selection of the toList
        list.setSelectionInterval(row, row + selection.length - 1);

        // ensure the selection is visible
        list.ensureIndexIsVisible(list.getMaxSelectionIndex());
        list.ensureIndexIsVisible(list.getMinSelectionIndex());
    }

    /**
     * Move selected Items in the JList
     *
     * @param list
     *          Move Items in this List
     * @param nrRows
     *          Move Items nrRows up/down
     */
    public static void moveSelectedItems(JList list, int nrRows) {
        DefaultListModel model = (DefaultListModel) list.getModel();

        // get the selection
        int[] selection = list.getSelectedIndices();
        if (selection.length == 0) {
            return;
        }

        // Remove the selected items
        Object[] items = new Object[selection.length];
        for (int i = selection.length - 1; i >= 0; i--) {
            items[i] = model.remove(selection[i]);
        }

        // insert the elements at the target position
        int targetPos = selection[0] + nrRows;
        targetPos = Math.max(targetPos, 0);
        targetPos = Math.min(targetPos, model.getSize());
        for (int i = 0; i < items.length; i++) {
            model.add(targetPos + i, items[i]);
        }

        // change selection of the toList
        list.setSelectionInterval(targetPos, targetPos + selection.length - 1);

        // ensure the selection is visible
        list.ensureIndexIsVisible(list.getMaxSelectionIndex());
        list.ensureIndexIsVisible(list.getMinSelectionIndex());
    }

    /**
     * Scale Icons to a specific width. The aspect ratio is kept.
     *
     * @param icon
     *          The icon to scale.
     * @param newWidth
     *          The new width of the icon.
     * @return The scaled Icon.
     */
    public static Icon scaleIcon(Icon icon, int newWidth) {
        if (icon == null) {
            return null;
        }
        return scaleIcon(icon, newWidth, (int) ((newWidth / (float) icon.getIconWidth()) * icon.getIconHeight()));
    }

    /**
     * Scales Icons to a specific size
     *
     * @param icon
     *          Icon that should be scaled
     * @param width
     *          scaled width
     * @param height
     *          scaled height
     * @return Scaled Icon
     */
    public static Icon scaleIcon(Icon icon, int width, int height) {
        if (icon == null) {
            return null;
        }
        int currentWidth = icon.getIconWidth();
        int currentHeight = icon.getIconHeight();
        if ((currentWidth == width) && (currentHeight == height)) {
            return icon;
        }
        try {
            // Create Image with Icon
            BufferedImage iconImage = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(),
                    BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = iconImage.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            AffineTransform z = g2.getTransform();
            g2.setTransform(z);
            icon.paintIcon(null, g2, 0, 0);
            g2.dispose();
            BufferedImage scaled = scaleDown(iconImage, width, height);
            // Return new Icon
            return new ImageIcon(scaled);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return icon;
    }

    /**
     * Scales an image to a specific size and returns an BufferedImage
     *
     * @param img
     *          Scale this IMage
     * @param width
     *          new width
     * @param height
     *          new height
     * @return Scaled BufferedImage
     *
     * @since 2.5
     */
    public static BufferedImage scaleIconToBufferedImage(BufferedImage img, int width, int height) {
        return scaleIconToBufferedImage(img, width, height, img.getType());
    }

    /**
     * Scales an image to a specific size and returns an BufferedImage
     *
     * @param img
     *          Scale this image
     * @param width
     *          new width
     * @param height
     *          new height
     * @param type The type of the image.
     * @return Scaled BufferedImage
     *
     * @since 2.7
     */
    public static BufferedImage scaleIconToBufferedImage(BufferedImage img, int width, int height, int type) {
        return scaleIconToBufferedImage(img, width, height, type, null);
    }

    /**
     * Scales an image to a specific size and returns an BufferedImage
     *
     * @param img
     *          Scale this image
     * @param width
     *          new width
     * @param height
     *          new height
     * @param type The type of the image.
     * @return Scaled BufferedImage
     *
     * @since 3.0
     */
    public static BufferedImage scaleIconToBufferedImage(BufferedImage img, int width, int height, int type,
            Color backgroundColor) {
        // Scale Image
        Image image = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);

        BufferedImage im = new BufferedImage(width, height, type);

        Graphics2D g2 = im.createGraphics();
        if (backgroundColor != null) {
            g2.setColor(backgroundColor);
            g2.fillRect(0, 0, width, height);
        }

        g2.drawImage(image, null, null);
        g2.dispose();

        im.flush();
        return im;

    }

    /**
     * Convenience method that returns a scaled instance of the
     * provided {@code BufferedImage}.
     *
     * @param img the original image to be scaled
     * @param targetWidth the desired width of the scaled instance,
     *    in pixels
     * @param targetHeight the desired height of the scaled instance,
     *    in pixels
     * @return a scaled version of the original {@code BufferedImage}
     */
    public static BufferedImage scaleDown(final BufferedImage img, final int targetWidth, final int targetHeight) {
        if (targetWidth > img.getWidth() || targetHeight > img.getHeight()) {
            return scaleIconToBufferedImage(img, targetWidth, targetHeight);
        }

        int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB
                : BufferedImage.TYPE_INT_ARGB;
        BufferedImage result = img;
        int w = img.getWidth();
        int h = img.getHeight();

        do {
            w /= 2;
            if (w < targetWidth) {
                w = targetWidth;
            }
            h /= 2;
            if (h < targetHeight) {
                h = targetHeight;
            }

            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2.drawImage(result, 0, 0, w, h, null);
            g2.dispose();

            result = tmp;
        } while (w != targetWidth || h != targetHeight);

        return result;
    }

    /**
     * Creates a scaled Version of the Icon.
     *
     * The scaled Version will have a Background and a Border.
     *
     * @param ic
     * @return ImageIcon
     * @since 2.1
     */
    public static ImageIcon createChannelIcon(Icon ic) {
        BufferedImage img = new BufferedImage(42, 22, BufferedImage.TYPE_INT_RGB);

        if (ic == null) {
            ic = new ImageIcon("./imgs/tvbrowser16.png");
        }

        int height = 20;
        int width = 40;

        if ((ic.getIconWidth() != 0) && (ic.getIconHeight() != 0)) {
            double iWidth = ic.getIconWidth();
            double iHeight = ic.getIconHeight();
            if (iWidth / iHeight < 2.0) {
                width = (int) (iWidth * (20.0 / iHeight));
            } else {
                height = (int) (iHeight * (40.0 / iWidth));
            }
        }
        ic = scaleIcon(ic, width, height);

        Graphics2D g = img.createGraphics();

        g.setColor(Color.WHITE);
        g.fillRect(1, 1, 40, 20);

        int x = 1 + 20 - ic.getIconWidth() / 2;
        int y = 1 + 10 - ic.getIconHeight() / 2;

        ic.paintIcon(null, g, x, y);

        g.setColor(Color.BLACK);
        g.drawRect(0, 0, 42, 22);

        return new ImageIcon(img);
    }

    /**
     * Registers the escape key as close key for a component.
     *
     * @param component
     *          The component to close on pressing escape key.
     */
    public static void registerForClosing(final WindowClosingIf component) {
        Action a = new AbstractAction() {
            private static final long serialVersionUID = 1L;

            public void actionPerformed(ActionEvent e) {
                component.close();
            }
        };

        if (OperatingSystem.isMacOs()) {
            // Add MacOS Apple+W for Closing of Dialogs
            KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.META_DOWN_MASK);
            component.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(stroke, "CLOSE_ON_APPLE_W");
            component.getRootPane().getActionMap().put("CLOSE_ON_APPLE_W", a);

            stroke = KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.META_DOWN_MASK);
            component.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(stroke,
                    "CLOSE_COMPLETE_ON_APPLE");
            component.getRootPane().getActionMap().put("CLOSE_COMPLETE_ON_APPLE", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    MainFrame.getInstance().quit();
                }
            });
        }

        KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
        component.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(stroke, "CLOSE_ON_ESCAPE");
        component.getRootPane().getActionMap().put("CLOSE_ON_ESCAPE", a);
    }

    /**
     * set the size of a dialog, but never sizes it smaller than the preferred
     * size
     *
     * @param dialog
     *          dialog to be sized
     * @param width
     *          wanted width
     * @param height
     *          wanted height
     */
    public static void setSize(JDialog dialog, int width, int height) {
        dialog.pack();
        Dimension size = dialog.getMinimumSize();
        if (width > size.width) {
            size.width = width;
        }
        if (height > size.height) {
            size.height = height;
        }
        dialog.setSize(size);
    }
}