swingx-master/swingx-core/src/test/java/org/jdesktop/swingx/JXPanelVisualCheck.java
/*
 * $Id$
 *
 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package org.jdesktop.swingx;


import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Paint;
import java.awt.event.ActionEvent;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;

import org.jdesktop.swingx.action.AbstractActionExt;
import org.jdesktop.swingx.painter.ImagePainter;
import org.jdesktop.swingx.painter.MattePainter;
import org.jdesktop.swingx.test.XTestUtils;
import org.jdesktop.swingx.util.PaintUtils;

import com.sun.java.swing.Painter;

/**
 * Contains methods to visually test JXPanel.
 * 
 * @author Jeanette Winzenburg
 */
public class JXPanelVisualCheck extends InteractiveTestCase {

    public static void main(String args[]) {
        final JXPanelVisualCheck test = new JXPanelVisualCheck();
        setLAF("Nimbus");
//        UIManager.put("JXPanel.patch", Boolean.TRUE);
        try {

//             test.runInteractiveTests();
            test.runInteractiveTests("interactiveBackgroundAlphaToggleOpaque");
//            test.runInteractive("PanelPainter");
//             test.runInteractive("BackgroundAndAlphaCheck");
            // test.runInteractive("FrameArtefacts");

        } catch (Exception e) {
            System.err.println("exception when executing interactive tests:");
            e.printStackTrace();
        }
    }

    /**
     * Issue #1515-swingx: painting artefacts in a JXFrame (which uses JXPanel
     * as rootPane)
     * 
     * If the upper frame contains a JXPanel with alpha, the lower background is
     * painted only below the area of the upper frame. All fine without alpha on
     * the upper. The exact outcome is erractic (sometimes half or even fully
     * painted). On/off EDT doesn't seem to make a difference.
     */
    public void interactiveXPanelInFrameArtefacts() {
        JPanel panel = new JPanel();
        Color red = Color.RED;
        panel.setBackground(red);
        JXFrame frame = wrapInFrame(panel,
                "plain panel added to contentPane of a xframe");
        show(frame, 400, 400);

        JXPanel other = new JXPanel();
        other.setAlpha(.5f);
        JXFrame otherFrame = wrapInFrame(other,
                "xpanel with alpha, showing on top of first");
        show(otherFrame, 100, 100);
    }

    /**
     * Issue #1516-swingx: need feature to _not_ paint the background if alpha
     * and not-opaque
     * 
     * 
     */
    public void interactiveBackgroundAlphaToggleOpaque() {
        JPanel container = new JPanel(new GridLayout(0, 3));
        Color base = Color.RED;
        Color alpha = PaintUtils.setAlpha(base, 100);

        final JPanel p = new JPanel();
        p.setBorder(BorderFactory.createTitledBorder("core (alpha back)"));
        p.setBackground(alpha);
        final JLabel coreLabel = new JLabel("is-opaque: " + p.isOpaque());
        p.add(coreLabel);

        final JXPanel xp1 = new JXPanel();
        xp1.setBorder(BorderFactory.createTitledBorder("x (alpha back)"));
        xp1.setBackground(alpha);
        final JLabel xbackAlpha = new JLabel("is-opaque: " + xp1.isOpaque());
        xp1.add(xbackAlpha);

        final JXPanel xp2 = new JXPanel();
        xp2.setBorder(BorderFactory.createTitledBorder("x (alpha container)"));
        xp2.setBackground(base);
        xp2.setAlpha(100f / 255f);
        final JLabel xcontainerAlpha = new JLabel("is-opaque: "
                + xp2.isOpaque());
        xp2.add(xcontainerAlpha);

        container.add(p);
        container.add(xp1);
        container.add(xp2);

        JXFrame frame = wrapInFrame(container,
                "opaque with alpha " + System.getProperty("java.version") + " "
                        + UIManager.get("JXPanel.patch"));
        Action action = new AbstractAction("toggle opaque (is on)") {
            boolean realOpaque = true;

            @Override
            public void actionPerformed(ActionEvent e) {
                realOpaque = !realOpaque;

                putValue(Action.NAME, realOpaque ? "toggle opaque (is on)"
                        : "toggle opaque (is off)");

                p.setOpaque(realOpaque);
                xp1.setOpaque(realOpaque);
                xp2.setOpaque(realOpaque);

                coreLabel.setText("is-opaque: " + p.isOpaque());
                xbackAlpha.setText("is-opaque: " + xbackAlpha.isOpaque());
                xcontainerAlpha.setText("is-opaque: "
                        + xcontainerAlpha.isOpaque());
                p.repaint();
                xp1.repaint();
                xp2.repaint();
            }
        };
        addAction(frame, action);
        show(frame, 400, 400);
    }

    /**
     * Issue 1517-swingx: JXPanel - background color depends on opaqueness prior
     * to setting
     */
    public void interactiveBackgroundAlphaColorDependsOnOpaque() {
        JPanel container = new JPanel(new GridLayout(0, 2));
        Color alpha = PaintUtils.setAlpha(Color.RED, 100);

        JXPanel opaque = new JXPanel();
        opaque.setBorder(BorderFactory
                .createTitledBorder("xpanel (alpha color, real opaque)"));
        opaque.setBackground(alpha);

        JXPanel nonOpaque = new JXPanel();
        nonOpaque.setOpaque(false);
        nonOpaque.setBorder(BorderFactory
                .createTitledBorder("xpanel (alpha color, real !opaque)"));
        nonOpaque.setBackground(alpha);

        container.add(opaque);
        container.add(nonOpaque);
        show(wrapInFrame(container,
                "compare alpha background: opaque <-> not opaque"), 400, 400);
    }

    /**
     * Issue ??-swingx: support core painters in synth-based LAFs
     * 
     * In synth-based LAFs (core) painters are applied on top of the background
     * fill and below the foreground (== content) painting. SwingX painters are
     * applied on top of the background but below the core painter.
     * 
     * The example below has:
     * 
     * - yellowish background color - SwingX ImagePainter - core painter which
     * paints a diagonal line (top left to bottom right) - a label as content
     * 
     * With Nimbus, all three "background" layers should be visible
     * 
     * Actions:
     * 
     * - toggle opaqueness: if false, the background color must not be painted 
     * - toggle alpha of background color: must not show any artefacts 
     * - toggle alpha of containter: must not show any artefacts, must respect the
     * background filling or not (opaqueness on/off), background alpha must be
     * unchanged
     */
    public void interactiveCustomPanelPainter() {
        final JXPanel panel = new JXPanel(new BorderLayout());
        final Color background = Color.YELLOW;
        final Color backgroundTrans = PaintUtils.setAlpha(background, 100);
        panel.setBackground(background);
        panel.setBackgroundPainter(new ImagePainter(XTestUtils
                .loadDefaultImage("moon.jpg")));
        JLabel label = new JLabel(" seeing something");
        label.setHorizontalAlignment(JLabel.CENTER);
        label.setFont(label.getFont().deriveFont(55f));
        panel.add(label);
        UIDefaults defaults = new UIDefaults();
        defaults.put("Panel.backgroundPainter", new CrossPainter());
        panel.putClientProperty("Nimbus.Overrides", defaults);
        panel.putClientProperty("Nimbus.Overrides.InheritDefaults", true);
        JXFrame frame = wrapInFrame(panel, "background");

        Action opaque = new AbstractAction("toggle opaque (is: true)") {
            boolean isOpaque = true;

            @Override
            public void actionPerformed(ActionEvent e) {
                isOpaque = !isOpaque;
                panel.setOpaque(isOpaque);
                putValue(NAME, "toggle opaque (is: " + isOpaque);
                panel.repaint();
            }
        };
        addAction(frame, opaque);

        Action containerAlpha = new AbstractAction("toggle container alpha") {

            @Override
            public void actionPerformed(ActionEvent e) {
                float alpha = panel.getAlpha();
                panel.setAlpha(alpha < 1f ? 1f : 0.5f);
            }
        };
        addAction(frame, containerAlpha);
        Action backgroundAlpha = new AbstractAction("toggle background alpha") {

            @Override
            public void actionPerformed(ActionEvent e) {
                Color back = panel.getBackground();
                panel.setBackground(back.getAlpha() < 255 ? background
                        : backgroundTrans);

            }
        };
        addAction(frame, backgroundAlpha);
        show(frame, 800, 1000);
    }

    public static class CrossPainter implements Painter<JComponent> {

        BasicStroke stroke = new BasicStroke(20f);

        @Override
        public void paint(Graphics2D g, JComponent comp, int width, int height) {
            g.setColor(Color.MAGENTA);
            g.setStroke(stroke);
            g.drawLine(0, 0, comp.getWidth(), comp.getHeight());
        }

    }

    /**
     * Issue #1199-swingx: JXPanel - must repaint on changes to background
     * painter.
     */
    public void interactivePainterUpdate() {
        JXPanel panel = new JXPanel();
        final MattePainter painter = new MattePainter(Color.RED);
        panel.setBackgroundPainter(painter);
        JXFrame frame = wrapInFrame(panel, "background");
        Action toggleColor = new AbstractAction("toggle background") {

            @Override
            public void actionPerformed(ActionEvent e) {
                Paint old = painter.getFillPaint();
                painter.setFillPaint(old == Color.RED ? Color.YELLOW
                        : Color.RED);

            }
        };
        addAction(frame, toggleColor);
        show(frame, 200, 200);
    }

    /**
     * Issue #1187-swingx: default scrollable tracks property prevents
     * scrolling. Problem are the implementations of scrollableTracks: they
     * unconditionally return true, so forcing the viewport/scrollpane to the
     * size of the contained component.
     */
    public void interactiveScrolling() {
        final JXPanel panel = new JXPanel(new BorderLayout());
        panel.add(createScrollableContent(20));
        JXFrame frame = wrapWithScrollingInFrame(panel,
                "scrollbar must be showing");
        Action toggleHeightTrack = new AbstractActionExt("track height: "
                + panel.getScrollableHeightHint()) {

            ScrollableSizeHint[] tracks = new ScrollableSizeHint[] {
                    ScrollableSizeHint.FIT, ScrollableSizeHint.NONE,
                    ScrollableSizeHint.PREFERRED_STRETCH };

            int position;

            @Override
            public void actionPerformed(ActionEvent e) {
                position++;
                if (position >= tracks.length)
                    position = 0;
                panel.setScrollableHeightHint(tracks[position]);
                setName("track height: " + tracks[position]);
            }
        };
        addAction(frame, toggleHeightTrack);
        show(frame, 400, 400);
    }

    /**
     * @return
     */
    private JComponent createScrollableContent(int rows) {
        JPanel component = new JPanel();
        component.setPreferredSize(new Dimension(400, 400));
        component.setMinimumSize(new Dimension(200, 200));
        component.setMaximumSize(new Dimension(600, 600));
        component.setBorder(BorderFactory.createLineBorder(Color.RED, 5));

        // JButton component = new JButton("gotcha!");
        // JXTable table = new JXTable(rows, 6);
        // for (int i = 0; i < table.getRowCount(); i++) {
        // table.setValueAt("row: " + i, i, 0);
        // }
        return component;
    }

    /**
     * See a painter at work.
     * 
     * Plus Issue ??-swingx: setting opaqueness _after_ the painter leads to
     * painting artefacts.
     * 
     * Here: run this check with several tests active so that the frame create
     * here is overlapped by others, the click on its title to move to front.
     * The background is not uniform: the formerly covered part is grey, the
     * formerly exposed part is white.
     * 
     * Update: probably similar to #1515
     * 
     * @throws Exception
     */
    public void interactiveIconPainter() throws Exception {
        ImagePainter imagePainter = new ImagePainter(ImageIO.read(JXPanel.class
                .getResource("resources/images/kleopatra.jpg")));
        JXPanel panel = new JXPanel();
        panel.setBackgroundPainter(imagePainter);
        // uncomment to see the painting glitch. Move to before setting the
        // background painter and
        // all is fine.
        panel.setOpaque(false);
        panel.setPreferredSize(new Dimension(200, 200));
        showWithScrollingInFrame(panel, "icon painter in jxpanel");
    }

    public void interactiveAlphaCheck() {
        JXPanel xp = new JXPanel();
        xp.setBackgroundPainter(new MattePainter(PaintUtils.AERITH, true));
        xp.setAlpha(.5f);
        xp.add(new JButton("Press Me"));

        JPanel p = new JPanel(new BorderLayout());
        p.setBackground(Color.BLACK);
        p.add(xp);

        show(wrapInFrame(p, "Alpha Check"), 200, 200);
    }

    public void interactiveBackgroundAndAlphaCheck() {
        final JXPanel xp = new JXPanel();
        xp.setBackground(Color.RED);
        xp.setAlpha(.5f);
        xp.add(new JButton("Press Me"));

        JPanel p = new JPanel(new BorderLayout());
        p.setBackground(Color.BLACK);
        p.add(xp);

        show(wrapInFrame(p, "Alpha Check"), 200, 200);
    }

    /**
     * do-nothing method - suppress warning if there are no other test fixtures
     * to run.
     * 
     */
    public void testDummy() {

    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger.getLogger(JXPanelVisualCheck.class
            .getName());
}
