/*
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.smart.dataui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.Border;
import javax.swing.text.html.CSS;
import com.servoy.j2db.ControllerUndoManager;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.IDataRendererFactory;
import com.servoy.j2db.IFormUIInternal;
import com.servoy.j2db.IScriptExecuter;
import com.servoy.j2db.component.ComponentFactory;
import com.servoy.j2db.dataprocessing.IDisplay;
import com.servoy.j2db.dataprocessing.IDisplayData;
import com.servoy.j2db.persistence.Field;
import com.servoy.j2db.persistence.Form;
import com.servoy.j2db.persistence.GraphicalComponent;
import com.servoy.j2db.persistence.IDataProviderLookup;
import com.servoy.j2db.persistence.IFormElement;
import com.servoy.j2db.persistence.IPersist;
import com.servoy.j2db.persistence.ISupportAnchors;
import com.servoy.j2db.persistence.ISupportPrintSliding;
import com.servoy.j2db.persistence.ISupportPrinting;
import com.servoy.j2db.persistence.ISupportTabSeq;
import com.servoy.j2db.persistence.Part;
import com.servoy.j2db.persistence.Portal;
import com.servoy.j2db.persistence.PositionComparator;
import com.servoy.j2db.smart.SwingForm;
import com.servoy.j2db.ui.IDataRenderer;
import com.servoy.j2db.ui.IFieldComponent;
import com.servoy.j2db.ui.ILabel;
import com.servoy.j2db.util.ComponentFactoryHelper;
import com.servoy.j2db.util.EnableScrollPanel;
import com.servoy.j2db.util.IStyleRule;
import com.servoy.j2db.util.IStyleSheet;
import com.servoy.j2db.util.ISupplyFocusChildren;
import com.servoy.j2db.util.Pair;
import com.servoy.j2db.util.ScopesUtils;
import com.servoy.j2db.util.SortedList;
import com.servoy.j2db.util.TabSequenceHelper;
import com.servoy.j2db.util.gui.AnchorLayout;
import com.servoy.j2db.util.gui.FixedSpringLayout;
import com.servoy.j2db.util.gui.Spring;
/**
* Factory for Swing datarenderers
*
* @author jblok
*/
public class DataRendererFactory implements IDataRendererFactory<Component>
{
public IDataRenderer getEmptyDataRenderer(String Id, String name, IApplication app, boolean showSelection)
{
DataRenderer dr = new DataRenderer(app, showSelection);
dr.putClientProperty("Id", Id);
dr.setName(name);
return dr;
}
private void setBasicSettings(IDataRenderer panel, Color bg, Dimension size, Point location, boolean printing)
{
DataRenderer dr = (DataRenderer)panel;
if (dr != null)
{
if (bg != null)
{
dr.setBackground(bg);
}
if (printing)
{
dr.setLayout(new FixedSpringLayout());
}
else
{
dr.setLayout(new AnchorLayout(size));
dr.setPreferredSize(size);
}
dr.setSize(size);
dr.setLocation(location);
}
}
public IDataRenderer createPortalRenderer(IApplication app, Portal objToRender, Form dataProviderLookup, IScriptExecuter listner, boolean printing,
ControllerUndoManager undoManager) throws Exception
{
List<IPersist> allObjectsAsList = objToRender.getAllObjectsAsList();
List<IFormElement> formElements = new ArrayList<IFormElement>(allObjectsAsList.size());
for (IPersist persist : allObjectsAsList)
{
if (persist instanceof IFormElement)
{
formElements.add((IFormElement)persist);
}
}
List<IFormElement> children = new SortedList<IFormElement>(new Comparator<IFormElement>()
{
public int compare(IFormElement o1, IFormElement o2)
{
// reverse order, right order for tab sequence
int result = -PositionComparator.XY_PERSIST_COMPARATOR.compare(o1, o2);
if (result == 0)
{
return (o1.getFormIndex() - o2.getFormIndex());
}
return result;
}
}, formElements);
Iterator<IFormElement> e1 = children.iterator();
Map emptyDataRenderers = new LinkedHashMap();
DataRenderer dr = null;
int height = objToRender.getRowHeight();
boolean calculateHeight = (height == 0);
if (height == 0) height = 100;//for safety
// int leftBorder = 0;
// int bottomBorder = 0;
// if (objToRender.getShowHorizontalLines())
// {
// bottomBorder = 1;
// }
// if (objToRender.getShowVerticalLines())
// {
// leftBorder = 4;
// }
boolean showSelection = objToRender.getShowVerticalLines();
dr = (DataRenderer)getEmptyDataRenderer(ComponentFactory.getWebID(dataProviderLookup, objToRender), "portal_" + objToRender.getName(), app,
showSelection);
setBasicSettings(dr, objToRender.getBackground(), new Dimension(objToRender.getSize().width, height), new Point(0, 0), printing);
emptyDataRenderers.put(new Boolean(true), dr);//first is dummy saying is portal
dr.setLocation(objToRender.getLocation());
Border b = ComponentFactoryHelper.createBorder(objToRender.getBorderType());
Insets ins = new Insets(0, 0, 0, 0);
if (b != null)
{
ins = ComponentFactoryHelper.getBorderInsetsForNoComponent(b);
}
// if (b instanceof EmptyBorder)
// {
// ins = ((EmptyBorder)b).getBorderInsets();
// }
placeElements(e1, app, dataProviderLookup, listner, emptyDataRenderers, objToRender.getSize().width, -(objToRender.getLocation().x + ins.right),
-ins.top, printing, true, undoManager, true, null);
int biggest_width = 10;
int biggest_height = calculateHeight ? 0 : height;
Component[] comps = dr.getComponents();
boolean hasRowBGColorCalc = objToRender.getRowBGColorCalculation() != null;
for (Component element : comps)
{
int w = element.getLocation().x + element.getSize().width;
if (w > biggest_width) biggest_width = w;
if (hasRowBGColorCalc && element instanceof JComponent) ((JComponent)element).setOpaque(false);
if (calculateHeight)
{
int h = element.getLocation().y + element.getSize().height;
if (h > biggest_height) biggest_height = h;
}
}
dr.setSize(new Dimension(biggest_width, biggest_height));
dr.setPreferredSize(new Dimension(biggest_width, biggest_height));
if (printing)
{
addSpringsBetweenComponents(app, dr);//sliding inside a multiline portal renderer is nor supported, be we have to attach the springs for resizes
}
return dr;
}
/**
* Fills all the panels provided in emptyDataRenderers with the components from the form
*
* @param form the form to work with
* @param emptyDataRenderers the orderedHashmap with the Part -> DataRenderer
* @param insets for any border
* @param with of all parts
* @return usesSliding
*/
public Map completeRenderers(IApplication app, Form form, IScriptExecuter listner, Map emptyDataRenderers, int width, boolean printing,
ControllerUndoManager undoManager, TabSequenceHelper<Component> tabSequence) throws Exception
{
int partHeight = 0;
boolean formHasBgImage = false;
Pair<IStyleSheet, IStyleRule> formStyle = ComponentFactory.getCSSPairStyleForForm(app, form);
if (formStyle != null && formStyle.getRight() != null && formStyle.getRight().hasAttribute(CSS.Attribute.BACKGROUND_IMAGE.toString()))
{
formHasBgImage = true;
}
Iterator e2 = form.getParts();
while (e2.hasNext())
{
Part part = (Part)e2.next();
Color bg = ComponentFactory.getPartBackground(app, part, form);
if (bg == null && printing) bg = Color.white;
DataRenderer panel = (DataRenderer)emptyDataRenderers.get(part);
if (panel != null)
{
panel.setDoubleBuffered(!printing);
int total = Math.abs(part.getHeight() - partHeight);
setBasicSettings(panel, bg, new Dimension(width, total), new Point(0, partHeight), printing);
}
partHeight = part.getHeight();
// revert css3 features
Pair<IStyleSheet, IStyleRule> pair = ComponentFactory.getStyleForBasicComponent(app, part, form);
if (panel != null)
{
// panel.setBgColor(part.getBackground());
if (pair != null && pair.getRight() != null && pair.getLeft() != null)
{
// panel.setCssRule(pair.getRight());
Border border = pair.getLeft().getBorder(pair.getRight());
if (border != null)
{
panel.setBorder(border);
}
}
// boolean partHasBgColor = (part.getBackground() != null) ||
// (pair != null && pair.getRight() != null && pair.getRight().hasAttribute(CSS.Attribute.BACKGROUND_COLOR.toString()));
// if (!form.getTransparent() && (formHasBgImage || (partHasBgColor && bg.getAlpha() < 255)))
// {
// panel.setPaintBackgroundOnTopOfFormImage(true);
// }
}
}
//place all the elements
Iterator<IFormElement> e1 = form.getFormElementsSortedByFormIndex();
return placeElements(e1, app, form, listner, emptyDataRenderers, width, 0, 0, printing, false, undoManager, false, tabSequence);
}
//returns usesSliding
private Map placeElements(Iterator<IFormElement> e1, IApplication app, Form form, IScriptExecuter listner, Map emptyDataRenderers, int width,
int XCorrection, int YCorrection, boolean printing, boolean cutDataProviderNames, ControllerUndoManager undoManager, boolean isPortal,
TabSequenceHelper<Component> tabSequence) throws Exception
{
IDataProviderLookup dataProviderLookup = app.getFlattenedSolution().getDataproviderLookup(app.getFoundSetManager(), form);
Map listTocomplete = new HashMap();
Map labelForComponents = new HashMap();
// Insets insets = new Insets(0, 0, 0, 0);
while (e1.hasNext())
{
Point l = null;
IPersist obj = e1.next();
l = ((IFormElement)obj).getLocation();
if (l == null) continue;//unkown where to add
if (printing && obj instanceof ISupportPrinting)
{
if (!((ISupportPrinting)obj).getPrintable()) continue;
}
Iterator it = emptyDataRenderers.values().iterator();
while (it.hasNext())
{
DataRenderer panel = (DataRenderer)it.next();
int start = panel.getLocation().y;
if (l.y >= start && l.y < start + panel.getSize().height)
{
Component comp = (Component)ComponentFactory.createComponent(app, form, obj, dataProviderLookup, listner, printing);
// Test for a visible bean, then get the real component
if (comp instanceof VisibleBean)
{
comp = ((VisibleBean)comp).getDelegate();
}
if (comp != null)
{
if (obj instanceof Field && comp instanceof JComponent)
{
String name = ((Field)obj).getName();
if (name != null && !"".equals(name))
{
labelForComponents.put(name, comp);
}
}
else if (obj instanceof GraphicalComponent && comp instanceof JLabel)
{
String labelFor = ((GraphicalComponent)obj).getLabelFor();
if (labelFor != null && !"".equals(labelFor))
{
labelForComponents.put(comp, labelFor);
}
}
if (obj instanceof ISupportTabSeq && comp instanceof JComponent && (tabSequence != null))
{
tabSequence.add(panel, (ISupportTabSeq)obj, comp);
}
Component newComp = comp;
if (newComp instanceof IDisplay)
{
//HACK:don;t no other way to do this.........
if (newComp instanceof IDisplayData && cutDataProviderNames)
{
IDisplayData da = (IDisplayData)newComp;
String id = da.getDataProviderID();
if (id != null && !ScopesUtils.isVariableScope(id))
{
int index = id.indexOf('.'); // only cut first relation (so you can have relation chain inside portal)
//TODO:check if part before . is same as relation name (objToRender.getRelationID() )
if (index > 0)
{
id = id.substring(index + 1);
}
da.setDataProviderID(id);
}
}
panel.addDisplayComponent(obj, (IDisplay)newComp);
}
comp.setLocation((l.x /* +insets.left */) + XCorrection, (l.y - start) + YCorrection);
int index = 0;
if (!printing && obj instanceof ISupportAnchors)
{
panel.add(comp, new Integer(((ISupportAnchors)obj).getAnchors()), index);
}
else if (printing)
{
if (obj instanceof ISupportPrintSliding && !isPortal)
{
int slide = ((ISupportPrintSliding)obj).getPrintSliding();
if (slide != ISupportPrintSliding.NO_SLIDING)
{
listTocomplete.put(comp, new Integer(slide));
panel.setUsingSliding(true);
}
}
panel.add(comp, index);
}
else
{
panel.add(comp, index);
}
}
}
}
}
if (!printing)
{
Iterator it = labelForComponents.entrySet().iterator();
while (it.hasNext())
{
Map.Entry entry = (Entry)it.next();
if (entry.getKey() instanceof JLabel)
{
JComponent component = (JComponent)labelForComponents.get(entry.getValue());
if (component != null)
{
((JLabel)entry.getKey()).setLabelFor(component);
if (component instanceof IFieldComponent)
{
((IFieldComponent)component).addLabelFor((ILabel)entry.getKey());
if (!((IFieldComponent)component).isVisible())
{
((IFieldComponent)component).setComponentVisible(((IFieldComponent)component).isVisible());
}
if (!((IFieldComponent)component).isEnabled())
{
((IFieldComponent)component).setComponentEnabled(((IFieldComponent)component).isEnabled());
}
}
}
}
}
}
Iterator it = emptyDataRenderers.values().iterator();
while (it.hasNext())
{
DataRenderer panel = (DataRenderer)it.next();
panel.createDataAdapter(app, dataProviderLookup, listner, undoManager);
}
return listTocomplete;
}
@Override
public void prepareRenderers(IApplication application, Form form)
{
}
public static void addSpringsBetweenComponents(IApplication application, DataRenderer panel)
{
Map componentsListToBeHandeldOnX = new HashMap();
Map componentsListToBeHandeldOnY = new HashMap();
Map componentsListToBeHandeldOnWidth = new HashMap();
Map componentsListToBeHandeldOnHeigth = new HashMap();
FixedSpringLayout sl = (FixedSpringLayout)panel.getLayout();
FixedSpringLayout.Constraints pcons = sl.getConstraints(panel);
Component[] allc = panel.getComponents();
for (Component comp : allc)
{
if (comp instanceof EnableScrollPanel)
{
((EnableScrollPanel)comp).setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
((EnableScrollPanel)comp).setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
}
int slide = ISupportPrintSliding.NO_SLIDING;
Map componentsListToBeHandeld = panel.getComponentsUsingSliding();
if (componentsListToBeHandeld != null && componentsListToBeHandeld.containsKey(comp))
{
slide = ((Integer)componentsListToBeHandeld.get(comp)).intValue();
for (Component ccomp : allc)
{
if (slide != ISupportPrintSliding.NO_SLIDING && ccomp != comp && ccomp.getBounds().intersects(comp.getBounds()))
{
application.reportJSError(
application.getI18NMessage("servoy.sliding.error.overlap"), application.getI18NMessage("servoy.sliding.error.overlap.components", new Object[] { comp, ccomp })); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
Spring sx = Spring.constant(comp.getX());
Spring sy = Spring.constant(comp.getY());
Spring sw = Spring.constant(comp.getWidth());
Spring sh = Spring.constant(comp.getHeight());
if (((slide & ISupportPrintSliding.ALLOW_MOVE_MIN_X) == ISupportPrintSliding.ALLOW_MOVE_MIN_X) ||
((slide & ISupportPrintSliding.ALLOW_MOVE_PLUS_X) == ISupportPrintSliding.ALLOW_MOVE_PLUS_X))
{
componentsListToBeHandeldOnX.put(comp, new Integer(slide));
}
if (((slide & ISupportPrintSliding.ALLOW_MOVE_MIN_Y) == ISupportPrintSliding.ALLOW_MOVE_MIN_Y) ||
((slide & ISupportPrintSliding.ALLOW_MOVE_PLUS_Y) == ISupportPrintSliding.ALLOW_MOVE_PLUS_Y))
{
componentsListToBeHandeldOnY.put(comp, new Integer(slide));
}
if (((slide & ISupportPrintSliding.GROW_WIDTH) == ISupportPrintSliding.GROW_WIDTH) ||
((slide & ISupportPrintSliding.SHRINK_WIDTH) == ISupportPrintSliding.SHRINK_WIDTH))
{
// if (comp instanceof EnableScrollPanel)
// {
// ((EnableScrollPanel)comp).setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// ((EnableScrollPanel)comp).setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
// }
componentsListToBeHandeldOnWidth.put(comp, new Integer(slide));
int max = Short.MAX_VALUE;
int min = 0;
if (((slide & ISupportPrintSliding.GROW_WIDTH) != ISupportPrintSliding.GROW_WIDTH) &&
((slide & ISupportPrintSliding.SHRINK_WIDTH) == ISupportPrintSliding.SHRINK_WIDTH))
{
min = 0;
max = comp.getWidth();
}
if (((slide & ISupportPrintSliding.GROW_WIDTH) == ISupportPrintSliding.GROW_WIDTH) &&
((slide & ISupportPrintSliding.SHRINK_WIDTH) != ISupportPrintSliding.SHRINK_WIDTH))
{
min = comp.getWidth();
max = Short.MAX_VALUE;
}
sw = new AbsWidthSpring(comp, min, max);
}
if (((slide & ISupportPrintSliding.GROW_HEIGHT) == ISupportPrintSliding.GROW_HEIGHT) ||
((slide & ISupportPrintSliding.SHRINK_HEIGHT) == ISupportPrintSliding.SHRINK_HEIGHT))
{
componentsListToBeHandeldOnHeigth.put(comp, new Integer(slide));
int max = Short.MAX_VALUE;
int min = 0;
if (((slide & ISupportPrintSliding.GROW_HEIGHT) != ISupportPrintSliding.GROW_HEIGHT) &&
((slide & ISupportPrintSliding.SHRINK_HEIGHT) == ISupportPrintSliding.SHRINK_HEIGHT))
{
min = 0;
max = comp.getHeight();
}
if (((slide & ISupportPrintSliding.GROW_HEIGHT) == ISupportPrintSliding.GROW_HEIGHT) &&
((slide & ISupportPrintSliding.SHRINK_HEIGHT) != ISupportPrintSliding.SHRINK_HEIGHT))
{
min = comp.getHeight();
max = Short.MAX_VALUE;
}
sh = new AbsHeightSpring(comp, min, max);
}
FixedSpringLayout.Constraints constr = sl.getConstraints(comp); //new FixedSpringLayout.Constraints(sx,sy,sw,sh);
constr.setX(sx);
constr.setY(sy);
constr.setWidth(sw);
constr.setHeight(sh);
}
Component[] allSortedXy = new Component[allc.length];
System.arraycopy(allc, 0, allSortedXy, 0, allc.length);
Arrays.sort(allSortedXy, PositionComparator.XY_COMPONENT_COMPARATOR);
Component[] allSortedYx = new Component[allc.length];
System.arraycopy(allc, 0, allSortedYx, 0, allc.length);
Arrays.sort(allSortedYx, PositionComparator.YX_COMPONENT_COMPARATOR);
// add west component spring for sliding components that can move horizontally, to set component location
Iterator it1 = componentsListToBeHandeldOnX.keySet().iterator();
while (it1.hasNext())
{
Component element1 = (Component)it1.next();
BarSpring bs = null;
int minXSpaceOnLeft = Integer.MAX_VALUE; // X space left to the element1's WEST border from
// components on X exactly on the left of element1
ArrayList slidingComponentsOnLeft = new ArrayList(); // sliding X components that are exactly on the left of element1
Component rightMostNonSlidingLastComponentOnLeft = null; // the right most non sliding component that is on the left of element1
int xSpaceForRightmostNonSlidingLastComponentOnLeft = Integer.MAX_VALUE;
for (Component element2 : allSortedYx)
{
boolean isExactlyOnLeftOfElement1 = true;
if (element2 == element1) continue;
Rectangle join = createSmallestHorizontalJoin(element2.getBounds(), element1.getBounds());
if (join == null || join.isEmpty())
{
isExactlyOnLeftOfElement1 = false;
}
else
{
for (Component element3 : allSortedYx)
{
if (element3 != element1 && element3 != element2 && join.intersects(element3.getBounds()))
{
isExactlyOnLeftOfElement1 = false;
break;//too large, contains other eleemnts in between
}
}
}
if (isExactlyOnLeftOfElement1)
{
int xSpace = element1.getX() - (element2.getX() + element2.getWidth());
minXSpaceOnLeft = Math.min(minXSpaceOnLeft, xSpace);
if (componentsListToBeHandeldOnWidth.containsKey(element2) || componentsListToBeHandeldOnX.containsKey(element2))
{
slidingComponentsOnLeft.add(element2);
}
else
{
if (xSpaceForRightmostNonSlidingLastComponentOnLeft > xSpace)
{
xSpaceForRightmostNonSlidingLastComponentOnLeft = xSpace;
rightMostNonSlidingLastComponentOnLeft = element2;
}
}
}
}
if (rightMostNonSlidingLastComponentOnLeft != null)
{
bs = new BarSpring();
sl.getConstraints(element1).setConstraint(FixedSpringLayout.WEST, bs);
bs.add(Spring.sum(Spring.constant(minXSpaceOnLeft, minXSpaceOnLeft, Short.MAX_VALUE),
sl.getConstraint(FixedSpringLayout.EAST, rightMostNonSlidingLastComponentOnLeft)));
}
else if (slidingComponentsOnLeft.size() > 0)
{
bs = new BarSpring();
sl.getConstraints(element1).setConstraint(FixedSpringLayout.WEST, bs);
}
for (int i = slidingComponentsOnLeft.size() - 1; i >= 0; i--)
{
bs.add(Spring.sum(Spring.constant(minXSpaceOnLeft, minXSpaceOnLeft, Short.MAX_VALUE),
sl.getConstraint(FixedSpringLayout.EAST, (Component)slidingComponentsOnLeft.get(i))));
}
}
// add north component spring for sliding components that allow vertical move, to set component location
Iterator it2 = componentsListToBeHandeldOnY.keySet().iterator();
while (it2.hasNext())
{
Component element1 = (Component)it2.next();
BarSpring bs = null;
int minYSpaceOnTop = Integer.MAX_VALUE; // Y space left to the element1's NORTH border from
// components on Y right on top of element1
ArrayList slidingComponentsOnTop = new ArrayList(); // sliding Y components that are right on top of element1
Component lowestNonSlidingLastComponentOnTop = null; // the lowest non sliding component that is on top of element1
int ySpaceForLowestNonSlidingLastComponentOnTop = Integer.MAX_VALUE;
for (Component element2 : allSortedXy)
{
boolean isRightOnTopOfElement1 = true;
if (element2 == element1) continue;
Rectangle join = createSmallestVerticalJoin(element2.getBounds(), element1.getBounds());
if (join == null || join.isEmpty())
{
isRightOnTopOfElement1 = false;
}
else
{
for (Component element3 : allSortedXy)
{
if (element3 != element1 && element3 != element2 && join.intersects(element3.getBounds()))
{
isRightOnTopOfElement1 = false;
break;//too large, contains other elements in between
}
}
}
if (isRightOnTopOfElement1)
{
int ySpace = element1.getY() - (element2.getY() + element2.getHeight());
minYSpaceOnTop = Math.min(minYSpaceOnTop, ySpace);
if (componentsListToBeHandeldOnHeigth.containsKey(element2) || componentsListToBeHandeldOnY.containsKey(element2))
{
slidingComponentsOnTop.add(element2);
}
else
{
if (ySpaceForLowestNonSlidingLastComponentOnTop > ySpace)
{
ySpaceForLowestNonSlidingLastComponentOnTop = ySpace;
lowestNonSlidingLastComponentOnTop = element2;
}
}
}
}
if (lowestNonSlidingLastComponentOnTop != null)
{
bs = new BarSpring();
sl.getConstraints(element1).setConstraint(FixedSpringLayout.NORTH, bs);
bs.add(Spring.sum(Spring.constant(minYSpaceOnTop, minYSpaceOnTop, Short.MAX_VALUE),
sl.getConstraint(FixedSpringLayout.SOUTH, lowestNonSlidingLastComponentOnTop)));
}
else if (slidingComponentsOnTop.size() > 0)
{
bs = new BarSpring();
sl.getConstraints(element1).setConstraint(FixedSpringLayout.NORTH, bs);
}
for (int i = slidingComponentsOnTop.size() - 1; i >= 0; i--)
{
bs.add(Spring.sum(Spring.constant(minYSpaceOnTop, minYSpaceOnTop, Short.MAX_VALUE),
sl.getConstraint(FixedSpringLayout.SOUTH, (Component)slidingComponentsOnTop.get(i))));
}
}
// add east panel spring, to set Panel width
Rectangle pb = panel.getBounds();
BarSpring bs = null;
int spaceToRightMargin = 0;
if (componentsListToBeHandeldOnWidth.size() > 0)
{
int minWidthLeft = Integer.MAX_VALUE; // width left to the part's EAST border from the right-most component on Y
ArrayList lastSlidingComponentsOnX = new ArrayList(); // sliding X components that are last on X axis
Component lowestNonSlidingLastComponentOnX = null; // the right most non sliding component that is last on X axis
int widthLeftForLowestNonSlidingLastComponentOnX = Integer.MAX_VALUE;
for (int i = allSortedXy.length - 1; i >= 0; i--)
{
boolean isALastComponentOnX = true; // are there no other components between it and the part east border?
Component element = allSortedXy[i];
Rectangle rect1 = new Rectangle(element.getBounds());
int widthLeft = pb.width - (rect1.x + rect1.width);
rect1.width += widthLeft;
for (Component element2 : allSortedXy)
{
if (element2 != element && element.getBounds().intersects(element2.getBounds()))
{
//overlapping elements
continue;
}
if (element2 != element && rect1.intersects(element2.getBounds()))
{
isALastComponentOnX = false;
break; //too large, contains other elements in between
}
}
if (isALastComponentOnX)
{
minWidthLeft = Math.min(minWidthLeft, widthLeft);
if (componentsListToBeHandeldOnWidth.containsKey(element) || componentsListToBeHandeldOnX.containsKey(element))
{
lastSlidingComponentsOnX.add(element);
}
else
{
if (widthLeftForLowestNonSlidingLastComponentOnX > widthLeft)
{
widthLeftForLowestNonSlidingLastComponentOnX = widthLeft;
lowestNonSlidingLastComponentOnX = element;
}
}
}
}
// add springs needed to determine the width of the part
if (lowestNonSlidingLastComponentOnX != null)
{
bs = new BarSpring();
pcons.setConstraint(FixedSpringLayout.EAST, bs);
bs.add(Spring.sum(Spring.constant(minWidthLeft, minWidthLeft, Short.MAX_VALUE),
sl.getConstraint(FixedSpringLayout.EAST, lowestNonSlidingLastComponentOnX)));
spaceToRightMargin = minWidthLeft;
}
else if (lastSlidingComponentsOnX.size() > 0)
{
bs = new BarSpring();
pcons.setConstraint(FixedSpringLayout.EAST, bs);
spaceToRightMargin = minWidthLeft;
}
for (int i = lastSlidingComponentsOnX.size() - 1; i >= 0; i--)
{
bs.add(Spring.sum(Spring.constant(minWidthLeft, minWidthLeft, Short.MAX_VALUE),
sl.getConstraint(FixedSpringLayout.EAST, (Component)lastSlidingComponentsOnX.get(i))));
}
panel.setSpaceToRightMargin(spaceToRightMargin);
}
if (bs == null)//add fixed spring for panel size
{
pcons.setConstraint(FixedSpringLayout.EAST, Spring.constant(panel.getWidth()));
}
// add south panel spring, to set Panel height
bs = null;
if (componentsListToBeHandeldOnHeigth.size() > 0)
{
int minHeightLeft = Integer.MAX_VALUE; // height left to the part's SOUTH border from the lowest component on Y
ArrayList lastSlidingComponentsOnY = new ArrayList(); // sliding Y components that are last on Y axis
Component lowestNonSlidingLastComponentOnY = null; // the lowest non sliding component that is last on Y axis
int heightLeftForLowestNonSlidingLastComponentOnY = Integer.MAX_VALUE;
for (int i = allSortedYx.length - 1; i >= 0; i--)
{
boolean isALastComponentOnY = true; // are there no other components between it and the part south border?
Component element = allSortedYx[i];
Rectangle rect1 = new Rectangle(element.getBounds());
int heightLeft = pb.height - (rect1.y + rect1.height);
rect1.height += heightLeft;
for (Component element2 : allSortedYx)
{
if (element2 != element && element.getBounds().intersects(element2.getBounds()))
{
//overlapping elements
continue;
}
if (element2 != element && rect1.intersects(element2.getBounds()))
{
isALastComponentOnY = false;
break;//too large, contains other elements in between
}
}
if (isALastComponentOnY)
{
minHeightLeft = Math.min(minHeightLeft, heightLeft);
if (componentsListToBeHandeldOnHeigth.containsKey(element) || componentsListToBeHandeldOnY.containsKey(element))
{
lastSlidingComponentsOnY.add(element);
}
else
{
if (heightLeftForLowestNonSlidingLastComponentOnY > heightLeft)
{
heightLeftForLowestNonSlidingLastComponentOnY = heightLeft;
lowestNonSlidingLastComponentOnY = element;
}
}
}
}
// add springs needed to determine the height of the part
if (lowestNonSlidingLastComponentOnY != null)
{
bs = new BarSpring();
pcons.setConstraint(FixedSpringLayout.SOUTH, bs);
bs.add(Spring.sum(Spring.constant(minHeightLeft, minHeightLeft, Short.MAX_VALUE),
sl.getConstraint(FixedSpringLayout.SOUTH, lowestNonSlidingLastComponentOnY)));
}
else if (lastSlidingComponentsOnY.size() > 0)
{
bs = new BarSpring();
pcons.setConstraint(FixedSpringLayout.SOUTH, bs);
}
for (int i = lastSlidingComponentsOnY.size() - 1; i >= 0; i--)
{
bs.add(Spring.sum(Spring.constant(minHeightLeft, minHeightLeft, Short.MAX_VALUE),
sl.getConstraint(FixedSpringLayout.SOUTH, (Component)lastSlidingComponentsOnY.get(i))));
}
}
if (bs == null)//add fixed spring for panel size
{
pcons.setConstraint(FixedSpringLayout.SOUTH, Spring.constant(panel.getHeight()));
}
}
private static Rectangle createSmallestHorizontalJoin(Rectangle r1, Rectangle r2)
{
// while(true)
// {
if (r1.x <= r2.x)
{
if (r2.y + r2.height < r1.y || r2.y > r1.y + r1.height) return new Rectangle();
int y = Math.max(r1.y, r2.y);
return new Rectangle(r1.x, y, (r2.x + r2.width) - r1.x, Math.min(r1.y + r1.height, r2.y + r2.height) - y);
}
else
//swap
{
// Rectangle r = r1;
// r1 = r2;
// r2 = r;
return new Rectangle();
}
// }
}
private static Rectangle createSmallestVerticalJoin(Rectangle r1, Rectangle r2)
{
// while(true)
// {
if (r1.y <= r2.y)
{
if (r2.x + r2.width < r1.x || r2.x > r1.x + r1.width) return new Rectangle();
int x = Math.max(r1.x, r2.x);
return new Rectangle(x, r1.y, Math.min(r1.x + r1.width, r2.x + r2.width) - x, (r2.y + r2.height) - r1.y);
}
else
//swap
{
// Rectangle r = r1;
// r1 = r2;
// r2 = r;
return new Rectangle();
}
// }
}
static class AbsWidthSpring extends Spring.AbstractSpring
{
private final Component c;
private final int minWidth;
private final int maxWidth;
public AbsWidthSpring(Component c)
{
this.c = c;
this.minWidth = c.getMinimumSize().height;
this.maxWidth = c.getMaximumSize().width;
}
public AbsWidthSpring(Component c, int min, int max)
{
this.c = c;
this.minWidth = min;
this.maxWidth = max;
}
@Override
public int getMinimumValue()
{
return minWidth;//c.getMinimumSize().width;
}
@Override
public int getPreferredValue()
{
int pw = c.getPreferredSize().width;
if (pw < minWidth) pw = minWidth;
if (pw > maxWidth) pw = maxWidth;
return pw;
}
@Override
public int getMaximumValue()
{
// We will be doing arithmetic with the results of this call,
// so if a returned value is Integer.MAX_VALUE we will get
// arithmetic overflow. Truncate such values.
return Math.min(Short.MAX_VALUE, maxWidth);
}
}
static class AbsHeightSpring extends Spring.AbstractSpring
{
private final Component c;
private final int minHeight;
private final int maxHeight;
public AbsHeightSpring(Component c)
{
this.c = c;
this.minHeight = c.getMinimumSize().height;
this.maxHeight = c.getMaximumSize().height;
}
public AbsHeightSpring(Component c, int min, int max)
{
this.c = c;
this.minHeight = min;
this.maxHeight = max;
}
@Override
public int getMinimumValue()
{
return minHeight;
}
@Override
public int getPreferredValue()
{
int ph = c.getPreferredSize().height;
if (ph < minHeight) ph = minHeight;
if (ph > maxHeight) ph = maxHeight;
return ph;
}
@Override
public int getMaximumValue()
{
return Math.min(Short.MAX_VALUE, maxHeight);
}
}
private static class BarSpring extends Spring.StaticSpring
{
protected List springs;
public BarSpring()
{
clear();
springs = new ArrayList();
}
@Override
public String toString()
{
return "BarSpring of " + springs.size(); //$NON-NLS-1$
}
public void add(Spring s)
{
springs.add(s);
}
@Override
protected void clear()
{
min = pref = max = size = UNSET;
}
@Override
public void setValue(int size)
{
if (size == UNSET)
{
if (this.size != UNSET)
{
super.setValue(size);
Iterator it = springs.iterator();
while (it.hasNext())
{
Spring element = (Spring)it.next();
element.setValue(UNSET);
}
//Debug.trace("Barsize - clear");
size = UNSET;
return;
}
}
//Debug.trace("Barsize - SET size " + size);
super.setValue(size);
// s1.setStrain(this.getStrain());
// s2.setValue(size - s1.getValue());
}
@Override
public int getMinimumValue()
{
if (min == UNSET)
{
min = 0;//Short.MAX_VALUE;
Iterator it = springs.iterator();
while (it.hasNext())
{
Spring element = (Spring)it.next();
min = Math.max(min, element.getMinimumValue());
}
}
//Debug.trace("Barsize - min " + min);
return min;
}
@Override
public int getPreferredValue()
{
if (pref == UNSET)
{
pref = 0;
Iterator it = springs.iterator();
while (it.hasNext())
{
Spring element = (Spring)it.next();
pref = Math.max(pref, element.getPreferredValue());
}
}
//Debug.trace("Barsize - pref " + pref);
return pref;
}
@Override
public int getMaximumValue()
{
if (max == UNSET)
{
max = Short.MAX_VALUE;
Iterator it = springs.iterator();
while (it.hasNext())
{
Spring element = (Spring)it.next();
max = Math.min(max, element.getMaximumValue());
}
}
//Debug.trace("Barsize - max " + max);
return max;
}
@Override
public int getValue()
{
if (size == UNSET)
{
size = 0;
Iterator it = springs.iterator();
while (it.hasNext())
{
Spring element = (Spring)it.next();
size = Math.max(size, element.getValue());
}
}
//Debug.trace("Barsize - size " + size);
return size;
}
}
public void extendTabSequence(List<Component> tabSequence, IFormUIInternal containerImpl)
{
SwingForm sf = (SwingForm)containerImpl;
JComponent west = sf.getWest();
if (west != null)
{
if (west instanceof ISupplyFocusChildren)
{
ISupplyFocusChildren<Component> s = (ISupplyFocusChildren<Component>)west;
Component[] fchilds = s.getFocusChildren();
for (Component element : fchilds)
{
tabSequence.add(element);
}
}
}
}
public void applyTabSequence(List<Component> tabSequence, IFormUIInternal containerImpl)
{
SwingForm sf = (SwingForm)containerImpl;
sf.setTabSeqComponents(tabSequence);
if (tabSequence != null) sf.setFocusTraversalPolicy(ServoyFocusTraversalPolicy.datarenderPolicy);
else sf.setFocusTraversalPolicy(ServoyFocusTraversalPolicy.defaultPolicy);
}
public void reapplyTabSequence(IFormUIInternal containerImpl, int newBaseTabSequenceIndex)
{
// ignore: used only in web client
}
}