Package DisplayProject

Source Code of DisplayProject.WindowFormLayout

/*
Copyright (c) 2003-2009 ITerative Consulting Pty Ltd. 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 This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder

 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "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 DisplayProject;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.LayoutManager2;

import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTabbedPane;

import org.apache.log4j.Logger;

import DisplayProject.actions.HeightPolicy;
import DisplayProject.actions.WidthPolicy;
import DisplayProject.actions.WindowStyle;

/**
* The WindowFormLayout replicates the behaviour of the Forte Window.Form.
* It will size its self to the minimum size to display the visible Components it contains.
*
*/
public class WindowFormLayout implements LayoutManager2{
    private static Logger _log = Logger.getLogger(WindowFormLayout.class);
    /**
     * This is the size of a window form which has no visible children
     */
    protected static Dimension EMPTY_DIMENSION = new Dimension(0, 0);
    protected JFrame frame;

    public WindowFormLayout() {
        super();
    }
    /**
     * experimental constructor taking a JFrame parameter
     * to effect the resize.
     * Used only with swing builder
     * @param frame
     */
    public WindowFormLayout(JFrame frame) {
        this();
        this.frame = frame;
    }


    protected JLayeredPane getLayeredPane(Component c) {
        if (c instanceof JFrame) {
            return ((JFrame)c).getLayeredPane();
        }
        else if (c instanceof JDialog) {
            return ((JDialog)c).getLayeredPane();
        }
        else {
            return null;
        }
    }

    /**
     * Determine if the window which contains the passed component is resizable
     * @param parent
     * @return
     */
    private boolean isParentResizable(JComponent parent) {
        JFrame grandMa =(JFrame)parent.getTopLevelAncestor();

        if (this.frame != null)
            return WindowStyle.get(this.frame) == Constants.WS_RESIZEABLE;
        else {
            return WindowStyle.get(grandMa) == Constants.WS_RESIZEABLE;
        }
    }

    /**
     * Determine if this component can be re-sized in the X direction (width)
     * @param parent
     * @return
     */
    protected boolean isResizableX(JComponent parent) {
        int widthPolicy = WidthPolicy.get(parent);
        return (widthPolicy == Constants.SP_TO_PARENT);
    }

    /**
     * Determine if this component can be re-sized in the Y direction (height)
     * @param parent
     * @return
     */
    protected boolean isResizableY(JComponent parent) {
        int heightPolicy = HeightPolicy.get(parent);
        return (heightPolicy == Constants.SP_TO_PARENT);
    }

    public Insets getLayoutInsets(Container parent) {
        Component[] kids = parent.getComponents();
        int minX = 10000000;
        int minY = 10000000;
        boolean hasKids = false;
        for (int i = 0; i < kids.length; i++){
            // TF:17/8/07:The form offset must be re-computed each time, in case the defining widget is
            // deleted or another one inserted
            if (kids[i].isVisible()) {
                int thisX = kids[i].getX();
                int thisY = kids[i].getY();
                if (thisX < minX) {
                    minX = thisX;
                }
                if (thisY < minY) {
                    minY = thisY;
                }
                hasKids = true;
            }
        }
        if (hasKids) {
            return new Insets(minY, minX, minY, minX);
        }
        else {
            return LayoutManagerHelper.emptyInsets;
        }
    }

    /**
     * This method lays out the Forte Window.Form and takes in consideration the
     * margin or border
     */
    public void layoutContainer(Container parent) {
      boolean debugEnabled = _log.isDebugEnabled();
      if (debugEnabled) {
        _log.debug("Laying out panel " + parent.getName());
      }
        Component[] kids = parent.getComponents();
        // TF:19/9/07:Fixed this up for the proper structure of the WindowFormLayout after experimenting with the Forte one
        // If we're not already at 0,0 set the parent there and adjust all the kids offsets to compensate
        int oldX = parent.getX();
        int oldY = parent.getY();
        if (oldX != 0 && oldY != 0) {
            parent.setLocation(0, 0);
            for (int i = 0; i < kids.length; i++){
                // set all the kids, including invisible ones
                kids[i].setLocation(kids[i].getX() + oldX, kids[i].getY() + oldY);
            }
        }

        // Get the minimum size of the current container, and it's current size
        Dimension minSize = minimumLayoutSize(parent);
        Dimension currentSize = parent.getSize();
        // TF:26/9/07:Had to remove this as there were some cases where this was true, but we still had to reapply our
        // size to our kids. This is particularly just after an open.
//        if (currentSize.equals(minSize))
//            return;
        if (debugEnabled) {
          _log.debug("\tCurrent size = " + currentSize + " Minimum size = " + minSize);
        }

        // Force the minimum size to be the calculated minimum size
        boolean minSizeChanged = false;
        if (!minSize.equals(parent.getMinimumSize())) {
            ((JComponent) parent).setMinimumSize(minSize);
            minSizeChanged = true;
        }
        if (debugEnabled) {
          _log.debug("\tMinimum size = " + minSize);
        }

        boolean parentResizable = isParentResizable((JComponent)parent);

        int newWidth;
        int newHeight;
       
        // If we're smaller than our currently allowed minimum width (for example, a component has been set
        // visible which has changed our minimum width) or the window is not resizable, we force the window
        // to be the minimum width
        if (minSize.width > currentSize.width || !parentResizable) {
          newWidth = minSize.width;
        }
        else {
          newWidth = currentSize.width;
        }
       
        // Same for the height
        if (minSize.height > currentSize.height || !parentResizable) {
          newHeight = minSize.height;
        }
        else {
          newHeight = currentSize.height;
        }

        for (int i = 0; i < kids.length; i++){
            JComponent thisComp = (JComponent)kids[i];

            // If any widgets can expand, expand it to take the extra room, otherwise we need to
            // shrink the window down to the size of the inner grid
            if (thisComp instanceof JTabbedPane) {
                // We must force the tab pane to recalculate the proper minimum size
                // by setting it to be null. This will ensure the minimum size is large
                // enough for all of the children
                thisComp.setMinimumSize(null);
            }

            int aWidth;     // The width of the widget in this form
            int aHeight;    // The height of the widget in this form

            if (isResizableX(thisComp)) {
                aWidth = newWidth - 2*thisComp.getX();
            }
            else {
                // We can't size the grid up, so size the window down. The size of the root
                // pane must be the size of the grid plus our borders (X loc on each side)
                // TF:11/2/08:Fixed this to use the getMinimumSize method to cater for partners and scrollbars
                //aWidth = thisComp.getMinimumSize().width;
                aWidth = LayoutManagerHelper.getMinimumSize(thisComp).width;
            }

            if (isResizableY(thisComp)) {
                aHeight = newHeight - 2*thisComp.getY();
            }
            else {
                // We can't size the grid up, so size the window down. The size of the root
                // pane must be the size of the grid plus our borders (Y loc on each side)
                // TF:11/2/08:Fixed this to use the getMinimumSize method to cater for partners and scrollbars
                //aHeight = thisComp.getMinimumSize().height;
                aHeight = LayoutManagerHelper.getMinimumSize(thisComp).height;
            }

            Dimension d = new Dimension(aWidth, aHeight);
            if (!thisComp.getSize().equals(d)) {
              if (debugEnabled) {
                _log.debug("\tSetting inner grid size to " + d);
              }
                thisComp.setSize(d);
            }
            // A window form layout never alters the location of the children once it's set to 0,0
        }

        Dimension newSize = new Dimension(newWidth, newHeight);

        //PM:15/8/07 only resize if you need to
        if (newSize.equals(parent.getSize()) && !minSizeChanged)
            return;

        if (debugEnabled) {
          _log.debug("\tSetting Form size = " + newSize);
        }
        if (!parentResizable){
            parent.setSize(newSize);
//            parent.setMinimumSize(newSize);
            parent.setPreferredSize(newSize);
        }
        else if (currentSize.width < minSize.width || currentSize.height < minSize.height) {
            // We are resizable, but we've been sized smaller than what we should be allowed to be
            parent.setSize(Math.max(minSize.width, currentSize.width), Math.max(minSize.height, currentSize.height));
        }
        else {
            //TF:29/8/07:If the window is resizable and the current size is larger than the desired size,
            // allow it to exist at this increased size, like Forte did
            return;
        }

        if (this.frame != null){
            /*
             * if we have stored our frame the we will resize it.
             * PM:06/8/07 to allow the Swing Designer to work
             */
            resizeJFrame(newSize);
        } else {
            /*
             * otherwise we will go through the process of finding the frame
             *
             * @deprecated, this code remains only for backward compatability.
             * Only code generated prior to 6/8/07 will use this
             */
            Component grandMa = ((JComponent)parent).getTopLevelAncestor();
            JRootPane root = ((JComponent)parent).getRootPane();
            JLayeredPane layeredPane = getLayeredPane(grandMa);
            Component glassPane = UIutils.getGlassPane(grandMa);
            JMenuBar menuBar = root == null ? null : root.getJMenuBar();
            if (grandMa != null) {
                Insets insets = ((Container)grandMa).getInsets();
                Insets tempInsets = new Insets(0,0,0,0);

                int menuHeight = 0;
                // TF:19/09/2009:Only compensate for the menu bar if it's visible.
                if (menuBar != null && menuBar.isVisible()) {
                    // Compensate for only the height of the menu, the width is derived from the screen.
                    menuHeight = menuBar.getHeight();
                }

                // Layered pane = content pane + menu bar + insets
                if (layeredPane != null) {
                    layeredPane.getInsets(tempInsets);
                    newSize.height += menuHeight + tempInsets.top + tempInsets.bottom;
                    newSize.width += tempInsets.left + tempInsets.right;
                    if (debugEnabled) {
                      _log.debug("\tsetting layered pane size to " + newSize);
                    }
                    if (newSize.height != layeredPane.getHeight()
                            || newSize.width != layeredPane.getWidth()) {
                        layeredPane.setSize(newSize);
                    }
                }
                if (glassPane != null) {
                  if (debugEnabled) {
                    _log.debug("\tsetting glass pane size to " + newSize);
                  }
                    if (newSize.height != glassPane.getHeight()
                            || newSize.width != glassPane.getWidth()) {
                        glassPane.setSize(newSize);
                    }
                }

                if (root != null) {
                    root.getInsets(tempInsets);
                    newSize.height += tempInsets.top + tempInsets.bottom;
                    newSize.width += tempInsets.left + tempInsets.right;
                    if (debugEnabled) {
                      _log.debug("\tsetting root pane size to " + newSize);
                    }
                    if (newSize.height != root.getHeight()
                            || newSize.width != root.getWidth()) {
                        root.setSize(newSize);
                        root.revalidate(); //PM:4/8/07 Added to correct paint issue
                    }
                }

                if (debugEnabled) {
                  _log.debug("\tSetting owning container's size to ("
                          + (newSize.width + insets.left + insets.right) + ", "
                          + (newSize.height + insets.top + insets.bottom) + ")");
                }
                JPanel theForm = UIutils.getForm((JFrame)grandMa);
                if (theForm != null && theForm == parent) {
                  //PM:13/06/07 to ensure that we only resize the JFrame when necessary
                    grandMa.setSize(newSize.width + insets.left + insets.right,
                            newSize.height + insets.top + insets.bottom);
                }
            }
        }
    }

    /**
     * PM:5/8/07 moved this code to a new method
     * @param newSize
     */
    private void resizeJFrame(final Dimension newSize){
        Insets insets = this.frame.getInsets();
        JLayeredPane layeredPane = this.frame.getLayeredPane();
        Insets layeredPaneInsets = new Insets(0,0,0,0);
        JMenuBar menuBar = this.frame.getJMenuBar();
        int menuHeight = (menuBar == null) ? 0 : menuBar.getHeight()// Compensate for only the height of the menu, the width is derived from the screen.
        Component glassPane = this.frame.getGlassPane();
        JRootPane rootPane = this.frame.getRootPane();
        Insets RootPaneInsets = new Insets(0,0,0,0);

        // Layered pane = content pane + menu bar + insets
        if (layeredPane != null) {
            layeredPane.getInsets(layeredPaneInsets);
            // TF:20/8/07:Tests show that if we include the menu height here that our window comes out too big,
            // by the height of the menu. So setting the layered pane size must cater for this.
            newSize.height += menuHeight + layeredPaneInsets.top + layeredPaneInsets.bottom;
            newSize.width += layeredPaneInsets.left + layeredPaneInsets.right;
            if (_log.isDebugEnabled()) {
              _log.debug("\tsetting layered pane size to " + newSize);
            }
            if (newSize.height != layeredPane.getHeight()
                    || newSize.width != layeredPane.getWidth()) {
                layeredPane.setSize(newSize);
                layeredPane.revalidate();
                layeredPane.repaint();
            }
        }
        // size the glass pane
        if (glassPane != null) {
            if (_log.isDebugEnabled()) {
              _log.debug("\tsetting glass pane size to " + newSize);
            }
            if (newSize.height != glassPane.getHeight()
                    || newSize.width != glassPane.getWidth()) {
                glassPane.setSize(newSize);
            }
        }

        //size the root pane
        if (rootPane != null) {
            rootPane.getInsets(RootPaneInsets);
            newSize.height += RootPaneInsets.top + RootPaneInsets.bottom;
            newSize.width += RootPaneInsets.left + RootPaneInsets.right;
            if (_log.isDebugEnabled()) {
              _log.debug("\tsetting root pane size to " + newSize);
            }
            if (newSize.height != rootPane.getHeight()
                    || newSize.width != rootPane.getWidth()) {
                rootPane.setSize(newSize);
                rootPane.revalidate(); //PM:4/8/07 Added to correct paint issue
                rootPane.repaint();
            }
        }

        if (_log.isDebugEnabled()) {
          _log.debug("\tSetting owning container's size to ("
                  + (newSize.width + insets.left + insets.right) + ", "
                  + (newSize.height + insets.top + insets.bottom) + ")");
        }
        this.frame.setSize(newSize.width + insets.left + insets.right,
                newSize.height + insets.top + insets.bottom);
        this.frame.repaint();
    }

    /**
     * This calculates the minimum size of the form based on visible components
     */ 
    public Dimension minimumLayoutSize(Container parent) {
        // TF:19/9/07:Changed this so that it followed the (quirky) rules of the Forte layout manager. For example, there
        // are actually 2 sets of margins -- one for those components that are sized to parent, and one for those that are
        // not. The minimum size is the larger of the 2.
        int minXNonResizable = Integer.MAX_VALUE;
        int maxXNonResizable = 0;
        int minYNonResizable = Integer.MAX_VALUE;
        int maxYNonResizable = 0;

        int maxXResizable = 0;
        int maxYResizable = 0;

        Component[] comps = parent.getComponents();
        // TF:10/7/07: Ensured there is at least one visible child to prevent the calculation going haywire
//        boolean hasChildren = false;
        for (int k = 0; k < comps.length; k++){
            JComponent thisComp = (JComponent)comps[k];
            if (!(thisComp.isVisible())) {
                continue;
            }
            GridCell cell = GridField.getConstraints(thisComp);
            int compX = thisComp.getX();
            int compY = thisComp.getY();

            // TF:11/2/08:Fixed this to use the getMinimumSize method to cater for partners and scrollbars
            //Dimension minSize = thisComp.getMinimumSize();
            Dimension minSize = LayoutManagerHelper.getMinimumSize(thisComp);

            // TF:27/2/08:Resizable components have a border around each component whose size is always 2*(x,y).
            // Fixed components on the other hand have a border equal to the smallest x,y location of all fixed
            // components. Corrected the rules here to accomodate this.
            if (cell.getWidthPolicy() == Constants.SP_TO_PARENT) {
                maxXResizable = Math.max(maxXResizable, 2 * compX + minSize.width);
            }
            else {
              // TF:15/02/2010:If there are some components that are at a locations less than 0, we
              // must treat their minimum location as 0
                minXNonResizable = Math.max(0, Math.min(minXNonResizable, compX));
                maxXNonResizable = Math.max(maxXNonResizable, compX + minSize.width);
            }

            if (cell.getHeightPolicy() == Constants.SP_TO_PARENT) {
                maxYResizable = Math.max(maxYResizable, 2 * compY + minSize.height);
            }
            else {
              // TF:15/02/2010:If there are some components that are at a locations less than 0, we
              // must treat their minimum location as 0
                minYNonResizable = Math.max(0, Math.min(minYNonResizable, compY));
                maxYNonResizable = Math.max(maxYNonResizable, compY + minSize.height);
            }
        }
        Dimension size = new Dimension(0, 0);
        // Get the size of the non-resizable components first...
        if (maxXNonResizable > 0) {
            size.width = Math.max(size.width, minXNonResizable + maxXNonResizable);
        }
        if (maxYNonResizable > 0) {
            size.height = Math.max(size.height, minYNonResizable + maxYNonResizable);
        }

        // Then the size of the resizable components...
        if (maxXResizable > 0) {
            size.width = Math.max(size.width, maxXResizable);
        }
        if (maxYResizable > 0) {
            size.height = Math.max(size.height, maxYResizable);
        }
        return size;
    }

    public Dimension preferredLayoutSize(Container parent) {
        return minimumLayoutSize(parent);
    }

    public void removeLayoutComponent(Component comp) {
    }

    public void addLayoutComponent(String name, Component comp) {
    }

    public void addLayoutComponent(Component comp, Object constraint) {
        if (comp instanceof JComponent) {
            if (constraint instanceof GridBagConstraints) {
                // We must merge the new parts from the constraints against the existing cell. For example, if the field
                // is a grid field, it can have it's own constraints from having properties set on it such as height and
                // width policies. When it's added to it's parent grid, it's added with the values from the GridBagConstraints
                // so we must pick and choose which ones we really want.
                GridCell cell = GridField.getConstraints((JComponent)comp);
                GridCell newCell = new GridCell((GridBagConstraints)constraint);
                cell.merge(newCell);
                GridField.setConstraints((JComponent)comp, cell);
            }
            else if (constraint instanceof GridCell) {
                GridField.setConstraints((JComponent)comp, (GridCell)constraint);
            }
        }
    }

    public float getLayoutAlignmentX(Container target) {
        return 0;
    }

    public float getLayoutAlignmentY(Container target) {
        return 0;
    }

    public void invalidateLayout(Container target) {
    }

    public Dimension maximumLayoutSize(Container target) {
        return null;
    }

    /**
     * returns the frame the form is declare on
     * @return
     */
    public JFrame getFrame() {
        return frame;
    }

}
TOP

Related Classes of DisplayProject.WindowFormLayout

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.