/* * Copyright (c) 2011, Nikolaus Moll * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of the jo-widgets.org nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 jo-widgets.org 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 org.jowidgets.impl.layout.tablelayout; import java.util.HashMap; import java.util.List; import org.jowidgets.api.layout.tablelayout.ITableLayout; import org.jowidgets.api.layout.tablelayout.ITableLayoutBuilder.Alignment; import org.jowidgets.api.layout.tablelayout.ITableRowLayout; import org.jowidgets.api.widgets.IContainer; import org.jowidgets.api.widgets.IControl; import org.jowidgets.common.types.Dimension; import org.jowidgets.common.types.Rectangle; /** * This layout manager would appreciate events on new children * */ public final class TableRowLayout implements ITableRowLayout { private final IContainer container; private final ITableLayout rowLayoutCommon; private final HashMap<IControl, Dimension> preferredSizes; private final HashMap<Integer, IControl> controls; private final HashMap<IControl, Integer> spans; private final boolean ignoreInCalculations; private int layoutHashCode; private int nextIndex; public TableRowLayout(final IContainer container, final ITableLayout rowLayoutCommon, final boolean ignoreInCalculations) { this.container = container; this.rowLayoutCommon = rowLayoutCommon; this.preferredSizes = new HashMap<IControl, Dimension>(); this.controls = new HashMap<Integer, IControl>(); this.layoutHashCode = 0; this.spans = new HashMap<IControl, Integer>(); this.ignoreInCalculations = ignoreInCalculations; rowLayoutCommon.addRowLayout(this); nextIndex = 0; } @Override public IContainer getContainer() { return container; } private IControl getChild(final int index) { if (controls.containsKey(Integer.valueOf(index))) { return controls.get(index); } final List<IControl> children = container.getChildren(); for (final IControl control : children) { initControl(control); } return controls.get(index); } private Dimension getPreferredSize(final IControl control) { if (!preferredSizes.containsKey(control)) { final Dimension size = control.getPreferredSize(); if (size.getHeight() > 0) { preferredSizes.put(control, size); } return size; } return preferredSizes.get(control); } @Override public Dimension getPreferredSize(final int index) { final IControl control = getChild(index); if (control == null) { return null; } return getPreferredSize(control); } @Override public void layout() { final Rectangle clientArea = container.getClientArea(); if (clientArea.getHeight() <= 1) { // no valid layout return; } rowLayoutCommon.validate(); if (layoutHashCode == rowLayoutCommon.getLayoutHashCode()) { return; } layoutHashCode = rowLayoutCommon.getLayoutHashCode(); final int[] gaps = rowLayoutCommon.getGaps(); final int[] widths = rowLayoutCommon.getWidths(); final Alignment[] alignments = rowLayoutCommon.getAlignments(); int x = gaps[0]; int index = 0; while (index < widths.length) { final IControl control = getChild(index); final int span = getSpan(control); final int width = getSpanWidth(index, span, widths, gaps); if (control != null) { int controlWidth = width; final Dimension size = getPreferredSize(control); final int y = clientArea.getY() + (clientArea.getHeight() - size.getHeight()) / 2; if (alignments[index] == Alignment.CENTER) { controlWidth = size.getWidth(); } control.setSize(controlWidth, size.getHeight()); control.setPosition(x + (width - controlWidth) / 2, y); } index = index + span; x = x + width + gaps[index]; } } @Override public Dimension getMinSize() { return getPreferredSize(); } @Override public Dimension getPreferredSize() { return rowLayoutCommon.getPreferredSize(); } @Override public Dimension getMaxSize() { return getPreferredSize(); } @Override public void invalidate() { layout(); } @Override public void remove() { rowLayoutCommon.removeRowLayout(this); } private int getValueFromConstraints(final String constraints, final String valueName, final int defaultValue) { if (constraints != null) { final String lowerValueName = valueName.toLowerCase(); for (final String constraint : constraints.toLowerCase().split(",")) { final String c = constraint.trim(); if (c.startsWith(lowerValueName)) { final String value = c.substring(lowerValueName.length()).trim(); try { return Integer.parseInt(value); } catch (final Exception e) { return defaultValue; } } } } return defaultValue; } private int getSpan(final IControl control) { final Integer result = spans.get(control); if (result == null) { return 1; } else { return result.intValue(); } } private void initControl(final IControl control) { if (spans.containsKey(control)) { return; } final String constraints = (String) control.getLayoutConstraints(); final int span = getValueFromConstraints(constraints, "span", 1); spans.put(control, span); final int index = getValueFromConstraints(constraints, "index", nextIndex); controls.put(index, control); nextIndex = nextIndex + span; } private int getSpanWidth(final int index, final int span, final int[] widths, final int[] gaps) { int result = widths[index]; for (int i = 1; i < span; i++) { result = result + gaps[index + i] + widths[index + i]; } return result; } @Override public boolean isIgnoredInCalculations() { return ignoreInCalculations; } @Override public void invalidateControl(final IControl control) { preferredSizes.remove(control); } }