blob: 70216e08289c76900c1b36c699e20130869c45b4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 Sybase, Inc. and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Sybase, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.pagedesigner.dom.html;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jst.pagedesigner.IHTMLConstants;
import org.eclipse.jst.pagedesigner.utils.DOMUtil;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* @author mengbo
* @version 1.5
*/
public class TableUtil {
private Element _fakeCell = null;
private Element _table = null;
private List[] _trCellLists = null;
/**
* judge whether there is rowspan>1 cell in the tr
*
* @param tr
* TR element in a table
* @return true if there is rowspan>1 cell in the tr
*/
public static boolean hasRowSpanElement(Element tr) {
List list = DOMUtil.getElementChildren(tr);
Iterator itr = list.iterator();
while (itr.hasNext()) {
Element ele = (Element) itr.next();
int value = DOMUtil.getIntAttributeIgnoreCase(ele,
IHTMLConstants.ATTR_ROWSPAN, 1);
if (value > 1) {
return true;
}
}
return false;
}
/**
* judge whether a tr is affected by row span cell in the previous trs.
*
* @param trList
* list holds all tr elements in a table
* @param tr
* @param index
* tr index in the DOM tree
* @return true if tr is affected by row span cell in the previous trs
*/
public static boolean isAffectedByRowSpan(List trList, Element tr, int index) {
Node parent = tr.getParentNode();
int dex = index;
while (--dex >= 0) {
Element preTr = (Element) trList.get(dex);
if (preTr.getParentNode() != parent) {
break;
}
int maxRowSpan = countMaxRowSpan(preTr);
if (maxRowSpan > (index - dex)) {
return true;
}
}
return false;
}
/**
* count all tr in the table
*
* @param element
* table
* @param list
* list to hold tr elements
*/
public static void getTrElements(Element element, List list) {
NodeList nodeList = element.getChildNodes();
for (int i = 0, size = nodeList.getLength(); i < size; i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element ele = (Element) node;
if (ele.getNodeName().equalsIgnoreCase(IHTMLConstants.TAG_TR)) {
list.add(ele);
} else if (ele.getNodeName().equalsIgnoreCase(
IHTMLConstants.TAG_THEAD)
|| ele.getNodeName().equalsIgnoreCase(
IHTMLConstants.TAG_TBODY)
|| ele.getNodeName().equalsIgnoreCase(
IHTMLConstants.TAG_TFOOT)) {
getTrElements(ele, list);
}
}
}
}
/**
* count row index in the code DOM tree according to the display index
*
* @param table
* @param displayIndex
* @return the row index
*/
public static int countRowIndexInDOMTree(Element table, int displayIndex) {
int footRows = countSectionRows(table, IHTMLConstants.TAG_TFOOT);
if (footRows == 0) {
return displayIndex;
}
int headRows = countSectionRows(table, IHTMLConstants.TAG_THEAD);
List list = new ArrayList();
getTrElements(table, list);
int bodyRows = list.size() - headRows - footRows;
// if display index is in TFOOT area
if (displayIndex >= (list.size() - footRows)) {
int index = displayIndex - bodyRows;
return index;
}
// if display index is in TBODY area
else if (displayIndex >= headRows) {
int index = displayIndex + footRows;
return index;
}
// if display index is in THEAD area
else {
return displayIndex;
}
}
/**
* get row count in the specified section
*
* @param table
* @param sectionName
* child element name of table, like THEAD or TFOOT
* @return the row count in the section
*/
public static int countSectionRows(Element table, String sectionName) {
NodeList nodeList = table.getChildNodes();
for (int i = 0, size = nodeList.getLength(); i < size; i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element ele = (Element) node;
if (node.getNodeName().equalsIgnoreCase(sectionName)) {
List list = DOMUtil.getChildElementsByTagIgnoreCase(ele,
IHTMLConstants.TAG_TR);
if (list != null) {
return list.size();
}
}
}
}
return 0;
}
/**
* constructor
*
* @param table
*/
public TableUtil(Element table) {
this._table = table;
this._trCellLists = fillTrCells();
}
/**
* get tr cells list
*
* @return the list of tr cells
*/
public List[] getTrCellLists() {
return this._trCellLists;
}
/**
* calculate row and column index for tr or td/th
*
* @param node
* tr or td/th
* @return the position
*/
public TableChildElementPosition getPosition(Node node) {
TableChildElementPosition position = new TableChildElementPosition();
String tagName = node.getLocalName();
if (IHTMLConstants.TAG_TR.equalsIgnoreCase(tagName)) {
List list = new ArrayList();
getTrElements(this._table, list);
for (int i = 0, size = list.size(); i < size; i++) {
Element tr = (Element) list.get(i);
if (tr == node) {
position.setRowIndex(i);
break;
}
}
} else if (IHTMLConstants.TAG_TD.equalsIgnoreCase(tagName)
|| IHTMLConstants.TAG_TH.equalsIgnoreCase(tagName)) {
Element tr = (Element) node.getParentNode();
TableChildElementPosition pos = getPosition(tr);
position.setRowIndex(pos.getRowIndex());
List[] lists = getTrCellLists();
List list = lists[pos.getRowIndex()];
for (int i = 0, size = list.size(); i < size; i++) {
Element td = (Element) list.get(i);
if (td == node) {
position.setColumnIndex(i);
break;
}
}
} else {
boolean hasTDParent = false;
Node childBackup = node;
while (!IHTMLConstants.TAG_TABLE.equalsIgnoreCase(childBackup
.getParentNode().getLocalName())) {
childBackup = childBackup.getParentNode();
String localName = childBackup.getLocalName();
if (IHTMLConstants.TAG_TD.equalsIgnoreCase(localName)
|| IHTMLConstants.TAG_TH.equalsIgnoreCase(localName)) {
hasTDParent = true;
break;
}
}
if (hasTDParent) {
position = getPosition(childBackup);
}
}
return position;
}
/**
* get column count
*
* @return the column count
*/
public int getColumnCount() {
List[] lists = this._trCellLists;
if (lists != null) {
int max = 0;
for (int i = 0, size = lists.length; i < size; i++) {
List list = lists[i];
if (list.size() > max) {
max = list.size();
}
}
return max;
}
return 0;
}
/**
* judge whether there is columnspan>1 cell in the column
*
* @param columnIndex
* column index in a table
* @return true if there is columnspan>1 cell in the column
*/
public boolean hasColumnSpanElement(int columnIndex) {
List cells = getColumnCells(columnIndex);
if (cells != null) {
Iterator itr = cells.iterator();
while (itr.hasNext()) {
Element cell = (Element) itr.next();
int value = DOMUtil.getIntAttributeIgnoreCase(cell,
IHTMLConstants.ATTR_COLSPAN, 1);
if (value > 1) {
return true;
}
}
}
return false;
}
/**
* judge whether the column has cell affected by column span cell in
* privious columns
*
* @param columnIndex
* @return true if the column has cell affected by column span cell in
* privious columns
*/
public boolean isAffectedByColSpan(int columnIndex) {
int index = columnIndex;
while (--index >= 0) {
List cells = getColumnCells(index);
int max = countMaxColSpan(cells);
if (max > (columnIndex - index)) {
return true;
}
}
return false;
}
/**
* get cells in the specified column of the table
*
* @param columnIndex
* @return the column cells
*/
public List getColumnCells(int columnIndex) {
List list = new ArrayList();
List[] lists = this._trCellLists;
for (int i = 0; i < lists.length; i++) {
List tempList = lists[i];
if (tempList.size() <= columnIndex) {
continue;
}
list.add(tempList.get(columnIndex));
}
return list;
}
/**
* count max row span in the tr
*
* @param tr
* @return
*/
private static int countMaxRowSpan(Element tr) {
List list = DOMUtil.getElementChildren(tr);
int max = countMaxValue(list, IHTMLConstants.ATTR_ROWSPAN);
return max;
}
/**
* count max attr value
*
* @param list
* @param attr
* @return
*/
private static int countMaxValue(List list, String attr) {
int max = 1;
Iterator itr = list.iterator();
while (itr.hasNext()) {
Element ele = (Element) itr.next();
int value = DOMUtil.getIntAttributeIgnoreCase(ele, attr, 1);
if (value > max) {
max = value;
}
}
return max;
}
/**
* count max col span in a column
*
* @param list
* @return
*/
private int countMaxColSpan(List list) {
int max = countMaxValue(list, IHTMLConstants.ATTR_COLSPAN);
return max;
}
/**
* get fake element to fill tr cell
*
* @return
*/
private Element getFakeElement() {
if (_fakeCell != null) {
return _fakeCell;
}
_fakeCell = this._table.getOwnerDocument().createElement("fake");
return _fakeCell;
}
/**
* initial every tr cells according to th and td under each tr element
*
* @param trList
* @return
*/
private List[] initialTrCells(List trList) {
int size = trList.size();
List[] lists = new ArrayList[size];
if (trList != null) {
for (int i = 0, n = trList.size(); i < n; i++) {
lists[i] = new ArrayList();
Element tr = (Element) trList.get(i);
List domCells = DOMUtil.getElementChildren(tr);
Iterator itr = domCells.iterator();
while (itr.hasNext()) {
Element cell = (Element) itr.next();
lists[i].add(cell);
int colSpan = DOMUtil.getIntAttributeIgnoreCase(cell,
IHTMLConstants.ATTR_COLSPAN, 1);
while (--colSpan > 0) {
Element fakeElement = getFakeElement();
lists[i].add(fakeElement);
}
}
}
}
return lists;
}
/**
* after initial tr cells,fill tr with fake cells if necessary.
*
* @return
*/
private List[] fillTrCells() {
List list = new ArrayList();
getTrElements(this._table, list);
List[] lists = initialTrCells(list);
int size = lists.length;
int headRows = countSectionRows(this._table, IHTMLConstants.TAG_THEAD);
if (headRows > 0) {
List[] headList = new ArrayList[headRows];
for (int i = 0; i < headRows; i++) {
headList[i] = lists[i];
}
fillSectionTrCells(headList);
}
int footRows = countSectionRows(this._table, IHTMLConstants.TAG_TFOOT);
if (footRows > 0) {
List[] footList = new ArrayList[footRows];
for (int i = 0; i < footRows; i++) {
footList[i] = lists[headRows + i];
}
fillSectionTrCells(footList);
}
int bodyRows = size - headRows - footRows;
if (bodyRows > 0) {
int bodyCount = 1;
int k = 0;
List bodys = new ArrayList();
Element tr = (Element) list.get(headRows + footRows);
Node node = tr.getParentNode();
for (int i = 1; i < bodyRows; i++) {
Element tempTr = (Element) list.get(headRows + footRows + i);
if (tempTr.getParentNode() != node) {
node = tempTr.getParentNode();
bodys.add(new Integer(i - k));
k = i;
bodyCount++;
}
}
bodys.add(new Integer(bodyRows - k));
for (int j = 0; j < bodyCount; j++) {
int num = ((Integer) bodys.get(j)).intValue();
List[] bodyList = new ArrayList[num];
int m = headRows + footRows;
for (int i = 0; i < num; i++) {
bodyList[i] = lists[m + i];
}
fillSectionTrCells(bodyList);
m = m + num;
}
}
return lists;
}
/**
* fill tr cells under each table section,like THEAD,TFOOT,TBODY.
*
* @param lists
*/
private void fillSectionTrCells(List[] lists) {
Element cell = null;
if (lists != null) {
for (int i = 1, size = lists.length; i < size; i++) {
List insertPoints = new ArrayList();
for (int j = 0; j < i; j++) {
List list = lists[j];
for (int column = 0; column < list.size(); column++) {
cell = (Element) list.get(column);
if (cell.getTagName().equalsIgnoreCase("fake")) {
continue;
}
int rowSpan = DOMUtil.getIntAttributeIgnoreCase(cell,
IHTMLConstants.ATTR_ROWSPAN, 1);
if (rowSpan > (i - j)) {
int colSpan = DOMUtil.getIntAttributeIgnoreCase(
cell, IHTMLConstants.ATTR_COLSPAN, 1);
insertPoints.add(new ColStructure(column, colSpan));
}
}
}
// there are fake column cell need to be inserted into this tr
if (insertPoints.size() > 0) {
Collections.sort(insertPoints);
List trCells = lists[i];
Iterator itr = insertPoints.iterator();
while (itr.hasNext()) {
ColStructure cls = (ColStructure) itr.next();
int loop = cls.getColSpan();
int column = cls.getColumn();
while (loop-- != 0) {
trCells.add(column++, getFakeElement());
}
}
}
}
}
}
}