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

org.gephi.ui.components.richtooltip.BasicRichTooltipPanelUI Maven / Gradle / Ivy

/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian 
Website : http://www.gephi.org

This file is part of Gephi.

DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.

Copyright 2011 Gephi Consortium. All rights reserved.

The contents of this file are subject to the terms of either the GNU
General Public License Version 3 only ("GPL") or the Common
Development and Distribution License("CDDL") (collectively, the
"License"). You may not use this file except in compliance with the
License. You can obtain a copy of the License at
http://gephi.org/about/legal/license-notice/
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
specific language governing permissions and limitations under the
License.  When distributing the software, include this License Header
Notice in each file and include the License files at
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
License Header, with the fields enclosed by brackets [] replaced by
your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"

If you wish your version of this file to be governed by only the CDDL
or only the GPL Version 3, indicate your decision by adding
"[Contributor] elects to include this software in this distribution
under the [CDDL or GPL Version 3] license." If you do not indicate a
single choice of license, a recipient has the option to distribute
your version of this file under either the CDDL, the GPL Version 3 or
to extend the choice of license to its licensees as provided above.
However, if you add GPL Version 3 code and therefore, elected the GPL
Version 3 license, then the option applies only if the new code is
made subject to such option by the copyright holder.

Contributor(s):

Portions Copyrighted 2011 Gephi Consortium.
*/

package org.gephi.ui.components.richtooltip;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.text.AttributedString;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JSeparator;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import org.pushingpixels.flamingo.internal.utils.FlamingoUtilities;

/**
 * @author Mathieu Bastian
 */
class BasicRichTooltipPanelUI extends RichTooltipPanelUI {
    /**
     * The associated tooltip panel.
     */
    protected JRichTooltipPanel richTooltipPanel;

    protected JLabel titleLabel;

    protected java.util.List descriptionLabels;

    protected JLabel mainImageLabel;

    protected JSeparator footerSeparator;

    protected JLabel footerImageLabel;

    protected java.util.List footerLabels;

    public BasicRichTooltipPanelUI() {
        this.descriptionLabels = new ArrayList<>();
        this.footerLabels = new ArrayList<>();
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
     */
    public static ComponentUI createUI(JComponent c) {
        return new BasicRichTooltipPanelUI();
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.swing.plaf.ComponentUI#installUI(javax.swing.JComponent)
     */
    @Override
    public void installUI(JComponent c) {
        this.richTooltipPanel = (JRichTooltipPanel) c;
        super.installUI(this.richTooltipPanel);
        installDefaults();
        installComponents();
        installListeners();

        this.richTooltipPanel.setLayout(createLayoutManager());
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.swing.plaf.ComponentUI#uninstallUI(javax.swing.JComponent)
     */
    @Override
    public void uninstallUI(JComponent c) {
        uninstallListeners();
        uninstallComponents();
        uninstallDefaults();
        super.uninstallUI(this.richTooltipPanel);
    }

    /**
     * Installs default settings for the associated rich tooltip panel.
     */
    protected void installDefaults() {
        Border b = this.richTooltipPanel.getBorder();
        if (b == null || b instanceof UIResource) {
            Border toSet = UIManager.getBorder("RichTooltipPanel.border");
            if (toSet == null) {
                toSet = new BorderUIResource.CompoundBorderUIResource(
                    new LineBorder(FlamingoUtilities.getBorderColor()),
                    new EmptyBorder(2, 4, 3, 4));
            }
            this.richTooltipPanel.setBorder(toSet);
        }
        LookAndFeel.installProperty(this.richTooltipPanel, "opaque",
            Boolean.TRUE);
    }

    /**
     * Installs listeners on the associated rich tooltip panel.
     */
    protected void installListeners() {
    }

    /**
     * Installs components on the associated rich tooltip panel.
     */
    protected void installComponents() {
    }

    /**
     * Uninstalls default settings from the associated rich tooltip panel.
     */
    protected void uninstallDefaults() {
        LookAndFeel.uninstallBorder(this.richTooltipPanel);
    }

    /**
     * Uninstalls listeners from the associated rich tooltip panel.
     */
    protected void uninstallListeners() {
    }

    /**
     * Uninstalls subcomponents from the associated rich tooltip panel.
     */
    protected void uninstallComponents() {
        this.removeExistingComponents();
    }

    @Override
    public void update(Graphics g, JComponent c) {
        this.paintBackground(g);
        this.paint(g, c);
    }

    protected void paintBackground(Graphics g) {
        Color main = FlamingoUtilities.getColor(Color.gray,
            "Label.disabledForeground").brighter();
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setPaint(new GradientPaint(0, 0, FlamingoUtilities.getLighterColor(
            main, 0.9), 0, this.richTooltipPanel.getHeight(),
            FlamingoUtilities.getLighterColor(main, 0.4)));
        g2d.fillRect(0, 0, this.richTooltipPanel.getWidth(),
            this.richTooltipPanel.getHeight());
        g2d.setFont(FlamingoUtilities.getFont(this.richTooltipPanel,
            "Ribbon.font", "Button.font", "Panel.font"));
        g2d.dispose();
    }

    @Override
    public void paint(Graphics g, JComponent c) {
    }

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

    protected int getDescriptionTextWidth() {
        return 200;
    }

    protected int getLayoutGap() {
        return 4;
    }

    protected void removeExistingComponents() {
        if (this.titleLabel != null) {
            this.richTooltipPanel.remove(this.titleLabel);
        }
        if (this.mainImageLabel != null) {
            this.richTooltipPanel.remove(this.mainImageLabel);
        }
        for (JLabel label : this.descriptionLabels) {
            this.richTooltipPanel.remove(label);
        }
        if (this.footerSeparator != null) {
            this.richTooltipPanel.remove(this.footerSeparator);
        }
        if (this.footerImageLabel != null) {
            this.richTooltipPanel.remove(this.footerImageLabel);
        }
        for (JLabel label : this.footerLabels) {
            this.richTooltipPanel.remove(label);
        }
    }

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

        @Override
        public void removeLayoutComponent(Component comp) {
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return this.preferredLayoutSize(parent);
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            Insets ins = parent.getInsets();
            int gap = getLayoutGap();
            Font font = FlamingoUtilities.getFont(parent, "Ribbon.font",
                "Button.font", "Panel.font");

            // the main text gets 200 pixels. The width is defined
            // by this and the presence of the main text.
            // The height is defined based on the width and the
            // text broken into multiline paragraphs

            int descTextWidth = getDescriptionTextWidth();
            int width = ins.left + 2 * gap + descTextWidth + ins.right;
            RichTooltip tooltipInfo = richTooltipPanel.getTooltipInfo();
            FontRenderContext frc = new FontRenderContext(
                new AffineTransform(), true, false);
            if (tooltipInfo.getMainImage() != null) {
                width += tooltipInfo.getMainImage().getWidth(null);
            }

            int fontHeight = parent.getFontMetrics(font).getHeight();

            int height = ins.top;

            // The title label
            height += fontHeight + gap;

            // The description text
            int descriptionTextHeight = 0;
            for (String descText : tooltipInfo.getDescriptionSections()) {
                AttributedString attributedDescription = new AttributedString(
                    descText);
                attributedDescription.addAttribute(TextAttribute.FONT, font);
                LineBreakMeasurer lineBreakMeasurer = new LineBreakMeasurer(
                    attributedDescription.getIterator(), frc);
                while (true) {
                    TextLayout tl = lineBreakMeasurer.nextLayout(descTextWidth);
                    if (tl == null) {
                        break;
                    }
                    descriptionTextHeight += fontHeight;
                }
                // add an empty line after the paragraph
                descriptionTextHeight += fontHeight;
            }
            // remove the empty line after the last paragraph
            descriptionTextHeight -= fontHeight;

            if (tooltipInfo.getMainImage() != null) {
                height += Math.max(descriptionTextHeight, new JLabel(
                    new ImageIcon(tooltipInfo.getMainImage()))
                    .getPreferredSize().height);
            } else {
                height += descriptionTextHeight;
            }

            if ((tooltipInfo.getFooterImage() != null)
                || (tooltipInfo.getFooterSections().size() > 0)) {
                height += gap;
                // The footer separator
                height += new JSeparator(JSeparator.HORIZONTAL)
                    .getPreferredSize().height;

                height += gap;

                int footerTextHeight = 0;
                int availableWidth = descTextWidth;
                if (tooltipInfo.getFooterImage() != null) {
                    availableWidth -= tooltipInfo.getFooterImage().getWidth(
                        null);
                }
                if (tooltipInfo.getMainImage() != null) {
                    availableWidth += tooltipInfo.getMainImage().getWidth(null);
                }
                for (String footerText : tooltipInfo.getFooterSections()) {
                    AttributedString attributedDescription = new AttributedString(
                        footerText);
                    attributedDescription
                        .addAttribute(TextAttribute.FONT, font);
                    LineBreakMeasurer lineBreakMeasurer = new LineBreakMeasurer(
                        attributedDescription.getIterator(), frc);
                    while (true) {
                        TextLayout tl = lineBreakMeasurer
                            .nextLayout(availableWidth);
                        if (tl == null) {
                            break;
                        }
                        footerTextHeight += fontHeight;
                    }
                    // add an empty line after the paragraph
                    footerTextHeight += fontHeight;
                }
                // remove the empty line after the last paragraph
                footerTextHeight -= fontHeight;

                if (tooltipInfo.getFooterImage() != null) {
                    height += Math.max(footerTextHeight, new JLabel(
                        new ImageIcon(tooltipInfo.getFooterImage()))
                        .getPreferredSize().height);
                } else {
                    height += footerTextHeight;
                }
            }

            height += ins.bottom;
            return new Dimension(width, height);
        }

        @Override
        public void layoutContainer(Container parent) {
            if (parent.getWidth() <= 1) {
                // Prevent further ArrayIndexOutOfBoundsException in some cases
                return;
            }
            removeExistingComponents();

            Font font = FlamingoUtilities.getFont(parent, "Ribbon.font",
                "Button.font", "Panel.font");
            Insets ins = richTooltipPanel.getInsets();
            int y = ins.top;
            RichTooltip tooltipInfo = richTooltipPanel.getTooltipInfo();
            FontRenderContext frc = new FontRenderContext(
                new AffineTransform(), true, false);
            int gap = getLayoutGap();

            int fontHeight = parent.getFontMetrics(font).getHeight();

            // The title label
            titleLabel = new JLabel(tooltipInfo.getTitle());
            titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD));
            richTooltipPanel.add(titleLabel);

            titleLabel.setBounds(ins.left, y,
                titleLabel.getPreferredSize().width, fontHeight);
            y += titleLabel.getHeight() + gap;

            // The main image
            int x = ins.left;
            if (tooltipInfo.getMainImage() != null) {
                mainImageLabel = new JLabel(new ImageIcon(tooltipInfo
                    .getMainImage()));
                richTooltipPanel.add(mainImageLabel);
                mainImageLabel.setBounds(x, y, mainImageLabel
                    .getPreferredSize().width, mainImageLabel
                    .getPreferredSize().height);
                x += mainImageLabel.getWidth();
            }
            x += 2 * gap;

            // The description text
            int descLabelWidth = parent.getWidth() - x - ins.right;
            for (String descText : tooltipInfo.getDescriptionSections()) {
                AttributedString attributedDescription = new AttributedString(
                    descText);
                attributedDescription.addAttribute(TextAttribute.FONT, font);
                LineBreakMeasurer lineBreakMeasurer = new LineBreakMeasurer(
                    attributedDescription.getIterator(), frc);
                int currOffset = 0;
                while (true) {
                    TextLayout tl = lineBreakMeasurer
                        .nextLayout(descLabelWidth);
                    if (tl == null) {
                        break;
                    }
                    int charCount = tl.getCharacterCount();
                    String line = descText.substring(currOffset, currOffset
                        + charCount);

                    JLabel descLabel = new JLabel(line);
                    descriptionLabels.add(descLabel);
                    richTooltipPanel.add(descLabel);
                    descLabel.setBounds(x, y,
                        descLabel.getPreferredSize().width, fontHeight);
                    y += descLabel.getHeight();

                    currOffset += charCount;
                }
                // add an empty line after the paragraph
                y += titleLabel.getHeight();
            }
            // remove the empty line after the last paragraph
            y -= titleLabel.getHeight();

            if (mainImageLabel != null) {
                y = Math.max(y, mainImageLabel.getY()
                    + mainImageLabel.getHeight());
            }

            if ((tooltipInfo.getFooterImage() != null)
                || (tooltipInfo.getFooterSections().size() > 0)) {
                y += gap;
                // The footer separator
                footerSeparator = new JSeparator(JSeparator.HORIZONTAL);
                richTooltipPanel.add(footerSeparator);
                footerSeparator.setBounds(ins.left, y, parent.getWidth()
                    - ins.left - ins.right, footerSeparator
                    .getPreferredSize().height);

                y += footerSeparator.getHeight() + gap;

                // The footer image
                x = ins.left;
                if (tooltipInfo.getFooterImage() != null) {
                    footerImageLabel = new JLabel(new ImageIcon(tooltipInfo
                        .getFooterImage()));
                    richTooltipPanel.add(footerImageLabel);
                    footerImageLabel.setBounds(x, y, footerImageLabel
                        .getPreferredSize().width, footerImageLabel
                        .getPreferredSize().height);
                    x += footerImageLabel.getWidth() + 2 * gap;
                }

                // The footer text
                int footerLabelWidth = parent.getWidth() - x - ins.right;
                for (String footerText : tooltipInfo.getFooterSections()) {
                    AttributedString attributedDescription = new AttributedString(
                        footerText);
                    attributedDescription
                        .addAttribute(TextAttribute.FONT, font);
                    LineBreakMeasurer lineBreakMeasurer = new LineBreakMeasurer(
                        attributedDescription.getIterator(), frc);
                    int currOffset = 0;
                    while (true) {
                        TextLayout tl = lineBreakMeasurer
                            .nextLayout(footerLabelWidth);
                        if (tl == null) {
                            break;
                        }
                        int charCount = tl.getCharacterCount();
                        String line = footerText.substring(currOffset,
                            currOffset + charCount);

                        JLabel footerLabel = new JLabel(line);
                        footerLabels.add(footerLabel);
                        richTooltipPanel.add(footerLabel);
                        footerLabel.setBounds(x, y, footerLabel
                            .getPreferredSize().width, fontHeight);
                        y += footerLabel.getHeight();

                        currOffset += charCount;
                    }
                    // add an empty line after the paragraph
                    y += titleLabel.getHeight();
                }
                // remove the empty line after the last paragraph
                y -= titleLabel.getHeight();
            }
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy