Package org.openquark.util.ui

Source Code of org.openquark.util.ui.UIUtilities

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Business Objects nor the names of its contributors
*       may be used to endorse or promote products derived from this software
*       without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/


/*
* UIUtilities.java
* Created: Dec. 8 / 2003
* By: David Mosimann
*/
package org.openquark.util.ui;

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.SystemColor;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.plaf.OptionPaneUI;
import javax.swing.plaf.basic.BasicBorders;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.plaf.basic.BasicOptionPaneUI;
import javax.swing.plaf.basic.BasicToggleButtonUI;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

/**
* A collection of user interfaces helper methods.
*/
public class UIUtilities {

    /** An action property for specifying whether a regualar or toggle button should be created. */
    public static final String TOGGLE_BUTTON = "TOGGLE_BUTTON"; //$NON-NLS-1$

    /** Rendering hints - render at highest quality*/
    private static final RenderingHints RENDERING_HINTS_HIGH_QUALITY = new RenderingHints(null);
    static {
        RENDERING_HINTS_HIGH_QUALITY.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        RENDERING_HINTS_HIGH_QUALITY.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        RENDERING_HINTS_HIGH_QUALITY.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        RENDERING_HINTS_HIGH_QUALITY.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        RENDERING_HINTS_HIGH_QUALITY.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        RENDERING_HINTS_HIGH_QUALITY.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        RENDERING_HINTS_HIGH_QUALITY.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        RENDERING_HINTS_HIGH_QUALITY.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    }
   
    /** Enumeration indicating image flip orientation */
    public static final class FlipOrientation {
       
        /** Vertical Flip */
        public static final FlipOrientation Vertical = new FlipOrientation("Vertical Flip"); //$NON-NLS-1$
        /** Horizontal Flip */
        public static final FlipOrientation Horizontal = new FlipOrientation("Horizontal Flip"); //$NON-NLS-1$
        /** Vertical and Horizontal Flip */
        public static final FlipOrientation BiDirectional = new FlipOrientation("Vertical and Horizontal Flip"); //$NON-NLS-1$
       
        private final String enumType;
        private FlipOrientation(String type) {
            if (type == null) {
                throw new NullPointerException();
            }
            enumType = type;
        }
       
        @Override
        public String toString() {
            return enumType;
        }
    }
   
    /**
     * This class should never be constructed.  It's only purpose is to collect useful static methods
     * similar to how the SwingUtilities class works.
     */
    private UIUtilities() {
        super();
    }

    /**
     * Creates a new JButton with the flat appearance.  It uses the same rollover effect as flat buttons
     * in a toolbar.
     * @return a JButton with the roll over property set and the border customized to show the rollover effect
     */
    public static JButton CreateFlatButton() {
        JButton button = new JButton();
        makeButtonFlat(button);
        return button;
    }

    /**
     * Creates a new JToggleButton with the flat appearance. 
     * It uses the same rollover effect as flat buttons in a toolbar.
     * @return a JButton with the roll over property set and the border customized to show the rollover effect
     */
    public static JToggleButton CreateFlatToggleButton() {
        JToggleButton button = new JToggleButton();
        makeButtonFlat(button);
        return button;
    }
   
    /**
     * Creates a new JButton with the flat appearance. 
     * It uses the same rollover effect as flat buttons in a toolbar.
     * The TOGGLE_BUTTON boolean property is checked to determine whether to create a toggle
     * button or a regular one (default).
     * @param action  the action to be hooked up to the button
     * @return a JButton with the roll over property set and the border customized to show the rollover effect
     */
    public static AbstractButton CreateFlatButton(Action action) {
        // Create the button
        boolean toggleButton = false;
        if (action != null) {
            Object toggleButtonObj = action.getValue(TOGGLE_BUTTON);
            toggleButton = (toggleButtonObj instanceof Boolean) ? ((Boolean) toggleButtonObj).booleanValue() : false;
        }
       
        AbstractButton button = toggleButton?(AbstractButton)CreateFlatToggleButton():CreateFlatButton();
       
        if (action != null) {
            button.setAction(action);
        }
       
        return button;
    }
   
    public static void makeButtonFlat(AbstractButton button) {
        // Override the default look and feel: use basic L&F because some L&F (esp. WinXP)
        // ignores the border property
        if(button instanceof JToggleButton) {
            button.setUI(new BasicToggleButtonUI());
        } else {
            button.setUI(new BasicButtonUI());
        }
       
        button.setRolloverEnabled(true);
       
        UIDefaults table = UIManager.getLookAndFeelDefaults();
        button.setBorder(new BasicBorders.RolloverButtonBorder(
                table.getColor("controlShadow"), //$NON-NLS-1$
                table.getColor("controlDkShadow"), //$NON-NLS-1$
                table.getColor("controlHighlight"), //$NON-NLS-1$
                table.getColor("controlLtHighlight"))); //$NON-NLS-1$
    }

    /**
     * A helper class for creating actions for a toggle button.
     */
    public static abstract class AbstractToggleAction extends AbstractAction {
        /**
         * AbstractToggleAction constructor.
         */
        public AbstractToggleAction(String name, Icon icon) {
            super(name, icon);
            putValue(TOGGLE_BUTTON, Boolean.TRUE);
        }
    }

    /**
     * Shifts the image to the specified coordinates, growing or
     * shrinking the image size as required.
     *
     * @param originalImage
     * @param x horizontal position of top left corner
     * @param y vertical position of top left corner
     * @return image containing the original at the specified position
     */
    public static Image shiftImage(Image originalImage, int x, int y) {
       
        // Create a blank image and initialize graphics painter
       
        BufferedImage newImage = new BufferedImage(
            originalImage.getWidth(null) + x,
            originalImage.getHeight(null) + y,
            BufferedImage.TYPE_INT_ARGB_PRE
        );
        Graphics2D g2d = newImage.createGraphics();
        g2d.setRenderingHints(RENDERING_HINTS_HIGH_QUALITY);

        // Now paint the original on the new image
       
        g2d.drawImage(originalImage, x, y, null);
        g2d.dispose();
       
        return newImage;
    }
   
    /**
     * Crops the edges of the image, as specified. If the crop dimensions
     * are negative, the image is grown.
     *
     * @param originalImage
     * @param left number of pixels to trim from the the left edge
     * @param top pixels to trim from the top edge
     * @param right pixels to trim from the right edge
     * @param bottom pixels to trim from the bottom edge
     * @return cropped image
     */
    public static Image cropImage(Image originalImage, int left, int top, int right, int bottom) {
        BufferedImage newImage = new BufferedImage(
                originalImage.getWidth(null) - left - right,
                originalImage.getHeight(null) - top - bottom,
                BufferedImage.TYPE_INT_ARGB_PRE
        );
        Graphics2D g2d = newImage.createGraphics();
        g2d.setRenderingHints(RENDERING_HINTS_HIGH_QUALITY);
       
        g2d.drawImage(originalImage, -1 * left, -1 * top, null);
        g2d.dispose();
       
        return newImage;
    }
   
    /**
     * Rotates the image around its center by the specified angle. The original image 
     * size is maintained, so cropping may occur as a result of the rotation.
     *
     * @param originalImage
     * @param theta angle in radians (a positive angle indicates clockwise rotation)
     * @return rotated image
     */
    public static Image rotateImage (Image originalImage, double theta) {
        BufferedImage newImage = new BufferedImage(
                originalImage.getWidth(null),
                originalImage.getHeight(null),
                BufferedImage.TYPE_INT_ARGB_PRE
        );
        Graphics2D g2d = newImage.createGraphics();
        g2d.setRenderingHints(RENDERING_HINTS_HIGH_QUALITY);
       
        g2d.rotate(theta, originalImage.getWidth(null) / (double)2, originalImage.getHeight(null) / (double)2);
        g2d.drawImage( originalImage, 0, 0, null);
        g2d.dispose();
       
        return newImage;
    }
   
    /**
     * Flips the image vertically and/or horizontally.
     *
     * @param originalImage
     * @param flipType flip direction
     * @return flipped image
     */
    public static Image flipImage (Image originalImage, FlipOrientation flipType) {
        BufferedImage newImage = new BufferedImage(
                originalImage.getWidth(null),
                originalImage.getHeight(null),
                BufferedImage.TYPE_INT_ARGB_PRE
        );
        Graphics2D g2d = newImage.createGraphics();
        g2d.setRenderingHints(RENDERING_HINTS_HIGH_QUALITY);
      
        AffineTransform flipTransform = new AffineTransform(
                (flipType == FlipOrientation.Horizontal || flipType == FlipOrientation.BiDirectional)? -1.0 : 1.0,
                0.0, 0.0,
                (flipType == FlipOrientation.Vertical   || flipType == FlipOrientation.BiDirectional)? -1.0 : 1.0,
                0.0, 0.0);
        flipTransform.translate(
                (flipType == FlipOrientation.Horizontal || flipType == FlipOrientation.BiDirectional)? -originalImage.getWidth(null) : 0.0,
                (flipType == FlipOrientation.Vertical   || flipType == FlipOrientation.BiDirectional)? -originalImage.getHeight(null) : 0.0);
       
        g2d.setTransform(flipTransform);
        g2d.drawImage(originalImage, 0, 0, null);
        g2d.dispose();
       
        return newImage;
    }

    // Helper fields for fixMenuItem()
    private static final String lowerCaseOSName = System.getProperty("os.name").toLowerCase();
    private static final boolean JUSTIFY_MENU_ITEM_HACK =
        System.getProperty("java.version").startsWith("1.5") &&
        !(lowerCaseOSName.startsWith("mac os x") || lowerCaseOSName.endsWith("vista"));
   
    /**
     * Fix up the given menu item so that it is justified correctly, has the associated icon, has no tooltip.
     * @param menuItem the menu item to fix.
     * @return the menu item that was fixed.  ie. the menuItem param.
     */
    public static JMenuItem fixMenuItem(JMenuItem menuItem) {
   
        // HACK: Workaround for left-justifying icons. Sun Bug ID's: 4199382, 4203899.
        // Hack seems to bugger up mac os x
        // On Vista it makes the icon shift left enough so that you can't see most of it.
        // Fixed in Java 6.
       
        if (JUSTIFY_MENU_ITEM_HACK) {
            // Get the icon, calculate its width.
            Icon buttonIcon = menuItem.getIcon() != null ? menuItem.getIcon() :
                            menuItem.getAction() != null ? (Icon) menuItem.getAction().getValue(Action.SMALL_ICON) : null;
            int iconWidth = (buttonIcon == null) ? -(menuItem.getIconTextGap()) : buttonIcon.getIconWidth();
           
            Insets insets = menuItem.getInsets();
            insets.left -= iconWidth;
            menuItem.setMargin(insets);
        }
       
        // Menu items should not have tooltips, so clear it in case the action specifies one
        menuItem.setToolTipText(null);
       
        return menuItem;
    }
   
    /**
     * Creates a new JMenuItem and configures it for use in a popup menu.
     * @param action Action - the action used to configure the JMenuItem
     * @return JMenuItem a new menu item for the action.
     */
    public static JMenuItem makeNewMenuItem(Action action) {
        JMenuItem newMenuItem = new JMenuItem(action);
        return fixMenuItem(newMenuItem);
    }

    /**
     * A helper function to paint a watermark for a component.
     * This should be called in the paintComponent method before calling the super class method.
     * @param g
     */
    public static void paintWithWatermarkHelper(JComponent component, ImageIcon watermark, Graphics g) {
        Graphics2D g2 = (Graphics2D) g;

        Paint oldPaint = g2.getPaint();
        g2.setPaint(component.getBackground());

        try {
            // Fill in the background of the component.
            g2.fillRect(0, 0, component.getWidth(), component.getHeight());
   
            // Draw the background image, if any.
            if (watermark != null) {

                // draw the image centred in the visible area, and scaled to fit
                Rectangle viewRect = new Rectangle (0, 0, component.getWidth(), component.getHeight());

                Component parent = component.getParent();
                if (parent instanceof JViewport) {
                    JViewport viewport = (JViewport) parent;
                    viewRect = viewport.getViewRect();
                }

                int imageWidth  = watermark.getIconWidth();
                int imageHeight = watermark.getIconHeight();

                double xZoom = viewRect.getWidth() / imageWidth;
                double yZoom = viewRect.getHeight() / imageHeight;

                double zoom = Math.min (xZoom, yZoom);

                int drawnWidth = (int)(imageWidth * zoom);
                int drawnHeight = (int)(imageHeight * zoom);

                int x = viewRect.x + (viewRect.width - drawnWidth) / 2;
                int y = viewRect.y + (viewRect.height - drawnHeight) / 2;

                Composite oldComposite = g2.getComposite();

                g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.25f));

                g2.drawImage(watermark.getImage(), x, y, x + drawnWidth, y + drawnHeight, 0, 0, imageWidth, imageHeight, null);

                g2.setComposite(oldComposite);
            }
        }
        finally {
            g2.setPaint(oldPaint);
        }
    }
   
    /**
     * Returns the parent component of the component c that has the given type,
     * or <code>null</code> if such parent does not exist.
     * @param c
     * @param type
     * @return Component
     */
    public static Component getParent(Component c, Class<? extends Container> type) {
        c = c.getParent();
        while (c != null) {
            // assume that they are loaded by the same classloader
            if (c.getClass() == type) {
                return c;
            }
            c = c.getParent();
        }
        return null;
    }
   
    /**
     * A helper method for setting the bold font attribute in the given component.
     * @param c
     * @param useBold
     */
    public static void setFontBold(Component c, boolean useBold) {
        Font f = c.getFont ();
        int style = f.getStyle();
        if (useBold) {
            style |= Font.BOLD;
        } else {
            style &= ~Font.BOLD;
        }
        c.setFont(f.deriveFont(style));
    }
   
    /**
     * A helper method for setting the italic font attribute in the given component.
     * @param c
     * @param useItalic
     */
    public static void setFontItalic(Component c, boolean useItalic) {
        Font f = c.getFont ();
        int style = f.getStyle();
        if (useItalic) {
            style |= Font.ITALIC;
        } else {
            style &= ~Font.ITALIC;
        }
        c.setFont(f.deriveFont(style));
    }
   
    /**
     * Brightens each of the RGB components of color by the specified factor.
     * Note: This is identical to the java.awt.Color.brighten() method, using a variable factor.
     *
     * @param color color to brighten
     * @param factor luminosity factor; if negative, the color is darkened 
     * @return brightened color
     */
    public static Color brightenColor(Color color, double factor) {
        int r = color.getRed();
        int g = color.getGreen();
        int b = color.getBlue();
       
        int i = (int) (1.0 / (1.0 - factor));
        if ( r == 0 && g == 0 && b == 0) {
           return new Color(i, i, i);
        }
       
        if ( r > 0 && r < i ) {
            r = i;
        }
        if ( g > 0 && g < i ) {
            g = i;
        }
        if ( b > 0 && b < i ) {
            b = i;
        }

        return new Color(Math.min((int)(r/factor), 255),
                         Math.min((int)(g/factor), 255),
                         Math.min((int)(b/factor), 255));
    }

    /**
     * Returns an icon that combines the 2 specified icons.
     * One will be drawn over top of the base icon.
     * The resulting icon will be large enough to hold both icons.
     * @param underIcon  the icon to be drawn first
     * @param overIcon   the icon to be drawn over top
     * @return the combined icon
     */
    public static Icon combineIcons(Icon underIcon, Icon overIcon) {
        int newWidth = Math.max(underIcon.getIconWidth(), overIcon.getIconWidth());
        int newHeight = Math.max(underIcon.getIconHeight(), overIcon.getIconHeight());

        BufferedImage combinedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = combinedImage.createGraphics();
        underIcon.paintIcon(null, g2d, 0, 0);
        overIcon.paintIcon(null, g2d, 0, 0);
        g2d.dispose();

        return new ImageIcon(combinedImage);
    }

    /**
     * Changes the specified text component to support undo and redo using Ctrl-Z and Ctrl-Y.
     * @param textComponent  the text component to be modified
     */
    public static void makeTextComponentUndoable(JTextComponent textComponent) {
        final UndoManager undoManager = new UndoManager();
        final Action undoAction = new AbstractAction(UIMessages.instance.getString("GenericUndoName")) { //$NON-NLS-1$
            private static final long serialVersionUID = -2135822508998640523L;

                public void actionPerformed(ActionEvent e) {
                    try {
                        if (undoManager.canUndo()) {
                            undoManager.undo();
                        }
                    }
                    catch (CannotUndoException ex) {
                    }
                }
            };
        final Action redoAction = new AbstractAction(UIMessages.instance.getString("GenericRedoName")) { //$NON-NLS-1$
            private static final long serialVersionUID = 2928127985356997903L;

                public void actionPerformed(ActionEvent e) {
                    try {
                        if (undoManager.canRedo()) {
                            undoManager.redo();
                        }
                    }
                    catch (CannotUndoException ex) {
                    }
                }
            };

        UndoableEditListener undoListener = new UndoableEditListener() {
                public void undoableEditHappened(UndoableEditEvent e) {
                    undoManager.addEdit(e.getEdit());
                }
            };

        textComponent.getDocument().addUndoableEditListener(undoListener);

        Keymap keymap = JTextComponent.addKeymap("TextUndoRedoKeymap", textComponent.getKeymap()); //$NON-NLS-1$
        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK), undoAction);
        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_MASK), redoAction);
        textComponent.setKeymap(keymap);
    }

    /**
     * Loads an <code>Icon</code> from the specified icon path.  The <code>ClassLoader</code>
     * of the given class will be used to load the icon.
     * @param iconUrl
     * @return Icon
     */
    public static Icon LoadImageIcon(URL iconUrl) {
        if (iconUrl != null) {
            return new ImageIcon(iconUrl);
        }
        return null;
    }
   
    /**
     * Loads an <code>Icon</code> from the specified icon path.  This method will use
     * the <code>ClassLoader</code> that loaded this class to load the icon.
     * @param iconPath
     * @return Icon
     */
    public static Icon LoadImageIcon(String iconPath) {
        return LoadImageIcon(UIUtilities.class, iconPath);
    }

    /**
     * Loads an <code>Icon</code> from the specified icon path.  This method will use
     * the <code>ClassLoader</code> that loaded this class to load the icon.
     * @param c the class to get the resource from / for
     * @param iconPath
     * @return Icon
     */
    public static Icon LoadImageIcon(Class<?> c, String iconPath) {
        if (iconPath != null && c != null) {
            URL imagePath = c.getResource(iconPath);
            return LoadImageIcon(imagePath);
        }
        return null;
    }
   
    /**
     * Method makeLocalObjectDataFlavor
     *
     * @param representationClass
     * @param name
     *
     * @return Returns a DataFlavour that represents a Java object local to this VM
     */
    public static DataFlavor makeLocalObjectDataFlavor (Class<?> representationClass, String name) {
        return new DataFlavor (DataFlavor.javaJVMLocalObjectMimeType + ";class=" + representationClass.getName(), name); //$NON-NLS-1$
    }
   
    /**
     * Create a label that looks a bit like a post-it note, nice for giving
     * feedback without makeing people think they've made an error.
     * @param text
     * @return JLabel
     */
    public static JLabel createInfoLabel(String text) {
        JLabel label = new JLabel(text);
        label.setOpaque(true);

        Border inner = BorderFactory.createEmptyBorder(2,4,2,4);
        Border outer = BorderFactory.createLineBorder(SystemColor.info.darker());
        label.setBorder(BorderFactory.createCompoundBorder(outer, inner));
        label.setBackground(SystemColor.info);

        return label;
    }
   
    /**
     * Add a search box to a UtilTree.
     * @param tree A searchable UtilTree.
     * @return A panel containing the given UtilTree and a search box.
     */
    public static JPanel makeSearchablePanel(UtilTree tree) {
        JPanel panel = new JPanel(new BorderLayout());
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setViewportView(tree);
        panel.add(scrollPane, BorderLayout.CENTER);
       
        SearchTextField searchField = new SearchTextField(tree);
        panel.add(searchField, BorderLayout.SOUTH);
       
        return panel;
    }
   
   
    /**
     * Used by getJOptionPaneIcon().
     * Cache from message type (JOptionPane int constant representing message type)
     * to icon representing that message type.
     */
    private static final Map<Integer, Icon> jOptionPaneMessageTypeToIconMap = new HashMap<Integer, Icon>();
   
    /**
     * Get the icon used in the JOptionPane to signify its message type.
     * Note that this is almost the same as a call to something like: UIManager.getIcon("OptionPane.questionIcon")
     *  but that doesn't work on GTK look-and-feel since there is no corresponding entry in its laf defaults map.
     * 
     * @param jOptionPaneMessageType One of the message types constants defined in the javax.swing.JOptionPane class.
     * @return the corresponding icon, or null if the icon is undefined for the provided message type.
     */
    public static Icon getJOptionPaneIcon(int jOptionPaneMessageType) {
        /*
         * HACK - workaround for GTK.
         * We create a new JOptionPane, get its UI (which should be a BasicOptionPaneUI), then call BasicOptionPaneUI.getIconForType().
         * GTK uses SynthOptionPaneUI (which is package protected), which eventually defers to SynthDefaultLookup to look
         * up default values for ui items such as icons.
         * However using this with non-Synth UIs causes lookup to defer to the basic (non-synth) lookup scheme.
         * Since we can't instantiate SynthOptionPaneUI (which is the SynthUI that we want) we are stuck calling the protected
         * method getIconForType() reflectively after unprotecting it.
         */

        Integer messageTypeInteger = new Integer(jOptionPaneMessageType);

        Icon icon = jOptionPaneMessageTypeToIconMap.get(messageTypeInteger);

        if (icon == null) {

            // Get the icon from a new JOptionPane's UI.
            OptionPaneUI ui = (new JOptionPane()).getUI();
           
            // The code below only works for BasicOptionPaneUIs.
            if (!(ui instanceof BasicOptionPaneUI)) {
                ui = new BasicOptionPaneUI();
               
                // Have to use a UI with a JOptionPane for it to initialize its icons.
                JOptionPane optionPane = new JOptionPane();
                optionPane.setUI(ui);
            }
           
            BasicOptionPaneUI optionPaneUI = (BasicOptionPaneUI)ui;

            try {
                Method method = BasicOptionPaneUI.class.getDeclaredMethod("getIconForType", new Class[] {int.class}); //$NON-NLS-1$
                boolean oldAccessible = method.isAccessible();
                method.setAccessible(true);
                try {
                    icon = (Icon)method.invoke(optionPaneUI, new Object[] {new Integer(jOptionPaneMessageType)});
                } finally {
                    method.setAccessible(oldAccessible);
                }

            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }

            jOptionPaneMessageTypeToIconMap.put(messageTypeInteger, icon);
        }

        return icon;
    }

}
TOP

Related Classes of org.openquark.util.ui.UIUtilities

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.