All Downloads are FREE. Search and download functionalities are using the official Maven repository.

wicket.extensions.markup.html.tree.table.MiddleColumnsView Maven / Gradle / Ivy

/*
 * $Id$ $Revision$ $Date$
 * 
 * ==============================================================================
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package wicket.extensions.markup.html.tree.table;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.swing.tree.TreeNode;

import wicket.Component;
import wicket.RequestCycle;
import wicket.Response;
import wicket.extensions.markup.html.tree.table.ColumnLocation.Unit;
import wicket.markup.MarkupStream;
import wicket.markup.html.WebMarkupContainer;
import wicket.response.NullResponse;

/**
 * Class that renders cells of columns aligned in the middle. This class also
 * takes care of counting their widths and of column spans.
 * 
 * @author Matej Knopp
 */
final class MiddleColumnsView extends WebMarkupContainer
{
	private static final long serialVersionUID = 1L;

	private final List columns = new ArrayList();

	private final List components = new ArrayList();

	private TreeNode node;

	private final List renderables = new ArrayList();

	/**
	 * Constructor.
	 * 
	 * @param id
	 *            The component id
	 * @param node
	 *            The tree node
	 */
	public MiddleColumnsView(String id, TreeNode node)
	{
		super(id);
		this.node = node;
	}

	/**
	 * Adds a column to be rendered.
	 * 
	 * @param column
	 *            The column to render
	 * @param component
	 *            The component
	 * @param renderable
	 *            The renderer
	 */
	public void addColumn(IColumn column, Component component, IRenderable renderable)
	{
		if (column.isVisible())
		{
			columns.add(column);
			components.add(component);
			renderables.add(renderable);
		}
	}

	/**
	 * Computes the percentagle widths of columns. If a column spans over other
	 * columns, the widths of those columns will be zero.
	 * 
	 * @return widths of columns
	 */
	protected double[] computeColumnWidths()
	{
		// initialize the columns array
		double result[] = new double[columns.size()];
		Arrays.fill(result, 0d);

		// the sum of weights of all columns
		double sum = 0d;
		double whole = 99.8d;

		// go over all columns, check their alignment and count sum of their
		// weights
		for (Iterator i = columns.iterator(); i.hasNext();)
		{
			IColumn column = (IColumn)i.next();
			// check if the unit is right
			if (column.getLocation().getUnit() != Unit.PROPORTIONAL)
			{
				throw new IllegalStateException("Middle columns must have PROPORTIONAL unit set.");
			}
			sum += column.getLocation().getSize();
		}


		int index = 0; // index of currently processed column

		int spanColumn = 0; // index of column that is spanning over currently
		// processed column (if any)
		int spanLeft = 0; // over how many columns does the spanning column
		// span

		for (Iterator i = columns.iterator(); i.hasNext();)
		{
			IColumn column = (IColumn)i.next();
			int ix = index; // to which column should we append the size
			if (spanLeft > 0) // is there a column spanning over current
			// column?
			{
				ix = spanColumn; // the size should be appended to the
				// spanning
				// column
				--spanLeft;
			}
			// add the percentage size to the column
			result[ix] += Math.round((column.getLocation().getSize()) / sum * whole);

			// wants this column to span and no other column is spanning over
			// this column?
			if (spanLeft == 0 && column.getSpan(node) > 1)
			{
				int maxSpan = columns.size() - columns.indexOf(column); // how
				// many
				// columns
				// left
				int span = column.getSpan(node) - 1; // how much columns want
				// the column to span
				// over
				spanColumn = index; // index of column that is spanning
				spanLeft = span < maxSpan ? span : maxSpan; // set the number of
				// columns spanned
				// over
			}
			++index;
		}

		// count the sum
		double together = 0d;

		for (int i = 0; i < result.length; i++)
		{
			together += result[i];
		}

		// is it bigger than 99.8? that can cause layout problems in IE
		if (together > 99.8d)
		{
			// this can happen - rounding error. just decrease the last one
			for (int i = result.length - 1; i >= 0; --i)
			{
				if (result[i] != 0d)
				{
					result[i] -= together - 99.8d;
					break;
				}
			}

		}

		return result;
	}

	/**
	 * Renders all columns.
	 * 
	 * @param markupStream
	 *            The markup stream of this component
	 */
	protected void onRender(final MarkupStream markupStream)
	{
		final int markupStart = markupStream.getCurrentIndex();
		Response response = RequestCycle.get().getResponse();
		double widths[] = computeColumnWidths();

		boolean rendered = false; // has been at least one column (component,
		// not renderable) rendered?

		NumberFormat nf = NumberFormat.getNumberInstance(Locale.ENGLISH);
		nf.setMaximumFractionDigits(0);
		nf.setMaximumFractionDigits(2);

		for (int i = 0; i < columns.size(); ++i)
		{
			Component component = (Component)components.get(i);
			IRenderable renderable = (IRenderable)renderables.get(i);
			IColumn column = (IColumn)columns.get(i);

			// write the wrapping column markup
			response.write("");
			response.write("");

			if (component != null) // is there a component for current column?
			{
				// render the component
				markupStream.setCurrentIndex(markupStart);
				component.render(markupStream);
				rendered = true;
			}
			else if (renderable != null) // no component - try to render
			// renderable
			{
				renderable.render(node, response);
			}
			else
			{
				// no renderable or component. fail
				throw new IllegalStateException(
						"Either renderable or cell component must be created for this noode");
			}

			// end of wrapping markup
			response.write("\n");

			// does this component span over other columns
			int span = column.getSpan(node);
			if (span > 1)
			{
				// iterate through the columns and if any of them has a
				// component,
				// render the component to null response (otherwise the
				// component will
				// complain that it hasn't been rendered
				for (int j = 1; j < span && i < components.size(); ++j)
				{
					++i;
					if (components.get(i) != null)
					{
						Response old = RequestCycle.get().setResponse(NullResponse.getInstance());
						markupStream.setCurrentIndex(markupStart);
						((Component)components.get(i)).render(markupStream);
						RequestCycle.get().setResponse(old);
						rendered = true;
					}

				}
			}
		}

		// if no component was rendered just advance in the markup stream
		if (rendered == false)
		{
			markupStream.skipComponent();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy