All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pushingpixels.substance.internal.utils.WidgetUtilities Maven / Gradle / Ivy

There is a newer version: 4.5.0
Show newest version
/*
 * Copyright (c) 2005-2020 Radiance Kirill Grouchnikov. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  o Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  o 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.
 *
 *  o Neither the name of the copyright holder 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.
 */
package org.pushingpixels.substance.internal.utils;

import org.pushingpixels.substance.api.SubstanceSlices.AnimationFacet;
import org.pushingpixels.substance.api.painter.preview.PreviewPainter;
import org.pushingpixels.substance.api.password.PasswordStrengthChecker;
import org.pushingpixels.substance.internal.AnimationConfigurationManager;
import org.pushingpixels.substance.internal.SubstanceSynapse;

import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;

/**
 * Various utility functions.
 * 
 * @author Kirill Grouchnikov
 * @author Romain Guy
 */
public class WidgetUtilities {
    /**
     * Name for the internal client property that marks a component as previewable.
     */
    public static final String PREVIEW_MODE = "substance.widget.internal.previewMode";

    /**
     * Private constructor. Is here to enforce using static methods only.
     */
    private WidgetUtilities() {
    }

    /**
     * Makes the specified component and all its descendants previewable.
     * 
     * @param comp
     *            Component.
     * @param dbSnapshot
     *            The "snapshot" map that will contain the original double-buffer status of the
     *            specified component and all its descendants. Key is {@link JComponent}, value is
     *            {@link Boolean}.
     */
    public static void makePreviewable(Component comp, Map dbSnapshot) {
        if (comp instanceof JComponent) {
            JComponent jcomp = (JComponent) comp;
            // if (jcomp.getParent() instanceof CellRendererPane) {
            // System.out.println(jcomp.getClass().getSimpleName() + ":"
            // + jcomp.hashCode());
            // }
            dbSnapshot.put(jcomp, Boolean.valueOf(jcomp.isDoubleBuffered()));
            jcomp.setDoubleBuffered(false);
            jcomp.putClientProperty(WidgetUtilities.PREVIEW_MODE, Boolean.TRUE);
        }
        if (comp instanceof Container) {
            Container cont = (Container) comp;
            for (int i = 0; i < cont.getComponentCount(); i++) {
                WidgetUtilities.makePreviewable(cont.getComponent(i), dbSnapshot);
            }
        }
    }

    /**
     * Restores the regular (non-previewable) status of the specified component and all its
     * descendants.
     * 
     * @param comp
     *            Component.
     * @param dbSnapshot
     *            The "snapshot" map that contains the original double-buffer status of the
     *            specified component and all its descendants. Key is {@link JComponent}, value is
     *            {@link Boolean}.
     */
    public static void restorePreviewable(Component comp, Map dbSnapshot) {
        if (comp instanceof JComponent) {
            JComponent jcomp = (JComponent) comp;
            if (dbSnapshot.containsKey(comp)) {
                jcomp.setDoubleBuffered(dbSnapshot.get(comp));
                jcomp.putClientProperty(WidgetUtilities.PREVIEW_MODE, null);
            } else {
                // this can happen in case the application has
                // renderers (combos, ...). Take the property from the parent
                Component parent = comp.getParent();
                if (parent instanceof JComponent) {
                    jcomp.setDoubleBuffered(dbSnapshot.get(parent));
                    jcomp.putClientProperty(WidgetUtilities.PREVIEW_MODE, null);
                }
                // System.out.println("Not found");
                // Component c = jcomp;
                // while (c != null) {
                // System.out.println("\t" + c.getClass().getSimpleName()
                // + ":" + c.hashCode());
                // c = c.getParent();
                // }
            }
        }
        if (comp instanceof Container) {
            Container cont = (Container) comp;
            for (int i = 0; i < cont.getComponentCount(); i++) {
                WidgetUtilities.restorePreviewable(cont.getComponent(i), dbSnapshot);
            }
        }
    }

    /**
     * Checks whether the specified text component has "select all on focus gain" property.
     * 
     * @param textComp
     *            Text component.
     * @return true if the specified text component has "select all on focus gain"
     *         property, false otherwise.
     */
    public static boolean hasTextFocusSelectAllProperty(JTextComponent textComp) {
        Component comp = textComp;
        while (comp != null) {
            if (comp instanceof JComponent) {
                Object textFocusSelectAllProperty = ((JComponent) comp)
                        .getClientProperty(SubstanceSynapse.TEXT_SELECT_ON_FOCUS);
                if (Boolean.TRUE.equals(textFocusSelectAllProperty)) {
                    return true;
                }
                if (Boolean.FALSE.equals(textFocusSelectAllProperty)) {
                    return false;
                }
            }
            comp = comp.getParent();
        }
        return (Boolean.TRUE.equals(UIManager.get(SubstanceSynapse.TEXT_SELECT_ON_FOCUS)));
    }

    /**
     * Checks whether the specified text component has "flip select on escape" property.
     * 
     * @param textComp
     *            Text component.
     * @return true if the specified text component has "flip select on escape"
     *         property, false otherwise.
     */
    public static boolean hasTextFlipSelectOnEscapeProperty(JTextComponent textComp) {
        Object textFocusSelectAllProperty = textComp
                .getClientProperty(SubstanceSynapse.TEXT_FLIP_SELECT_ON_ESCAPE);
        return (Boolean.TRUE.equals(textFocusSelectAllProperty));
    }

    /**
     * Checks whether the specified text component has edit context menu property.
     * 
     * @param textComp
     *            Text component.
     * @return true if the specified text component has edit context menu property,
     *         false otherwise.
     */
    public static boolean hasTextEditContextMenu(JTextComponent textComp) {
        Object textEditContextMenuProperty = textComp
                .getClientProperty(SubstanceSynapse.TEXT_EDIT_CONTEXT_MENU);
        if (Boolean.TRUE.equals(textEditContextMenuProperty)) {
            return true;
        }
        if (Boolean.FALSE.equals(textEditContextMenuProperty)) {
            return false;
        }
        return (Boolean.TRUE.equals(UIManager.get(SubstanceSynapse.TEXT_EDIT_CONTEXT_MENU)));
    }

    /**
     * Checks whether the specified scroll pane supports auto scroll.
     * 
     * @param scrollPane
     *            Scroll pane component.
     * @return true if the specified scroll pane supports auto scroll,
     *         false otherwise.
     */
    public static boolean hasAutoScroll(JScrollPane scrollPane) {
        Object compProperty = scrollPane.getClientProperty(SubstanceSynapse.AUTO_SCROLL);
        if (Boolean.TRUE.equals(compProperty)) {
            return true;
        }
        if (Boolean.FALSE.equals(compProperty)) {
            return false;
        }
        return (Boolean.TRUE.equals(UIManager.get(SubstanceSynapse.AUTO_SCROLL)));
    }

    /**
     * Checks whether the specified tree component has automatic drag and drop support.
     * 
     * @param tree
     *            Tree component.
     * @return true if the specified text component has automatic drag and drop
     *         support, false otherwise.
     */
    public static boolean hasAutomaticDnDSupport(JTree tree) {
        Object dndProperty = tree.getClientProperty(SubstanceSynapse.TREE_AUTO_DND_SUPPORT);
        if (Boolean.TRUE.equals(dndProperty)) {
            return true;
        }
        if (Boolean.FALSE.equals(dndProperty)) {
            return false;
        }
        return (Boolean.TRUE.equals(UIManager.get(SubstanceSynapse.TREE_AUTO_DND_SUPPORT)));
    }

    /**
     * Checks whether the specified component has been configured (specifically or globally) to have
     * no animations of the specific facet. Can be used to cull unnecessary code in animation
     * listeners on large tables and lists.
     * 
     * @param comp
     *            Component.
     * @param animationFacet
     *            Animation facet.
     * @return true if the specified component has been configured (specifically or
     *         globally) to have no animations of the specific facet, false otherwise.
     */
    public static boolean hasNoAnimations(Component comp, AnimationFacet animationFacet) {
        return !AnimationConfigurationManager.getInstance().isAnimationAllowed(animationFacet,
                comp);
    }

    /**
     * Returns the current icon for the specified button. This method is for internal use
     * only.
     * 
     * @param b
     *            Button.
     * @return Icon for the specified button.
     */
    public static Icon getIcon(AbstractButton b) {
        Icon icon = b.getIcon();
        if (icon == null)
            return null;
        ButtonModel model = b.getModel();
        Icon tmpIcon = null;

        if (icon != null) {
            if (!model.isEnabled()) {
                if (model.isSelected()) {
                    tmpIcon = b.getDisabledSelectedIcon();
                } else {
                    tmpIcon = b.getDisabledIcon();
                }
            } else if (model.isPressed() && model.isArmed()) {
                tmpIcon = b.getPressedIcon();
            } else if (b.isRolloverEnabled() && model.isRollover()) {
                if (model.isSelected()) {
                    tmpIcon = b.getRolloverSelectedIcon();
                } else {
                    tmpIcon = b.getRolloverIcon();
                }
            } else if (model.isSelected()) {
                tmpIcon = b.getSelectedIcon();
            }

            if (tmpIcon != null) {
                icon = tmpIcon;
            }
        }
        return icon;
    }

    public static boolean toIgnoreAnimations(Component comp) {
        if (comp instanceof JMenuItem) {
            return false;
        }
        return (SwingUtilities.getAncestorOfClass(CellRendererPane.class, comp) != null);
    }

    /**
     * Fires the matching property change event on the specific component.
     * 
     * @param component
     *            Component.
     * @param propertyName
     *            Property name.
     * @param oldValue
     *            Old property value.
     * @param newValue
     *            New property value.
     */
    public static void firePropertyChangeEvent(JComponent component, String propertyName,
            Object oldValue, Object newValue) {
        PropertyChangeEvent pce = new PropertyChangeEvent(component, propertyName, oldValue,
                newValue);
        for (PropertyChangeListener general : component.getPropertyChangeListeners()) {
            general.propertyChange(pce);
        }
        for (PropertyChangeListener specific : component.getPropertyChangeListeners(propertyName)) {
            specific.propertyChange(pce);
        }
    }

    /**
     * Returns the composite to use for painting the specified component. The result should be set
     * on the {@link Graphics2D} before any custom rendering is done. This method can be used by
     * application painting code and by look-and-feel delegates.
     * 
     * @param c
     *            Component.
     * @param translucency
     *            The translucency of the original painting.
     * @param g
     *            The original graphics context.
     * @return The composite to use for painting the specified component.
     */
    public static Composite getAlphaComposite(Component c, float translucency, Graphics g) {
        float xFactor = 1.0f;
        if (g instanceof Graphics2D) {
            Graphics2D g2d = (Graphics2D) g;
            Composite existingComposite = g2d.getComposite();
            if (existingComposite instanceof AlphaComposite) {
                AlphaComposite ac = (AlphaComposite) existingComposite;
                if (ac.getRule() == AlphaComposite.SRC_OVER)
                    xFactor = ac.getAlpha();
            }
        }
        float finalAlpha = translucency * xFactor;
        if (finalAlpha < 0.0f) {
            finalAlpha = 0.0f;
        }
        if (finalAlpha > 1.0f) {
            finalAlpha = 1.0f;
        }
        if (finalAlpha == 1.0f) {
            return AlphaComposite.SrcOver;
        }
        return AlphaComposite.SrcOver.derive(finalAlpha);
    }

    public static Composite getAlphaComposite(Component c, float translucency) {
        return getAlphaComposite(c, translucency, null);
    }

    /**
     * Returns the composite to use for painting the specified component. The result should be set
     * on the {@link Graphics2D} before any custom rendering is done. This method can be used by
     * application painting code and by look-and-feel delegates.
     * 
     * @param c
     *            Component.
     * @return The composite to use for painting the specified component.
     */
    public static Composite getAlphaComposite(Component c, Graphics g) {
        return getAlphaComposite(c, 1.0f, g);
    }

    /**
     * Returns the composite to use for painting the specified component. The result should be set
     * on the {@link Graphics2D} before any custom rendering is done. This method can be used by
     * application painting code and by look-and-feel delegates.
     * 
     * @param c
     *            Component.
     * @return The composite to use for painting the specified component.
     */
    public static Composite getAlphaComposite(Component c) {
        return getAlphaComposite(c, 1.0f, null);
    }

    /**
     * Returns the preview painter for the specified component.
     * 
     * @param comp
     *            Component.
     * @return Preview painter for the specified component.
     */
    public static PreviewPainter getComponentPreviewPainter(Component comp) {
        if (comp == null) {
            return null;
        }

        // check property on component
        if (comp instanceof JComponent) {
            Object compProp = ((JComponent) comp)
                    .getClientProperty(SubstanceSynapse.COMPONENT_PREVIEW_PAINTER);
            if (compProp instanceof PreviewPainter) {
                return (PreviewPainter) compProp;
            }
        }

        // check property on parent
        Container parent = comp.getParent();
        if (parent instanceof JComponent) {
            Object parentProp = ((JComponent) parent)
                    .getClientProperty(SubstanceSynapse.COMPONENT_PREVIEW_PAINTER);
            if (parentProp instanceof PreviewPainter) {
                return (PreviewPainter) parentProp;
            }
        }

        Object globProp = UIManager.get(SubstanceSynapse.COMPONENT_PREVIEW_PAINTER);
        if (globProp instanceof PreviewPainter) {
            return (PreviewPainter) globProp;
        }

        return null;
    }

    /**
     * Returns the password strength checker for the specified password field.
     * 
     * @param jpf
     *            Password field.
     * @return Password strength checker for the specified password field. The result can be
     *         null.
     */
    public static PasswordStrengthChecker getPasswordStrengthChecker(JPasswordField jpf) {
        Object obj = jpf.getClientProperty(SubstanceSynapse.PASSWORD_STRENGTH_CHECKER);
        if (obj instanceof PasswordStrengthChecker) {
            return (PasswordStrengthChecker) obj;
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy