nextapp.echo2.webcontainer.syncpeer.TriCellTable Maven / Gradle / Ivy
Show all versions of ibis-echo2 Show documentation
/*
* This file is part of the Echo Web Application Framework (hereinafter "Echo").
* Copyright (C) 2002-2009 NextApp, Inc.
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*/
package nextapp.echo2.webcontainer.syncpeer;
import nextapp.echo2.app.Extent;
import nextapp.echo2.webcontainer.RenderContext;
import nextapp.echo2.webcontainer.propertyrender.ExtentRender;
import nextapp.echo2.webrender.Service;
import nextapp.echo2.webrender.WebRenderServlet;
import nextapp.echo2.webrender.service.StaticBinaryService;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Renders an HTML table that has two or three "container" cells and
* independently configurable margins between them. These tables are useful for
* rendering buttons that have two or three elements (images, text labels, and
* state indicators). This class supports all possible permutations for
* placement of each of the two or three contained components.
*
* This class should not be extended or used by classes outside of the
* Echo framework.
*/
class TriCellTable {
private static final Service TRANSPARENT_SPACER_IMAGE_SERVICE = StaticBinaryService.forResource(
"Echo.TriCellTable.TransparentImage", "image/gif", "/nextapp/echo2/webcontainer/resource/image/Transparent.gif");
static {
WebRenderServlet.getServiceRegistry().add(TRANSPARENT_SPACER_IMAGE_SERVICE);
}
static final int INVERTED = 1;
static final int VERTICAL = 2;
public static final int LEADING_TRAILING = 0;
public static final int TRAILING_LEADING = INVERTED;
public static final int TOP_BOTTOM = VERTICAL;
public static final int BOTTOM_TOP = INVERTED | VERTICAL;
private Element[] tdElements;
private Element[] marginTdElements = null;
private Element tableElement;
private Element tbodyElement;
private Document document;
private RenderContext rc;
/**
* This constructor is called by the non-private constructors to set up
* common properties.
*
* @param rc the relevant RenderContext
* @param id The id the id upon which the inner elements will be based.
* the id of the returned table element is not set and must be
* set appropriately by the caller.
*/
private TriCellTable(RenderContext rc, Document document, String id) {
super();
this.rc = rc;
this.document = document;
tableElement = document.createElement("table");
tbodyElement = document.createElement("tbody");
tbodyElement.setAttribute("id", id + "_tbody");
tableElement.appendChild(tbodyElement);
}
/**
* Creates a two-celled TriCellTable
.
*
* @param rc the relevant RenderContext
* @param document the outgoing XML document
* @param id the id of the root element
* @param orientation0_1 The orientation of Element 0 with respect to
* Element 1, one of the following values:
*
* - LEFT_RIGHT (element 0 is to the left of element 1)
* - RIGHT_LEFT (element 1 is to the left of element 0)
* - TOP_BOTTOM (element 0 is above element 1)
* - BOTTOM_TOP (element 1 is above element 0)
*
* @param margin0_1 The margin size between element 0 and element 1.
*/
TriCellTable(RenderContext rc, Document document, String id, int orientation0_1, Extent margin0_1) {
this(rc, document, id);
marginTdElements = new Element[1];
tdElements = new Element[2];
tdElements[0] = document.createElement("td");
tdElements[0].setAttribute("id", id + "_td_0");
tdElements[1] = document.createElement("td");
tdElements[1].setAttribute("id", id + "_td_1");
if (margin0_1 != null && margin0_1.getValue() > 0) {
marginTdElements[0] = document.createElement("td");
marginTdElements[0].setAttribute("id", id + "_tdmargin_0_1");
int size = ExtentRender.toPixels(margin0_1, 1);
if ((orientation0_1 & VERTICAL) == 0) {
marginTdElements[0].setAttribute("style", "width:" + size + "px;");
addSpacer(marginTdElements[0], size, false);
} else {
marginTdElements[0].setAttribute("style", "height:" + size + "px;");
addSpacer(marginTdElements[0], size, true);
}
}
if ((orientation0_1 & VERTICAL) == 0) {
// horizontally oriented
Element trElement = document.createElement("tr");
trElement.setAttribute("id", id + "_tr_0_1");
if ((orientation0_1 & INVERTED) == 0) {
// normal (left to right)
addColumn(trElement, tdElements[0]);
addColumn(trElement, marginTdElements[0]);
addColumn(trElement, tdElements[1]);
} else {
// inverted (right to left)
addColumn(trElement, tdElements[1]);
addColumn(trElement, marginTdElements[0]);
addColumn(trElement, tdElements[0]);
}
tbodyElement.appendChild(trElement);
} else {
// vertically oriented
if ((orientation0_1 & INVERTED) == 0) {
// normal (top to bottom)
addRow(tdElements[0], id + "_tr_0");
addRow(marginTdElements[0], id + "_trmargin_0_1");
addRow(tdElements[1], id + "_tr_1");
} else {
// inverted (bottom to top)
addRow(tdElements[1], id + "_tr_1");
addRow(marginTdElements[0], id + "_trmargin_0_1");
addRow(tdElements[0], id + "_tr_0");
}
}
}
/**
* Creates a three-celled TriCellTable
.
*
* @param rc the relevant RenderContext
* @param document the outgoing XML document
* @param id the id of the root element
* @param orientation0_1 The orientation of Element 0 with respect to
* Element 1, one of the following values:
*
* - LEFT_RIGHT (element 0 is to the left of element 1)
* - RIGHT_LEFT (element 1 is to the left of element 0)
* - TOP_BOTTOM (element 0 is above element 1)
* - BOTTOM_TOP (element 1 is above element 0)
*
* @param margin0_1 The margin size between element 0 and element 1.
* @param orientation01_2 The orientation of Elements 0 and 1 with
* respect to Element 2, one of the following values:
*
* - LEFT_RIGHT (elements 0 and 1 are to the left of
* element 1)
* - RIGHT_LEFT (element 2 is to the left of elements 0 and 1)
* - TOP_BOTTOM (elements 0 and 1 are above element 2)
* - BOTTOM_TOP (element 2 is above elements 0 and 1)
*
* @param margin01_2 The margin size between the combination
* of elements 0 and 1 and element 2.
*/
TriCellTable(RenderContext rc, Document document, String id, int orientation0_1, Extent margin0_1, int orientation01_2,
Extent margin01_2) {
this(rc, document, id);
Element trElement;
marginTdElements = new Element[2];
tdElements = new Element[3];
tdElements[0] = document.createElement("td");
tdElements[0].setAttribute("id", id + "_td_0");
tdElements[1] = document.createElement("td");
tdElements[1].setAttribute("id", id + "_td_1");
tdElements[2] = document.createElement("td");
tdElements[2].setAttribute("id", id + "_td_2");
// Create margin cells
if (margin0_1 != null || margin01_2 != null) {
if (margin0_1 != null && margin0_1.getValue() > 0) {
marginTdElements[0] = document.createElement("td");
marginTdElements[0].setAttribute("id", id + "_tdmargin_0_1");
int size = ExtentRender.toPixels(margin0_1, 1);
if ((orientation0_1 & VERTICAL) == 0) {
marginTdElements[0].setAttribute("style", "width:" + size + "px;");
addSpacer(marginTdElements[0], size, false);
} else {
marginTdElements[0].setAttribute("style", "height:" + size + "px;");
addSpacer(marginTdElements[0], size, true);
}
}
if (margin01_2 != null && margin01_2.getValue() > 0) {
marginTdElements[1] = document.createElement("td");
marginTdElements[1].setAttribute("id", id + "_tdmargin_01_2");
int size = ExtentRender.toPixels(margin01_2, 1);
if ((orientation01_2 & VERTICAL) == 0) {
marginTdElements[1].setAttribute("style", "width:" + size + "px;");
addSpacer(marginTdElements[1], size, false);
} else {
marginTdElements[1].setAttribute("style", "height:" + size + "px;");
addSpacer(marginTdElements[1], size, true);
}
}
}
if ((orientation0_1 & VERTICAL) == 0) {
// horizontally oriented 0/1
if ((orientation01_2 & VERTICAL) == 0) {
// horizontally oriented 01/2
trElement = document.createElement("tr");
trElement.setAttribute("id", id + "_tr_0");
if ((orientation01_2 & INVERTED) != 0) {
// 2 before 01: render #2 and margin at beginning of TR.
addColumn(trElement, tdElements[2]);
addColumn(trElement, marginTdElements[1]);
}
// Render 01
if ((orientation0_1 & INVERTED) == 0) {
// normal (left to right)
addColumn(trElement, tdElements[0]);
addColumn(trElement, marginTdElements[0]);
addColumn(trElement, tdElements[1]);
} else {
// inverted (right to left)
addColumn(trElement, tdElements[1]);
addColumn(trElement, marginTdElements[0]);
addColumn(trElement, tdElements[0]);
}
if ((orientation01_2 & INVERTED) == 0) {
addColumn(trElement, marginTdElements[1]);
addColumn(trElement, tdElements[2]);
}
tbodyElement.appendChild(trElement);
} else {
// vertically oriented 01/2
// determine and apply column span based on presence of margin between 0 and 1
int columns = (margin0_1 != null && margin0_1.getValue() > 0) ? 3 : 2;
tdElements[2].setAttribute("colspan", Integer.toString(columns));
if (marginTdElements[1] != null) {
marginTdElements[1].setAttribute("colspan", Integer.toString(columns));
}
if ((orientation01_2 & INVERTED) != 0) {
// 2 before 01: render #2 and margin at beginning of TR.
addRow(tdElements[2], id + "_tr_2");
addRow(marginTdElements[1], id + "_trmargin_01_2");
}
// Render 01
trElement = document.createElement("tr");
trElement.setAttribute("id", "tr_" + id);
if ((orientation0_1 & INVERTED) == 0) {
// normal (left to right)
addColumn(trElement, tdElements[0]);
addColumn(trElement, marginTdElements[0]);
addColumn(trElement, tdElements[1]);
} else {
// inverted (right to left)
addColumn(trElement, tdElements[1]);
addColumn(trElement, marginTdElements[0]);
addColumn(trElement, tdElements[0]);
}
tbodyElement.appendChild(trElement);
if ((orientation01_2 & INVERTED) == 0) {
// 01 before 2: render margin and #2 at end of TR.
addRow(marginTdElements[1], id + "_trmargin_01_2");
addRow(tdElements[2], id + "_tr_2");
}
}
} else {
// vertically oriented 0/1
if ((orientation01_2 & VERTICAL) == 0) {
// horizontally oriented 01/2
// determine and apply row span based on presence of margin between 0 and 1
int rows = (margin0_1 != null && margin0_1.getValue() > 0) ? 3 : 2;
tdElements[2].setAttribute("rowspan", Integer.toString(rows));
if (marginTdElements[1] != null) {
marginTdElements[1].setAttribute("rowspan", Integer.toString(rows));
}
trElement = document.createElement("tr");
trElement.setAttribute("id", id + "_tr_0");
if ((orientation01_2 & INVERTED) != 0) {
addColumn(trElement, tdElements[2]);
addColumn(trElement, marginTdElements[1]);
if ((orientation0_1 & INVERTED) == 0) {
addColumn(trElement, tdElements[0]);
} else {
addColumn(trElement, tdElements[1]);
}
} else {
if ((orientation0_1 & INVERTED) == 0) {
addColumn(trElement, tdElements[0]);
} else {
addColumn(trElement, tdElements[1]);
}
addColumn(trElement, marginTdElements[1]);
addColumn(trElement, tdElements[2]);
}
tbodyElement.appendChild(trElement);
addRow(marginTdElements[0], id + "_trmargin_0_1");
if ((orientation0_1 & INVERTED) == 0) {
addRow(tdElements[1], id + "_tr_1");
} else {
addRow(tdElements[0], id + "_tr_0");
}
} else {
// vertically oriented 01/2
if ((orientation01_2 & INVERTED) != 0) {
// 2 before 01: render #2 and margin at beginning of TABLE.
addRow(tdElements[2], id + "_tr_2");
addRow(marginTdElements[1], id + "_trmargin_01_2");
}
// Render 01
if ((orientation0_1 & INVERTED) == 0) {
// normal (top to bottom)
addRow(tdElements[0], id + "_tr_0");
addRow(marginTdElements[0], id + "_trmargin_0_1");
addRow(tdElements[1], id + "_tr_1");
} else {
// inverted (bottom to top)
addRow(tdElements[1], id + "_tr_1");
addRow(marginTdElements[0], id + "_trmargin_1_0");
addRow(tdElements[0], id + "_tr_0");
}
if ((orientation01_2 & INVERTED) == 0) {
// 01 before 2: render margin and #2 at end of TABLE.
addRow(marginTdElements[1], id + "_trmargin_01_2");
addRow(tdElements[2], id + "_tr_2");
}
}
}
}
/**
* Adds an cell element to a table row. The element will not be added
* if null is provided for the value of td
.
*
* @param tr The table row to which the cell element is to be added.
* @param td The cell element to be added (if not null).
*/
private void addColumn(Element tr, Element td) {
if (td != null) {
tr.appendChild(td);
}
}
/**
* Appends CSS text to the 'style' attribute of each table cell 'td'
* element.
*
* @param cssText the CSS text to add
*/
void addCellCssText(String cssText) {
for (int i = 0; i < tdElements.length; ++i) {
if (tdElements[i].hasAttribute("style")) {
tdElements[i].setAttribute("style", tdElements[i].getAttribute("style") + cssText);
} else {
tdElements[i].setAttribute("style", cssText);
}
}
if (marginTdElements != null) {
for (int i = 0; i < marginTdElements.length; ++i) {
if (marginTdElements[i] != null) {
if (marginTdElements[i].hasAttribute("style")) {
marginTdElements[i].setAttribute("style", marginTdElements[i].getAttribute("style") + cssText);
} else {
marginTdElements[i].setAttribute("style", cssText);
}
}
}
}
}
/**
* Adds a row containing a single column element to a table.
* The row will not be added if td
is null.
*
* @param tdElement The row element to be added.
* @param trElementId the id to assign to the row element.
*/
private void addRow(Element tdElement, String trElementId) {
if (tdElement != null) {
Element trElement = document.createElement("tr");
trElement.setAttribute("id", trElementId);
trElement.appendChild(tdElement);
tbodyElement.appendChild(trElement);
}
}
/**
* Adds a spacer element containing a transparent GIF image.
* These are unfortunately necessary to prevent spacer cells
* from collapsing in circumstances where horizontal real-estate
* is not available.
*
* @param parentElement the Element
to which the spacer image
* is to be appended
* @param size the size of the spacer cell, in pixels
* @param vertical a flag indicating the direction; specify
* true
for a vertical spacer or false
for
* a horizontal spacer.
*/
private void addSpacer(Element parentElement, int size, boolean vertical) {
Element imgElement = document.createElement("img");
imgElement.setAttribute("src", rc.getContainerInstance().getServiceUri(TRANSPARENT_SPACER_IMAGE_SERVICE));
imgElement.setAttribute("alt", "");
imgElement.setAttribute("width", vertical ? "1" : Integer.toString(size));
imgElement.setAttribute("height", vertical ? Integer.toString(size) : "1");
parentElement.appendChild(imgElement);
}
/**
* Returns the created table element.
*
* @return the table element
*/
Element getTableElement() {
return tableElement;
}
/**
* Returns the specified container element.
*
* @param index The index of the table element to return. For two-celled tables,
* legitimate values are 0 and 1. For three-celled tables,
* legitimate values are 0, 1, and 2.
* @return The specified container element.
*/
Element getTdElement(int index) {
return tdElements[index];
}
/**
* Returns the specified margin element.
*
* @param index The index of the table element to return. Index 0 is the margin
* element between container cells 0 and 1. Index 1 is the margin
* element between container cells 0/1 and 2.
* @return The specified margin element. Returns null if the margin is zero
* pixels.
*/
Element getMarginTdElement(int index) {
return marginTdElements[index];
}
}