/*
 *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
*/

// (PENDING:- PL) The copyright on this class needs to be modified,
// because most of the code comes straight from the super class

/* 
 * This software was written by Phillip Lord (p.lord@hgmp.mrc.ac.uk)
 * whilst at the University of Manchester as a Pfizer post-doctoral 
 * Research Fellow. 
 *
 * The initial code base is copyright by Pfizer, or the University
 * of Manchester. Modifications to the initial code base are copyright
 * of their respective authors, or their employers as appropriate. 
 * Authorship of the modifications may be determined from the ChangeLog
 * placed at the end of this file
 */

package uk.ac.man.bioinf.gui.viewer; // Package name inserted by JPack
import javax.swing.ScrollPaneLayout;
import java.awt.Container;
import javax.swing.JScrollPane;
import java.awt.Rectangle;
import java.awt.Insets;
import javax.swing.border.Border;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.Scrollable;


/**
 * InvertedScrollPaneLayout.java
 *
 *
 * Created: Fri Mar 31 14:27:41 2000
 *
 * @author Phillip Lord
 * @version $Id: InvertedScrollPaneLayout.java,v 1.3 2001/04/11 17:04:42 lord Exp $
 */

public class InvertedScrollPaneLayout extends ScrollPaneLayout
{

  public void layoutContainer( Container parent )
  {
    //super.layoutContainer( parent );
    
    // This code is more or less a straight copy of the super class
    // method. The bits that I have changed are maked "(PL)" so that I
    // know what is going on...
    /* Sync the (now obsolete) policy fields with the
     * JScrollPane.
     */
    JScrollPane scrollPane = (JScrollPane)parent;
    vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
    hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
    
    
    Rectangle availR = new Rectangle(scrollPane.getSize());
    
    Insets insets = parent.getInsets();
    availR.x = insets.left;
    availR.y = insets.top;
    availR.width -= insets.left + insets.right;
    availR.height -= insets.top + insets.bottom;
    
    
    /* If there's a visible column header remove the space it 
     * needs from the top of availR.  The column header is treated 
     * as if it were fixed height, arbitrary width.
     */
    
    Rectangle colHeadR = new Rectangle(0, availR.y, 0, 0);
    
    if ((colHead != null) && (colHead.isVisible())) {
      int colHeadHeight = colHead.getPreferredSize().height;
      colHeadR.height = colHeadHeight; 
      // (PL) this line here makes the main view port go to the top of
      // the scroll pane.
      //availR.y += colHeadHeight;
      availR.height -= colHeadHeight;
    }
    
    /* If there's a visible row header remove the space it needs
     * from the left of availR.  The row header is treated 
     * as if it were fixed width, arbitrary height.
     */
    
    Rectangle rowHeadR = new Rectangle(availR.x, 0, 0, 0);
    
    if ((rowHead != null) && (rowHead.isVisible())) {
      int rowHeadWidth = rowHead.getPreferredSize().width;
      rowHeadR.width = rowHeadWidth;
      availR.x += rowHeadWidth;
      availR.width -= rowHeadWidth;
    }
    
    /* If there's a JScrollPane.viewportBorder, remove the
     * space it occupies for availR.
     */
    
    Border viewportBorder = scrollPane.getViewportBorder();
    Insets vpbInsets;
    if (viewportBorder != null) {
      vpbInsets = viewportBorder.getBorderInsets(parent);
      availR.x += vpbInsets.left;
      availR.y += vpbInsets.top;
      availR.width -= vpbInsets.left + vpbInsets.right;
      availR.height -= vpbInsets.top + vpbInsets.bottom;
    }
    else {
      vpbInsets = new Insets(0,0,0,0);
    }
    
    colHeadR.x = availR.x;
    rowHeadR.y = availR.y;
    
    /* At this point availR is the space available for the viewport
     * and scrollbars, and the rowHeadR colHeadR rectangles are correct
     * except for their width and height respectively.  Once we're 
     * through computing the dimensions  of these three parts we can 
     * go back and set the dimensions of rowHeadR.width, colHeadR.height, 
     * and the bounds for the corners.
     * 
     * We'll decide about putting up scrollbars by comparing the 
     * viewport views preferred size with the viewports extent
     * size (generally just its size).  Using the preferredSize is
     * reasonable because layout proceeds top down - so we expect
     * the viewport to be layed out next.  And we assume that the
     * viewports layout manager will give the view it's preferred
     * size.  One exception to this is when the view implements 
     * Scrollable and Scrollable.getViewTracksViewport{Width,Height}
     * methods return true.  If the view is tracking the viewports
     * width we don't bother with a horizontal scrollbar, similarly
     * if view.getViewTracksViewport(Height) is true we don't bother
     * with a vertical scrollbar.
     */
    
    Component view = (viewport != null) ? viewport.getView() : null;
    Dimension viewPrefSize =  
      (view != null) ? view.getPreferredSize() 
      : new Dimension(0,0);
    
    Dimension extentSize = 
      (viewport != null) ? viewport.toViewCoordinates(availR.getSize()) 
      : new Dimension(0,0);
    
    boolean viewTracksViewportWidth = false;
    boolean viewTracksViewportHeight = false;
    if (view instanceof Scrollable) {
      Scrollable sv = ((Scrollable)view);
      viewTracksViewportWidth = sv.getScrollableTracksViewportWidth();
      viewTracksViewportHeight = sv.getScrollableTracksViewportHeight();
    }
    
    /* If there's a vertical scrollbar and we need one, allocate
     * space for it (we'll make it visible later). A vertical 
     * scrollbar is considered to be fixed width, arbitrary height.
     */
    
    Rectangle vsbR = new Rectangle(0, availR.y - vpbInsets.top, 0, 0);
    
    boolean vsbNeeded;
    if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
      vsbNeeded = true;
    }
    else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) {
      vsbNeeded = false;
    }
    else {  // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
      vsbNeeded = !viewTracksViewportHeight && (viewPrefSize.height > extentSize.height);
    }
    
    
    if ((vsb != null) && vsbNeeded) {
      int vsbWidth = vsb.getPreferredSize().width;
      availR.width -= vsbWidth;
      vsbR.x = availR.x + availR.width + vpbInsets.right;
      vsbR.width = vsbWidth;
    }
    
    /* If there's a horizontal scrollbar and we need one, allocate
     * space for it (we'll make it visible later). A horizontal 
     * scrollbar is considered to be fixed height, arbitrary width.
     */
    
    Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0);
    boolean hsbNeeded;
    if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
      hsbNeeded = true;
    }
    else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
      hsbNeeded = false;
    }
    else {  // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
      hsbNeeded = !viewTracksViewportWidth && (viewPrefSize.width > extentSize.width);
    }
    
    if ((hsb != null) && hsbNeeded) {
      int hsbHeight = hsb.getPreferredSize().height;
      availR.height -= hsbHeight;
      // (PL) We have to add here the colHead height as well, which is
      // usually accounted for in the availR.y value...
      // hsbR.y = availR.y + availR.height + vpbInsets.bottom;
      hsbR.y = availR.y + availR.height + vpbInsets.bottom + colHeadR.height;
      hsbR.height = hsbHeight;
      
      /* If we added the horizontal scrollbar then we've implicitly 
       * reduced  the vertical space available to the viewport. 
       * As a consequence we may have to add the vertical scrollbar, 
       * if that hasn't been done so already.  Ofcourse we
       * don't bother with any of this if the vsbPolicy is NEVER.
       */
      if ((vsb != null) && !vsbNeeded && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  	extentSize = viewport.toViewCoordinates(availR.getSize());
  	vsbNeeded = viewPrefSize.height > extentSize.height;
	
  	if (vsbNeeded) {
  	  int vsbWidth = vsb.getPreferredSize().width;
  	  availR.width -= vsbWidth;
	  vsbR.x = availR.x + availR.width + vpbInsets.right;
	  vsbR.width = vsbWidth;
	}
      }
    }
    
    /* We now have the final size of the viewport: availR.
     * Now fixup the header and scrollbar widths/heights.
     */
    
    vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
    hsbR.width = availR.width + vpbInsets.left + vpbInsets.right;
    rowHeadR.height = availR.height;
    colHeadR.width = availR.width;
    
    // (PL) The column head Y value is not set anywhere as it is
    // usually the default zero. Change that here. We can ignore the
    // availR.y value as we know that in this layout manager it is
    // always going to be zero
    colHeadR.y = availR.height;
    
    
    /* Set the bounds of all nine components.  The scrollbars
     * are made invisible if they're not needed.
     */
    
    if (viewport != null) {
      viewport.setBounds(availR);
    }
    
    if (rowHead != null) {
      rowHead.setBounds(rowHeadR);
    }
    
    if (colHead != null) {
      colHead.setBounds(colHeadR);
    }
    
    if (vsb != null) {
      if (vsbNeeded) {
  	vsb.setVisible(true);
  	vsb.setBounds(vsbR);
      }
      else {
  	vsb.setVisible(false);
      }
    }
    
    if (hsb != null) {
      if (hsbNeeded) {
  	hsb.setVisible(true);
  	hsb.setBounds(hsbR);
      }
      else {
  	hsb.setVisible(false);
      }
    }
    
    if (lowerLeft != null) {
      lowerLeft.setBounds(rowHeadR.x, hsbR.y, rowHeadR.width, hsbR.height);
    }
    
    if (lowerRight != null) {
      lowerRight.setBounds(vsbR.x, hsbR.y, vsbR.width, hsbR.height);
    }
    
    if (upperLeft != null) {
      upperLeft.setBounds(rowHeadR.x, colHeadR.y, rowHeadR.width, colHeadR.height);
    }
    
    if (upperRight != null) {
      upperRight.setBounds(vsbR.x, colHeadR.y, vsbR.width, colHeadR.height);
    }
  }
} // InvertedScrollPaneLayout



/*
 * ChangeLog
 * $Log: InvertedScrollPaneLayout.java,v $
 * Revision 1.3  2001/04/11 17:04:42  lord
 * Added License agreements to all code
 *
 * Revision 1.2  2000/05/08 16:29:41  lord
 * Fiddling whilst Rome burns
 *
 * Revision 1.1  2000/04/18 17:43:56  lord
 * All files moved from uk.ac.man.bioinf.viewer package
 *
 * Revision 1.1  2000/03/31 16:21:01  lord
 * Initial checkin
 *
 */
