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

org.pushingpixels.radiance.component.internal.ui.ribbon.BasicRibbonComponentUI Maven / Gradle / Ivy

/*
 * Copyright (c) 2005-2021 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.radiance.component.internal.ui.ribbon;

import org.pushingpixels.radiance.component.api.common.HorizontalAlignment;
import org.pushingpixels.radiance.component.api.ribbon.JRibbonBand;
import org.pushingpixels.radiance.component.internal.utils.ComponentUtilities;
import org.jdesktop.swingx.icon.RadianceIcon;

import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeListener;

public abstract class BasicRibbonComponentUI extends RibbonComponentUI {
    /**
     * The associated ribbon component.
     */
    protected JRibbonComponent ribbonComponent;

    private JLabel captionLabel;

    private PropertyChangeListener propertyChangeListener;

    private PropertyChangeListener projectionPropertyChangeListener;

    @Override
    public void installUI(JComponent c) {
        this.ribbonComponent = (JRibbonComponent) c;
        installDefaults();
        installComponents();
        installListeners();
        c.setLayout(createLayoutManager());
    }

    @Override
    public void uninstallUI(JComponent c) {
        c.setLayout(null);
        uninstallListeners();
        uninstallDefaults();
        uninstallComponents();
    }

    /**
     * Installs default parameters on the associated ribbon component.
     */
    protected void installDefaults() {
        if (!this.ribbonComponent.isSimpleWrapper()) {
            RadianceIcon icon = this.ribbonComponent.getIcon();
            if (icon != null) {
                icon.setDimension(new Dimension(16, 16));
            }
        }

        this.ribbonComponent.getMainComponent().setOpaque(false);
        this.ribbonComponent.setOpaque(false);
    }

    /**
     * Installs subcomponents on the associated ribbon component.
     */
    protected void installComponents() {
        this.captionLabel = new JLabel(this.ribbonComponent.getCaption());
        this.captionLabel.setEnabled(this.ribbonComponent.isEnabled());
        this.ribbonComponent.add(this.captionLabel);

        JComponent mainComponent = this.ribbonComponent.getMainComponent();
        this.ribbonComponent.add(mainComponent);

        this.propagateEnabled(this.ribbonComponent.isEnabled());
    }

    /**
     * Installs listeners on the associated ribbon component.
     */
    protected void installListeners() {
        this.propertyChangeListener = propertyChangeEvent -> {
            if ("enabled".equals(propertyChangeEvent.getPropertyName())) {
                propagateEnabled((Boolean) propertyChangeEvent.getNewValue());
            }
            if ("caption".equals(propertyChangeEvent.getPropertyName())) {
                captionLabel.setText((String) propertyChangeEvent.getNewValue());
                ribbonComponent.revalidate();
                ribbonComponent.doLayout();
            }
            if ("icon".equals(propertyChangeEvent.getPropertyName())) {
                RadianceIcon newIcon = (RadianceIcon) propertyChangeEvent.getNewValue();
                if (newIcon != null) {
                    newIcon.setDimension(new Dimension(16, 16));
                }

                ribbonComponent.revalidate();
                ribbonComponent.doLayout();
            }
            if ("presentationPriority".equals(propertyChangeEvent.getPropertyName())) {
                ribbonComponent.revalidate();
                ribbonComponent.doLayout();
            }
        };
        this.ribbonComponent.addPropertyChangeListener(this.propertyChangeListener);

        this.projectionPropertyChangeListener = propertyChangeEvent -> {
            if ("enabled".equals(propertyChangeEvent.getPropertyName())) {
                propagateEnabled((Boolean) propertyChangeEvent.getNewValue());
            }
        };
        this.ribbonComponent.getProjection().getContentModel().addPropertyChangeListener(
                this.projectionPropertyChangeListener);
    }

    /**
     * Uninstalls default parameters from the associated ribbon component.
     */
    protected void uninstallDefaults() {
    }

    /**
     * Uninstalls components from the associated ribbon component.
     */
    protected void uninstallComponents() {
        JComponent mainComponent = this.ribbonComponent.getMainComponent();
        this.ribbonComponent.remove(mainComponent);

        this.ribbonComponent.remove(this.captionLabel);
        this.captionLabel = null;
    }

    /**
     * Uninstalls listeners from the associated ribbon component.
     */
    protected void uninstallListeners() {
        this.ribbonComponent.removePropertyChangeListener(this.propertyChangeListener);
        this.propertyChangeListener = null;

        this.ribbonComponent.getProjection().getContentModel().removePropertyChangeListener(
                this.projectionPropertyChangeListener);
        this.projectionPropertyChangeListener = null;
    }

    private void propagateEnabled(boolean enabled) {
        this.ribbonComponent.getMainComponent().setEnabled(enabled);
        if (!this.ribbonComponent.isSimpleWrapper()) {
            this.captionLabel.setEnabled(enabled);
        }
        this.ribbonComponent.repaint();
    }

    @Override
    public Point getKeyTipAnchorCenterPoint() {
        int smallIconSize = ComponentUtilities.getCommandButtonSmallIconSize(
                this.ribbonComponent.getFont().getSize());
        int tipCenterY = (this.ribbonComponent.getHeight() + smallIconSize) / 2;
        String caption = this.ribbonComponent.getCaption();
        boolean hasCaption = (caption != null) && (caption.length() > 0);
        if (hasCaption) {
            return new Point(this.captionLabel.getX(), tipCenterY);
        } else {
            return new Point(this.ribbonComponent.getMainComponent().getX() +
                    this.ribbonComponent.getMainComponent().getWidth() / 2, tipCenterY);
        }
    }

    protected LayoutManager createLayoutManager() {
        return new ExtComponentLayout();
    }

    protected class ExtComponentLayout implements LayoutManager {
        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            Insets ins = ribbonComponent.getInsets();
            JComponent mainComponent = ribbonComponent.getMainComponent();
            Dimension minMain = mainComponent.getMinimumSize();

            int width = ins.left;
            int height = minMain.height;
            if (isIconVisible(ribbonComponent.getPresentationPriority())) {
                RadianceIcon icon = ribbonComponent.getIcon();
                if (icon != null) {
                    width += (icon.getIconWidth() + getLayoutGap());
                    height = Math.max(height, icon.getIconHeight());
                }
            }
            if (isCaptionVisible(ribbonComponent.getPresentationPriority())) {
                Dimension minCaption = captionLabel.getMinimumSize();
                width += (minCaption.width + getLayoutGap());
                height = Math.max(height, minCaption.height);
            }
            width += minMain.width;
            width += ins.right;
            height += (ins.top + ins.bottom);

            return new Dimension(width, height);
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            return getPreferredSize(ribbonComponent.getPresentationPriority());
        }

        @Override
        public void layoutContainer(Container parent) {
            JRibbonComponent ribbonComp = (JRibbonComponent) parent;
            Insets ins = ribbonComp.getInsets();
            int gap = getLayoutGap();
            int availableHeight = ribbonComp.getHeight() - ins.top - ins.bottom;
            int availableWidth = ribbonComp.getWidth() - ins.left - ins.right;

            HorizontalAlignment horizAlignment = ribbonComp.getHorizontalAlignment();
            JComponent mainComp = ribbonComp.getMainComponent();
            Dimension prefMainDim = mainComp.getPreferredSize();
            int prefMainWidth = prefMainDim.width;
            int finalHeight = Math.min(prefMainDim.height, availableHeight);
            boolean ltr = ribbonComp.getComponentOrientation().isLeftToRight();

            if (ribbonComp.isSimpleWrapper()) {
                int finalMainWidth = Math.min(availableWidth, prefMainWidth);
                int offset = availableWidth - prefMainWidth;
                int topMain = ins.top + (availableHeight - finalHeight) / 2;
                int x = ltr ? ins.left : ribbonComp.getWidth() - ins.right;
                switch (horizAlignment) {
                    case LEADING:
                        if (ltr) {
                            mainComp.setBounds(x, topMain, finalMainWidth, finalHeight);
                        } else {
                            mainComp.setBounds(x - finalMainWidth, topMain, finalMainWidth,
                                    finalHeight);
                        }
                        break;
                    case TRAILING:
                        if (ltr) {
                            mainComp.setBounds(x + offset, topMain, finalMainWidth, finalHeight);
                        } else {
                            mainComp.setBounds(x - finalMainWidth - offset, topMain, finalMainWidth,
                                    finalHeight);
                        }
                        break;
                    case CENTER:
                        if (ltr) {
                            mainComp.setBounds(x + offset / 2, topMain, finalMainWidth,
                                    finalHeight);
                        } else {
                            mainComp.setBounds(x - finalMainWidth - offset / 2, topMain,
                                    finalMainWidth,
                                    finalHeight);
                        }
                        break;
                    case FILL:
                        if (ltr) {
                            mainComp.setBounds(x, topMain, availableWidth, finalHeight);
                        } else {
                            mainComp.setBounds(x - availableWidth, topMain, availableWidth,
                                    finalHeight);
                        }
                        break;
                }
                mainComp.doLayout();
            } else {
                int x = ltr ? ins.left : ribbonComp.getWidth() - ins.right;
                if (isIconVisible(ribbonComponent.getPresentationPriority())) {
                    if (ribbonComp.getIcon() != null) {
                        // icon is painted separately
                        int iconW = ribbonComp.getIcon().getIconWidth();
                        x = ltr ? x + iconW + gap : x - iconW - gap;
                    }
                }

                if (isCaptionVisible(ribbonComponent.getPresentationPriority())) {
                    captionLabel.setVisible(true);
                    Dimension prefCaptionDim = captionLabel.getPreferredSize();
                    if (ltr) {
                        captionLabel.setBounds(x,
                                ins.top + (availableHeight - prefCaptionDim.height) / 2,
                                prefCaptionDim.width, prefCaptionDim.height);
                        x += (prefCaptionDim.width + gap);
                    } else {
                        captionLabel.setBounds(x - prefCaptionDim.width,
                                ins.top + (availableHeight - prefCaptionDim.height) / 2,
                                prefCaptionDim.width, prefCaptionDim.height);
                        x -= (prefCaptionDim.width + gap);
                    }
                } else {
                    captionLabel.setVisible(false);
                }

                int topMain = ins.top + (availableHeight - finalHeight) / 2;
                int finalMainWidth = ltr
                        ? Math.min(ribbonComp.getWidth() - ins.right - x, prefMainWidth)
                        : Math.min(x - ins.left, prefMainWidth);
                int offset = ltr ? ribbonComp.getWidth() - ins.right - x - prefMainWidth
                        : x - prefMainWidth - ins.left;

                switch (horizAlignment) {
                    case LEADING:
                        if (ltr) {
                            mainComp.setBounds(x, topMain, finalMainWidth, finalHeight);
                        } else {
                            mainComp.setBounds(x - finalMainWidth, topMain, finalMainWidth,
                                    finalHeight);
                        }
                        break;
                    case TRAILING:
                        if (ltr) {
                            mainComp.setBounds(x + offset, topMain, finalMainWidth, finalHeight);
                        } else {
                            mainComp.setBounds(x - finalMainWidth - offset, topMain, finalMainWidth,
                                    finalHeight);
                        }
                        break;
                    case CENTER:
                        if (ltr) {
                            mainComp.setBounds(x + offset / 2, topMain, finalMainWidth,
                                    finalHeight);
                        } else {
                            mainComp.setBounds(x - finalMainWidth - offset / 2, topMain,
                                    finalMainWidth,
                                    finalHeight);
                        }
                        break;
                    case FILL:
                        if (ltr) {
                            mainComp.setBounds(x, topMain, ribbonComp.getWidth() - ins.right - x,
                                    finalHeight);
                        } else {
                            mainComp.setBounds(ins.left, topMain, x - ins.left, finalHeight);
                        }
                        break;
                }
                mainComp.doLayout();
            }
        }
    }

    @Override
    public void paint(Graphics g, JComponent c) {
        Graphics2D graphics = (Graphics2D) g.create();

        JRibbonComponent ribbonComp = (JRibbonComponent) c;
        if (isIconVisible(this.ribbonComponent.getPresentationPriority())) {
            Insets ins = ribbonComp.getInsets();
            RadianceIcon icon = ribbonComp.getIcon();
            if (icon != null) {
                int availableHeight = ribbonComp.getHeight() - ins.top - ins.bottom;
                int iconY = Math.max(0, ins.top + (availableHeight - icon.getIconHeight()) / 2);
                if (ribbonComp.getComponentOrientation().isLeftToRight()) {
                    paintIcon(graphics, ribbonComp, icon, ins.left, iconY);
                } else {
                    paintIcon(graphics, ribbonComp, icon,
                            ribbonComp.getWidth() - ins.right - icon.getIconWidth(), iconY);
                }
            }
        }

        graphics.dispose();
    }

    protected abstract void paintIcon(Graphics g, JRibbonComponent ribbonComp, Icon icon, int x, int y);

    private int getLayoutGap() {
        return 4;
    }

    private boolean isIconVisible(JRibbonBand.PresentationPriority presentationPriority) {
        if (this.ribbonComponent.isSimpleWrapper()) {
            return false;
        }
        return (presentationPriority == JRibbonBand.PresentationPriority.TOP)
                || (presentationPriority == JRibbonBand.PresentationPriority.MEDIUM);
    }

    private boolean isCaptionVisible(JRibbonBand.PresentationPriority presentationPriority) {
        if (this.ribbonComponent.isSimpleWrapper()) {
            return false;
        }
        return (presentationPriority == JRibbonBand.PresentationPriority.TOP);
    }

    @Override
    public Dimension getPreferredSize(JRibbonBand.PresentationPriority priority) {
        Insets ins = ribbonComponent.getInsets();
        JComponent mainComponent = ribbonComponent.getMainComponent();
        Dimension prefMain = mainComponent.getPreferredSize();

        int width = ins.left;
        int height = prefMain.height;
        if (isIconVisible(priority)) {
            RadianceIcon icon = ribbonComponent.getIcon();
            if (icon != null) {
                width += (icon.getIconWidth() + getLayoutGap());
                height = Math.max(height, icon.getIconHeight());
            }
        }
        if (isCaptionVisible(priority)) {
            Dimension prefCaption = captionLabel.getPreferredSize();
            width += (prefCaption.width + getLayoutGap());
            height = Math.max(height, prefCaption.height);
        }
        width += prefMain.width;
        width += ins.right;
        height += (ins.top + ins.bottom);

        return new Dimension(width, height);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy