/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.util.toolbar;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.Rectangle;
import java.util.HashMap;
import java.util.Iterator;
/**
* ToolbarLayout is a LayoutManager2 that should be used on a toolbar panel to allow placement of components in absolute positions.
*
* This is the place where components are setted it's bounds by actual toolbar configuration.
*
* @author Libor Kramolis
*/
public class ToolbarLayout implements LayoutManager2, java.io.Serializable
{
/** Toolbar horizontal gap. */
public static final int HGAP = 1;
/** Toolbar vertical gap. */
public static final int VGAP = 1;
static final long serialVersionUID = 7489472539255790677L;
/** ToolbarConfiguration cached for getting preferred toolbar configuration width. */
ToolbarPanel toolbarConfig;
/** Map of components. */
HashMap componentMap;
/**
* Creates a new ToolbarLayout.
*/
public ToolbarLayout(ToolbarPanel conf)
{
toolbarConfig = conf;
componentMap = new HashMap();
}
/**
* Adds the specified component with the specified name to the layout. Everytime throws IllegalArgumentException.
*
* @param name the component name
* @param comp the component to be added
*/
public void addLayoutComponent(String name, Component comp)
{
throw new IllegalArgumentException();
}
/**
* Adds the specified component to the layout, using the specified constraint object.
*
* @param comp the component to be added
* @param constraints the where/how the component is added to the layout.
* @exception <code>ClassCastException</code> if the argument is not a <code>ToolbarConstraints</code>.
*/
public void addLayoutComponent(Component comp, Object constr)
{
if (!(constr instanceof ToolbarConstraints)) throw new IllegalArgumentException("EXC_wrongConstraints"); //$NON-NLS-1$
componentMap.put(comp, constr);
ToolbarConstraints tc = (ToolbarConstraints)constr;
tc.setPreferredSize(comp.getPreferredSize());
comp.setVisible(tc.isVisible());
}
/**
* Removes the specified component from this layout.
*
* @param comp the component to be removed
*/
public void removeLayoutComponent(Component comp)
{
componentMap.remove(comp);
}
/**
* Calculates the preferred dimension for the specified panel given the components in the specified parent container.
*
* @param parent the component to be laid out
*
* @see #minimumLayoutSize
*/
public Dimension preferredLayoutSize(Container parent)
{
Insets insets = parent.getInsets();
Dimension prefSize = new Dimension(insets.left + toolbarConfig.getPrefWidth() + insets.right, insets.top + toolbarConfig.getPrefHeight() +
insets.bottom);
return prefSize;
}
/**
* Calculates the minimum dimension for the specified panel given the components in the specified parent container.
*
* @param parent the component to be laid out
* @see #preferredLayoutSize
*/
public Dimension minimumLayoutSize(Container parent)
{
return preferredLayoutSize(parent);
}
/**
* Returns the maximum size of this component.
*
* @see java.awt.Component#getMinimumSize()
* @see java.awt.Component#getPreferredSize()
* @see LayoutManager
*/
public Dimension maximumLayoutSize(Container parent)
{
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
* Returns the alignment along the x axis. This specifies how the component would like to be aligned relative to other components. The value should be a
* number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5 is centered, etc.
*/
public float getLayoutAlignmentX(Container parent)
{
return 0;
}
/**
* Returns the alignment along the y axis. This specifies how the component would like to be aligned relative to other components. The value should be a
* number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5 is centered, etc.
*/
public float getLayoutAlignmentY(Container parent)
{
return 0;
}
/**
* Invalidates the layout, indicating that if the layout manager has cached information it should be discarded.
*/
public void invalidateLayout(Container parent)
{
}
/**
* Lays out the container in the specified panel.
*
* @param parent the component which needs to be laid out
*/
public void layoutContainer(Container parent)
{
synchronized (parent.getTreeLock())
{
Insets insets = parent.getInsets();
boolean ltr = parent.getComponentOrientation().isLeftToRight();
if (!ltr)
{
insets.right += insets.left;
insets.left = insets.right - insets.left;
insets.right -= insets.left;
}
int maxPosition = parent.getWidth() - (insets.left + insets.right) - HGAP;
Iterator it;
Component comp;
ToolbarConstraints constr;
Rectangle bounds;
/*
* It is very important to update preferred sizes for each component because when any component change it's size it can affect to other components'
* size and position.
*/
it = componentMap.keySet().iterator();
while (it.hasNext())
{
comp = (Component)it.next();
constr = (ToolbarConstraints)componentMap.get(comp);
constr.updatePreferredSize(comp.getPreferredSize());
}
/* Setting components' bounds. */
it = componentMap.keySet().iterator();
while (it.hasNext())
{
comp = (Component)it.next();
constr = (ToolbarConstraints)componentMap.get(comp);
/* ToolbarConstraints has component bounds prepared. */
bounds = constr.getBounds();
if ((bounds.x < maxPosition) && /* If component starts on visible position ... */
(bounds.x + bounds.width > maxPosition))
{ /* ... but with width it is over visible area ... */
bounds.width = maxPosition - bounds.x; /* ... so width is cropped to max possible. */
}
else
{
if (bounds.x > maxPosition + HGAP)
{ /* If component is over visible position ... */
constr.setPosition(maxPosition + HGAP); /* ... new position is setted to min invisible. */
constr.updatePosition();
}
}
if (!ltr)
{
bounds.x = maxPosition - bounds.x - bounds.width;
}
comp.setBounds(bounds);
}
}
}
}