/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* 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.
*/
/* $Id: BlockLayoutManager.java,v 1.19 2004/05/26 04:22:39 gmazza Exp $ */
package org.apache.fop.layoutmgr;
import java.util.ListIterator;
import java.util.ArrayList;
import java.util.List;
import org.apache.fop.datatypes.PercentBase;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.TextInfo;
import org.apache.fop.fo.PropertyManager;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.BlockParent;
import org.apache.fop.area.LineArea;
import org.apache.fop.traits.LayoutProps;
import org.apache.fop.fo.properties.CommonBorderAndPadding;
import org.apache.fop.fo.properties.CommonBackground;
import org.apache.fop.fo.properties.CommonMarginBlock;
import org.apache.fop.traits.MinOptMax;
/**
* LayoutManager for a block FO.
*/
public class BlockLayoutManager extends BlockStackingLayoutManager {
private Block curBlockArea;
private LayoutProps layoutProps;
private CommonBorderAndPadding borderProps;
private CommonBackground backgroundProps;
private CommonMarginBlock marginProps;
/* holds the (one-time use) fo:block space-before
and -after properties. Large fo:blocks are split
into multiple Area.Blocks to accomodate the subsequent
regions (pages) they are placed on. space-before
is applied at the beginning of the first
Block and space-after at the end of the last Block
used in rendering the fo:block.
*/
private MinOptMax foBlockSpaceBefore = null;
// need to retain foBlockSpaceAfter from previous instantiation
private static MinOptMax foBlockSpaceAfterpre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long *//*
@VaadinApache2LicenseForJavaFiles@
*/
package com.vaadin.data.util;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
/**
* <p>
* The <code>QueryContainer</code> is the specialized form of Container which is
* Ordered and Indexed. This is used to represent the contents of relational
* database tables accessed through the JDBC Connection in the Vaadin Table.
* This creates Items based on the queryStatement provided to the container.
* </p>
*
* <p>
* The <code>QueryContainer</code> can be visualized as a representation of a
* relational database table.Each Item in the container represents the row
* fetched by the query.All cells in a column have same data type and the data
* type information is retrieved from the metadata of the resultset.
* </p>
*
* <p>
* Note : If data in the tables gets modified, Container will not get reflected
* with the updates, we have to explicity invoke QueryContainer.refresh method.
* {@link com.vaadin.data.util.QueryContainer#refresh() refresh()}
* </p>
*
* @see com.vaadin.data.Container
*
* @author Vaadin Ltd.
* @since 4.0
*
* @deprecated will be removed in the future, use the SQLContainer add-on
*/
@Deprecated
@SuppressWarnings("serial")
public class QueryContainer implements Container, Container.Ordered,
Container.Indexed {
// default ResultSet type
public static final int DEFAULT_RESULTSET_TYPE = ResultSet.TYPE_SCROLL_INSENSITIVE;
// default ResultSet concurrency
public static final int DEFAULT_RESULTSET_CONCURRENCY = ResultSet.CONCUR_READ_ONLY;
private int resultSetType = DEFAULT_RESULTSET_TYPE;
private int resultSetConcurrency = DEFAULT_RESULTSET_CONCURRENCY;
private final String queryStatement;
private final Connection connection;
private ResultSet result;
private Collection<String> propertyIds;
private final HashMap<String, Class<?>> propertyTypes = new HashMap<String, Class<?>>();
private int size = -1;
private Statement statement;
/**
* Constructs new <code>QueryContainer</code> with the specified
* <code>queryStatement</code>.
*
* @param queryStatement
* Database query
* @param connection
* Connection object
* @param resultSetType
* @param resultSetConcurrency
* @throws SQLException
* when database operation fails
*/
public QueryContainer(String queryStatement, Connection connection,
int resultSetType, int resultSetConcurrency) throws SQLException {
this.queryStatement = queryStatement;
this.connection = connection;
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
init();
}
/**
* Constructs new <code>QueryContainer</code> with the specified
* queryStatement using the default resultset type and default resultset
* concurrency.
*
* @param queryStatement
* Database query
* @param connection
* Connection object
* @see QueryContainer#DEFAULT_RESULTSET_TYPE
* @see QueryContainer#DEFAULT_RESULTSET_CONCURRENCY
* @throws SQLException
* when database operation fails
*/
public QueryContainer(String queryStatement, Connection connection)
throws SQLException {
this(queryStatement, connection, DEFAULT_RESULTSET_TYPE,
DEFAULT_RESULTSET_CONCURRENCY);
}
/**
* Fills the Container with the items and properties. Invoked by the
* constructor.
*
* @throws SQLException
* when parameter initialization fails.
* @see QueryContainer#QueryContainer(String, Connection, int, int).
*/
private void init() throws SQLException {
refresh();
ResultSetMetaData metadata;
metadata = result.getMetaData();
final int count = metadata.getColumnCount();
final ArrayList<String> list = new ArrayList<String>(count);
for (int i = 1; i <= count; i++) {
final String columnName = metadata.getColumnName(i);
list.add(columnName);
final Property<?> p = getContainerProperty(new Integer(1),
columnName);
propertyTypes.put(columnName,
p == null ? Object.class : p.getType());
}
propertyIds = Collections.unmodifiableCollection(list);
}
/**
* <p>
* Restores items in the container. This method will update the latest data
* to the container.
* </p>
* Note: This method should be used to update the container with the latest
* items.
*
* @throws SQLException
* when database operation fails
*
*/
public void refresh() throws SQLException {
close();
statement = connection.createStatement(resultSetType,
resultSetConcurrency);
result = statement.executeQuery(queryStatement);
result.last();
size = result.getRow();
}
/**
* Releases and nullifies the <code>statement</code>.
*
* @throws SQLException
* when database operation fails
*/
public void close() throws SQLException {
if (statement != null) {
statement.close();
}
statement = null;
}
/**
* Gets the Item with the given Item ID from the Container.
*
* @param id
* ID of the Item to retrieve
* @return Item Id.
*/
@Override
public Item getItem(Object id) {
return new Row(id);
}
/**
* Gets the collection of propertyId from the Container.
*
* @return Collection of Property ID.
*/
@Override
public Collection<String> getContainerPropertyIds() {
return propertyIds;
}
/**
* Gets an collection of all the item IDs in the container.
*
* @return collection of Item IDs
*/
@Override
public Collection<?> getItemIds() {
final Collection<Integer> c = new ArrayList<Integer>(size);
for (int i = 1; i <= size; i++) {
c.add(new Integer(i));
}
return c;
}
/**
* Gets the property identified by the given itemId and propertyId from the
* container. If the container does not contain the property
* <code>null</code> is returned.
*
* @param itemId
* ID of the Item which contains the Property
* @param propertyId
* ID of the Property to retrieve
*
* @return Property with the given ID if exists; <code>null</code>
* otherwise.
*/
@Override
public synchronized Property<?> getContainerProperty(Object itemId,
Object propertyId) {
if (!(itemId instanceof Integer && propertyId instanceof String)) {
return null;
}
Object value;
try {
result.absolute(((Integer) itemId).intValue());
value = result.getObject((String) propertyId);
} catch (final Exception e) {
return null;
}
// Handle also null values from the database
return new ObjectProperty<Object>(value != null ? value
: new String(""));
}
/**
* Gets the data type of all properties identified by the given type ID.
*
* @param id
* ID identifying the Properties
*
* @return data type of the Properties
*/
@Override
public Class<?> getType(Object id) {
return propertyTypes.get(id);
}
/**
* Gets the number of items in the container.
*
* @return the number of items in the container.
*/
@Override
public int size() {
return size;
}
/**
* Tests if the list contains the specified Item.
*
* @param id
* ID the of Item to be tested.
* @return <code>true</code> if given id is in the container;
* <code>false</code> otherwise.
*/
@Override
public boolean containsId(Object id) {
if (!(id instanceof Integer)) {
return false;
}
final int i = ((Integer) id).intValue();
if (i < 1) {
return false;
}
if (i > size) {
return false;
}
return true;
}
/**
* Creates new Item with the given ID into the Container.
*
* @param itemId
* ID of the Item to be created.
*
* @return Created new Item, or <code>null</code> if it fails.
*
* @throws UnsupportedOperationException
* if the addItem method is not supported.
*/
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Creates a new Item into the Container, and assign it an ID.
*
* @return ID of the newly created Item, or <code>null</code> if it fails.
* @throws UnsupportedOperationException
* if the addItem method is not supported.
*/
@Override
public Object addItem() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Removes the Item identified by ItemId from the Container.
*
* @param itemId
* ID of the Item to remove.
* @return <code>true</code> if the operation succeeded; <code>false</code>
* otherwise.
* @throws UnsupportedOperationException
* if the removeItem method is not supported.
*/
@Override
public boolean removeItem(Object itemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Adds new Property to all Items in the Container.
*
* @param propertyId
* ID of the Property
* @param type
* Data type of the new Property
* @param defaultValue
* The value all created Properties are initialized to.
* @return <code>true</code> if the operation succeeded; <code>false</code>
* otherwise.
* @throws UnsupportedOperationException
* if the addContainerProperty method is not supported.
*/
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type,
Object defaultValue) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Removes a Property specified by the given Property ID from the Container.
*
* @param propertyId
* ID of the Property to remove
* @return <code>true</code> if the operation succeeded; <code>false</code>
* otherwise.
* @throws UnsupportedOperationException
* if the removeContainerProperty method is not supported.
*/
@Override
public boolean removeContainerProperty(Object propertyId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Removes all Items from the Container.
*
* @return <code>true</code> if the operation succeeded; <code>false</code>
* otherwise.
* @throws UnsupportedOperationException
* if the removeAllItems method is not supported.
*/
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Adds new item after the given item.
*
* @param previousItemId
* Id of the previous item in ordered container.
* @param newItemId
* Id of the new item to be added.
* @return Returns new item or <code>null</code> if the operation fails.
* @throws UnsupportedOperationException
* if the addItemAfter method is not supported.
*/
@Override
public Item addItemAfter(Object previousItemId, Object newItemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Adds new item after the given item.
*
* @param previousItemId
* Id of the previous item in ordered container.
* @return Returns item id created new item or <code>null</code> if the
* operation fails.
* @throws UnsupportedOperationException
* if the addItemAfter method is not supported.
*/
@Override
public Object addItemAfter(Object previousItemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Returns id of first item in the Container.
*
* @return ID of the first Item in the list.
*/
@Override
public Object firstItemId() {
if (size < 1) {
return null;
}
return new Integer(1);
}
/**
* Returns <code>true</code> if given id is first id at first index.
*
* @param id
* ID of an Item in the Container.
*/
@Override
public boolean isFirstId(Object id) {
return size > 0 && (id instanceof Integer)
&& ((Integer) id).intValue() == 1;
}
/**
* Returns <code>true</code> if given id is last id at last index.
*
* @param id
* ID of an Item in the Container
*
*/
@Override
public boolean isLastId(Object id) {
return size > 0 && (id instanceof Integer)
&& ((Integer) id).intValue() == size;
}
/**
* Returns id of last item in the Container.
*
* @return ID of the last Item.
*/
@Override
public Object lastItemId() {
if (size < 1) {
return null;
}
return new Integer(size);
}
/**
* Returns id of next item in container at next index.
*
* @param id
* ID of an Item in the Container.
* @return ID of the next Item or null.
*/
@Override
public Object nextItemId(Object id) {
if (size < 1 || !(id instanceof Integer)) {
return null;
}
final int i = ((Integer) id).intValue();
if (i >= size) {
return null;
}
return new Integer(i + 1);
}
/**
* Returns id of previous item in container at previous index.
*
* @param id
* ID of an Item in the Container.
* @return ID of the previous Item or null.
*/
@Override
public Object prevItemId(Object id) {
if (size < 1 || !(id instanceof Integer)) {
return null;
}
final int i = ((Integer) id).intValue();
if (i <= 1) {
return null;
}
return new Integer(i - 1);
}
/**
* The <code>Row</code> class implements methods of Item.
*
* @author Vaadin Ltd.
* @since 4.0
*/
class Row implements Item {
Object id;
private Row(Object rowId) {
id = rowId;
}
/**
* Adds the item property.
*
* @param id
* ID of the new Property.
* @param property
* Property to be added and associated with ID.
* @return <code>true</code> if the operation succeeded;
* <code>false</code> otherwise.
* @throws UnsupportedOperationException
* if the addItemProperty method is not supported.
*/
@Override
public boolean addItemProperty(Object id, Property property)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Gets the property corresponding to the given property ID stored in
* the Item.
*
* @param propertyId
* identifier of the Property to get
* @return the Property with the given ID or <code>null</code>
*/
@Override
public Property<?> getItemProperty(Object propertyId) {
return getContainerProperty(id, propertyId);
}
/**
* Gets the collection of property IDs stored in the Item.
*
* @return unmodifiable collection containing IDs of the Properties
* stored the Item.
*/
@Override
public Collection<String> getItemPropertyIds() {
return propertyIds;
}
/**
* Removes given item property.
*
* @param id
* ID of the Property to be removed.
* @return <code>true</code> if the item property is removed;
* <code>false</code> otherwise.
* @throws UnsupportedOperationException
* if the removeItemProperty is not supported.
*/
@Override
public boolean removeItemProperty(Object id)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}
/**
* Closes the statement.
*
* @see #close()
*/
@Override
public void finalize() {
try {
close();
} catch (final SQLException ignored) {
}
}
/**
* Adds the given item at the position of given index.
*
* @param index
* Index to add the new item.
* @param newItemId
* Id of the new item to be added.
* @return new item or <code>null</code> if the operation fails.
* @throws UnsupportedOperationException
* if the addItemAt is not supported.
*/
@Override
public Item addItemAt(int index, Object newItemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Adds item at the position of provided index in the container.
*
* @param index
* Index to add the new item.
* @return item id created new item or <code>null</code> if the operation
* fails.
*
* @throws UnsupportedOperationException
* if the addItemAt is not supported.
*/
@Override
public Object addItemAt(int index) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Gets the Index id in the container.
*
* @param index
* Index Id.
* @return ID in the given index.
*/
@Override
public Object getIdByIndex(int index) {
if (size < 1 || index < 0 || index >= size) {
return null;
}
return new Integer(index + 1);
}
/**
* Gets the index of the Item corresponding to id in the container.
*
* @param id
* ID of an Item in the Container
* @return index of the Item, or -1 if the Container does not include the
* Item
*/
@Override
public int indexOfId(Object id) {
if (size < 1 || !(id instanceof Integer)) {
return -1;
}
final int i = ((Integer) id).intValue();
if (i >= size || i < 1) {
return -1;
}
return i - 1;
}
}