/*
 This file is part of the software framework JStatCom, 
 a library for building applications for data based analysis.

 Copyright (C) 2000-2005  Markus Kraetzig

 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 */

package com.jstatcom.equation;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.JComponent;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;

/**
 * Special layout to be used with EqPanel. It manges the
 * visibility of scrollbars of a parent scrollpane, the adjustment of the
 * equation components and the dimension of the underlying EqPanel.
 * 
 * @author Alexander Benkwitz, Markus Kraetzig
 */
public final class EqLayout extends FlowLayout {
    /**
     * The number of left hand side terms. Managed by EqPanel.add.
     */
    protected int numberLHS = 0;

    private int indentRHS = 20;

    private JScrollPane enclosingScrollPane = null;

    /**
     * Constructor.
     */
    public EqLayout() {
        super(LEFT, 0, 5);
    }

    /**
     * Manages visibility of scrollbar.
     * 
     * @param scrollBar
     */
    private void adjustScrollBar(JScrollBar scrollBar) {

        if (scrollBar == null)
            return;

        if (scrollBar.isVisible()) {
            int max = scrollBar.getMaximum();
            int visibleAmount = scrollBar.getVisibleAmount();
            scrollBar.setVisible(visibleAmount != max);
        }

    }

    /**
     * Centers the elements in the specified row, if there is any slack.
     * 
     * @param target
     *            the component which needs to be moved
     * @param x
     *            the x coordinate
     * @param y
     *            the y coordinate
     * @param width
     *            the width dimensions
     * @param height
     *            the height dimensions
     * @param rowStart
     *            the beginning of the row
     * @param rowEnd
     *            the the ending of the row
     */
    private void centerComponents(Container target, int rowHeight,
            int rowStart, int rowEnd) {
        Point p = new Point();
        for (int i = rowStart; i < rowEnd; i++) {
            Component m = target.getComponent(i);
            if (m.isVisible()) {
                p = m.getLocation(p);
                m.setLocation(p.x, p.y + (rowHeight - m.getHeight()) / 2);
            }
        }
    }

    /**
     * Adds component listeners to all child components.
     * 
     * @param target
     *            the specified component being laid out
     * @param scrollPane
     *            the parent scrollPane
     */
    private void initializeScrollPaneListener(final Container target,
            JScrollPane scrollPane) {
        scrollPane.addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                ((JComponent) target).revalidate();
            }
        });
    }

    /**
     * Manages the layout for the target container and its child components.
     * 
     * @param target
     *            the specified component being laid out.
     * @see java.awt.Container#doLayout
     */
    public void layoutContainer(Container target) {
        synchronized (target.getTreeLock()) {
            boolean leadingSignVisible = false;
            Insets insets = target.getInsets();
            int hgap = getHgap();
            int vgap = getVgap();
            int maxwidth = target.getWidth() - (insets.right + hgap);
            int nmembers = target.getComponentCount();

            int x = insets.left + hgap, y = insets.top + vgap;
            // LHS
            int rowHeight = 0;
            for (int i = 0; i < Math.min(numberLHS, nmembers); i++) {
                Component m = target.getComponent(i);
                if (m.isVisible()) {
                    Dimension d = m.getPreferredSize();
                    m.setSize(d.width, d.height);
                    m.setLocation(x, y);
                    x += d.width + hgap;
                    rowHeight = Math.max(rowHeight, d.height);
                }
            }
            int indent = x;
            int membersTreated = Math.min(numberLHS, nmembers);
            // rest of row 0
            for (int i = membersTreated; i < nmembers; i++, membersTreated++) {
                Component m = target.getComponent(i);
                if (m.isVisible()) {
                    if (m instanceof EqTerm) {
                        ((EqTerm) m).setLeadingSignVisible(leadingSignVisible);
                        leadingSignVisible = true;
                    }
                    Dimension d = m.getPreferredSize();
                    if ((x + d.width) <= maxwidth) {
                        m.setSize(d.width, d.height);
                        m.setLocation(x, y);
                        x += d.width + hgap;
                        rowHeight = Math.max(rowHeight, d.height);
                    } else {
                        leadingSignVisible = !(membersTreated == numberLHS);
                        break;
                    }
                }
            }

            centerComponents(target, rowHeight, 0, membersTreated);
            //
            if (membersTreated == numberLHS)
                indent = indentRHS;
            // indent += insets.left + hgap;
            // row 1,...,N
            int firstItem = membersTreated;
            // int counter = 1;
            while (membersTreated < nmembers) {
                firstItem = membersTreated;
                Component m = target.getComponent(membersTreated++);
                if (m.isVisible()) {
                    
                    x = indent;
                    y += rowHeight + vgap;
                    rowHeight = 0;
                    if (m instanceof EqTerm) {
                        ((EqTerm) m).setLeadingSignVisible(leadingSignVisible);
                        leadingSignVisible = true;
                    }
                    Dimension d = m.getPreferredSize();
                    m.setSize(d.width, d.height);
                    m.setLocation(x, y);
                    x += d.width;
                    rowHeight = d.height;
                    for (int i = membersTreated; i < nmembers; i++, membersTreated++) {
                        Component comp = target.getComponent(i);
                        if (comp.isVisible()) {
                            if (comp instanceof EqTerm) {
                                ((EqTerm) comp).setLeadingSignVisible(true);
                            }
                            Dimension compPrefSize = comp.getPreferredSize();
                            if ((x + hgap + compPrefSize.width) <= maxwidth) {
                                comp.setSize(compPrefSize.width,
                                        compPrefSize.height);
                                comp.setLocation(hgap + x, y);
                                x += compPrefSize.width;
                                rowHeight = Math.max(rowHeight,
                                        compPrefSize.height);
                            } else {
                                membersTreated = i;
                                centerComponents(target, rowHeight, firstItem,
                                        membersTreated);
                                break;
                            }
                        }
                    }
                }
            }
            centerComponents(target, rowHeight, firstItem, membersTreated);
            //
            if (enclosingScrollPane != null
                    && enclosingScrollPane.getVerticalScrollBarPolicy() == ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED) {
                adjustScrollBar(enclosingScrollPane.getVerticalScrollBar());
            }
        }
    }

    /**
     * Returns the maximum dimensions needed to layout the components contained
     * in the specified target container.
     * 
     * @param target
     *            the component which needs to be laid out
     * @return the maximum dimensions to lay out the subcomponents of the
     *         specified container.
     */
    public Dimension maximumLayoutSize(Container target) {
        return preferredLayoutSize(target);
    }

    /**
     * Returns the minimum dimensions needed to layout the components contained
     * in the specified target container.
     * 
     * @param target
     *            the component which needs to be laid out
     * @return the minimum dimensions to lay out the subcomponents of the
     *         specified container.
     */
    public Dimension minimumLayoutSize(Container target) {
        return preferredLayoutSize(target);
    }

    /**
     * Wrappes component childs if there is a parent component of class
     * JScrollPane.
     * 
     * @param target
     *            the component which needs to be laid out
     * @return the preferred dimensions to lay out the subcomponents of the
     *         specified container.
     */
    public Dimension preferredLayoutSize(Container target) {
        if (enclosingScrollPane == null) {
            Container parent = target.getParent();
            while (parent != null) {
                if (parent instanceof JScrollPane) {
                    enclosingScrollPane = (JScrollPane) parent;
                    break;
                }
                parent = parent.getParent();
            }
            if (enclosingScrollPane != null)
                initializeScrollPaneListener(target, enclosingScrollPane);
        }

        if (enclosingScrollPane == null)
            return super.preferredLayoutSize(target);

        synchronized (target.getTreeLock()) {
            boolean leadingSignVisible = false;

            Dimension prefSize = preferredLayoutSizeLHS(target);
            int indent = prefSize.width;
            int hgap = getHgap();
            int vgap = getVgap();

            // we maybe share the JScrollPane with other components
            Dimension viewSize = enclosingScrollPane.getViewport().getSize();
            Point point = SwingUtilities.convertPoint(target, 0, 0,
                    enclosingScrollPane.getViewport());
            Insets insets = target.getInsets();
            int maxWidth = viewSize.width - point.x
                    - (insets.left + insets.right + hgap * 2);

            // rest of row 0
            int nmembers = target.getComponentCount();
            int membersTreated = numberLHS;
            for (int i = numberLHS; i < nmembers; i++, membersTreated++) {
                Component comp = target.getComponent(i);
                if (comp.isVisible()) {
                    if (comp instanceof EqTerm) {
                        ((EqTerm) comp)
                                .setLeadingSignVisible(leadingSignVisible);
                        leadingSignVisible = true;
                    }
                    Dimension compPrefSize = comp.getPreferredSize();
                    if ((prefSize.width + hgap + compPrefSize.width) <= maxWidth) {
                        prefSize.width += hgap + compPrefSize.width;
                        prefSize.height = Math.max(prefSize.height,
                                compPrefSize.height);
                    } else {
                        membersTreated = i;
                        leadingSignVisible = !(membersTreated == numberLHS);
                        break;
                    }
                }
            }
            // row 1,...,N
            if (indent == prefSize.width) {
                indent = indentRHS;
            }
            while (membersTreated < nmembers) {
                Component comp = target.getComponent(membersTreated++);
                if (comp.isVisible()) {
                    if (comp instanceof EqTerm) {
                        ((EqTerm) comp)
                                .setLeadingSignVisible(leadingSignVisible);
                        leadingSignVisible = true;
                    }
                    Dimension compPrefSize = comp.getPreferredSize();
                    int rowWidth = indent + compPrefSize.width;
                    int rowHeight = compPrefSize.height;
                    for (int i = membersTreated; i < nmembers; i++, membersTreated++) {
                        comp = target.getComponent(i);
                        if (comp.isVisible()) {
                            if (comp instanceof EqTerm) {
                                ((EqTerm) comp)
                                        .setLeadingSignVisible(leadingSignVisible);
                            }
                            compPrefSize = comp.getPreferredSize();
                            if ((rowWidth + hgap + compPrefSize.width) <= maxWidth) {
                                rowWidth += hgap + compPrefSize.width;
                                rowHeight = Math.max(rowHeight,
                                        compPrefSize.height);
                            } else {
                                membersTreated = i;
                                break;
                            }
                        }
                    }
                    prefSize.height += vgap + rowHeight;
                    prefSize.width = Math.max(prefSize.width, rowWidth);
                }
            }
            prefSize.width += insets.left + insets.right + hgap * 2;
            prefSize.height += insets.top + insets.bottom + vgap * 2;

            return prefSize;
        }

    }

    /**
     * Returns the preferred dimensions for this layout given the components in
     * the specified target container.
     * 
     * @param target
     *            the component which needs to be laid out
     * @return the preferred dimensions to lay out the subcomponents of the
     *         specified container.
     * @see Container
     * @see #minimumLayoutSize
     * @see java.awt.Container#getPreferredSize
     */
    private Dimension preferredLayoutSizeLHS(Container target) {
        Dimension dim = new Dimension(0, 0);
        int nmembers = Math.min(numberLHS, target.getComponentCount());
        for (int i = 0; i < nmembers; i++) {
            Component m = target.getComponent(i);
            if (m.isVisible()) {
                Dimension d = m.getPreferredSize();
                dim.height = Math.max(dim.height, d.height);
                if (i > 0) {
                    dim.width += getHgap();
                }
                dim.width += d.width;
            }
        }
        return dim;
    }
}
 

Ads help maintain this website.