/*******************************************************************************
* Copyright 2012 University of Southern California
*
* 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.
*
* This code was developed by the Information Integration Group as part
* of the Karma project at the Information Sciences Institute of the
* University of Southern California. For more information, publications,
* and related projects, please see: http://www.isi.edu/integration
******************************************************************************/
/**
*
*/
package edu.isi.karma.view.tabledata;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.contentRow;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.fullValue;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.isTruncated;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.rowCells;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.rowType;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.rows;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.separatorRow;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.status;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.value;
import static edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys.worksheetId;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.json.JSONException;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.isi.karma.controller.update.AbstractUpdate;
import edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate;
import edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.CellType;
import edu.isi.karma.controller.update.WorksheetHierarchicalDataUpdate.JsonKeys;
import edu.isi.karma.rep.CellValue;
import edu.isi.karma.rep.Table;
import edu.isi.karma.rep.TablePager;
import edu.isi.karma.util.JSONUtil;
import edu.isi.karma.view.Stroke;
import edu.isi.karma.view.Stroke.StrokeStyle;
import edu.isi.karma.view.VTableCssTags;
import edu.isi.karma.view.VWorksheet;
import edu.isi.karma.view.VWorkspace;
import edu.isi.karma.view.ViewPreferences.ViewPreference;
import edu.isi.karma.view.tabledata.VDCell.MinMaxDepth;
import edu.isi.karma.view.tabledata.VDCell.Position;
import edu.isi.karma.view.tabledata.VDCellStrokes.StrokeIterator;
import edu.isi.karma.view.tabledata.VDIndexTable.LeftRight;
import edu.isi.karma.view.tabledata.VDTriangle.TriangleLocation;
/**
* @author szekely
*
*/
public class VDTableCells {
Logger logger = LoggerFactory.getLogger(VDTableCells.class);
private final VDCell[][] cells;
private final int numRows;
private final int numCols;
private final VDIndexTable vdIndexTable;
private final VDVerticalSeparators vdVerticalSeparators;
private final String rootTableId;
private final Set<Stroke> defaultStrokes = new HashSet<Stroke>();
VDTableCells(VDTableData vdTableData, VWorksheet vWorksheet,
VWorkspace vWorkspace) {
this.numCols = vdTableData.getVdIndexTable().getNumColumns();
this.numRows = vdTableData.getNumLevels();
cells = new VDCell[numRows][numCols];
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
cells[i][j] = new VDCell();
}
}
this.vdIndexTable = vdTableData.getVdIndexTable();
this.rootTableId = vWorksheet.getWorksheet().getDataTable().getId();
this.vdVerticalSeparators = vdTableData.getVdVerticalSeparators();
populate(vdTableData, vWorksheet, vWorkspace);
setDefaultStrokes(vdTableData, vWorkspace);
}
int getNumRows() {
return numRows;
}
int getNumCols() {
return numCols;
}
VDCell get(int rowIndex, int columnIndex) {
return cells[rowIndex][columnIndex];
}
public int getNumHorizontalSeparators(int rowIndex, Position position) {
int num = 0;
for (int j = 0; j < numCols; j++) {
VDCell c = cells[rowIndex][j];
num = Math.max(num, c.getVdCellStrokes().getNumStrokes(position));
}
return num;
}
private void populate(VDTableData vdTableData, VWorksheet vWorksheet,
VWorkspace vWorkspace) {
for (VDRow vdRow : vdTableData.getRows()) {
populateFromVDRow(vdRow, vWorksheet, vWorkspace);
}
initializeVDCellStrokes();
}
private void initializeVDCellStrokes() {
for (int i = 0; i < numRows; i++) {
// MinMaxDepth topCombinedMinMaxDepth = getMinMaxDepth(i,
// Position.top);
// MinMaxDepth bottomCombinedMinMaxDepth = getMinMaxDepth(i,
// Position.bottom);
// int numTop = Math.max(0, topCombinedMinMaxDepth.getDelta()) + 1;
// int minTop = topCombinedMinMaxDepth.getMinDepth();
// int numBottom = Math.max(0, bottomCombinedMinMaxDepth.getDelta())
// + 1;
// int minBottom = bottomCombinedMinMaxDepth.getMinDepth();
int numTop = 0;
int numBottom = 0;
for (int j = 0; j < numCols; j++) {
numTop = Math.max(numTop, cells[i][j].getTopStrokes().size());
numBottom = Math.max(numBottom, cells[i][j].getBottomStrokes()
.size());
}
for (int j = 0; j < numCols; j++) {
List<Stroke> topStrokes = cells[i][j].getTopStrokes();
List<Stroke> bottomStrokes = cells[i][j].getBottomStrokes();
int minTop = topStrokes.isEmpty() ? 0 : topStrokes.get(0)
.getDepth();
int minBottom = bottomStrokes.isEmpty() ? 0 : bottomStrokes
.get(0).getDepth();
VDVerticalSeparator vdVS = vdVerticalSeparators
.get(vdIndexTable.getHNodeId(j));
VDCellStrokes vdcs = VDCellStrokes.create(
cells[i][j].getDepth(), vdVS, numTop, minTop,
numBottom, minBottom);
vdcs.populateFromVDCell(vdVS, cells[i][j]);
cells[i][j].setVdCellStrokes(vdcs);
}
}
}
private void populateFromVDRow(VDRow vdRow, VWorksheet vWorksheet,
VWorkspace vWorkspace) {
String fill = vdRow.getFillHTableId();
LeftRight lr = vdIndexTable.get(vdRow.getContainerHNodeId(vWorkspace));
// Set the depth and color of each cell.
for (int i = vdRow.getStartLevel(); i <= vdRow.getLastLevel(); i++) {
for (int j = lr.getLeft(); j <= lr.getRight(); j++) {
VDCell c = cells[i][j];
c.setFillHTableId(fill);
c.setDepth(vdRow.getDepth());
}
}
{// top strokes
Stroke topStroke = new Stroke(vdRow.isFirst() ? StrokeStyle.outer
: StrokeStyle.inner, fill, vdRow.getDepth());
for (int j = lr.getLeft(); j <= lr.getRight(); j++) {
VDCell c = cells[vdRow.getStartLevel()][j];
c.addTopStroke(topStroke);
}
}
{// bottom strokes
if (vdRow.isLast()) {
Stroke bottomStroke = new Stroke(StrokeStyle.outer, fill,
vdRow.getDepth());
for (int j = lr.getLeft(); j <= lr.getRight(); j++) {
VDCell c = cells[vdRow.getLastLevel()][j];
c.addBottomStroke(bottomStroke);
}
}
// All other rows but the last one.
else { // a none border at the bottom to create a space when there
// is a nested table.
Stroke noneStroke = new Stroke(StrokeStyle.none, fill,
vdRow.getDepth());
for (int j = lr.getLeft(); j <= lr.getRight(); j++) {
cells[vdRow.getLastLevel()][j].addBottomStroke(noneStroke);
}
}
}
{// left/right outer strokes
// Inner strokes are computed in populateFromVDTreeNode.
Stroke outerStroke = new Stroke(StrokeStyle.outer, fill,
vdRow.getDepth());
for (int i = vdRow.getStartLevel(); i <= vdRow.getLastLevel(); i++) {
cells[i][lr.getLeft()].addLeftStroke(outerStroke);
cells[i][lr.getRight()].addRightStroke(outerStroke);
}
}
{// inner vertical separator strokes.
// We do them here to make sure they span the height of the row even
// if each node is not as tall as the whole row.
Stroke innerStroke = new Stroke(StrokeStyle.inner, fill,
vdRow.getDepth());
for (VDTreeNode n : vdRow.getNodes()) {
LeftRight nodeLr = vdIndexTable.get(n.getHNode(vWorkspace)
.getId());
if (!n.isFirst() && n.getNumLevels() > 0) {
for (int i = vdRow.getStartLevel(); i <= vdRow
.getLastLevel(); i++) {
VDCell c = cells[i][nodeLr.getLeft()];
c.addLeftStroke(innerStroke);
}
}
}
}
{// triangles
cells[vdRow.getStartLevel()][lr.getLeft()]
.addTriangle(new VDTriangle(fill, vdRow.getRow().getId(),
vdRow.getDepth(), TriangleLocation.topLeft));
cells[vdRow.getStartLevel()][lr.getRight()]
.addTriangle(new VDTriangle(fill, vdRow.getRow().getId(),
vdRow.getDepth(), TriangleLocation.topRight));
cells[vdRow.getLastLevel()][lr.getLeft()]
.addTriangle(new VDTriangle(fill, vdRow.getRow().getId(),
vdRow.getDepth(), TriangleLocation.bottomLeft));
cells[vdRow.getLastLevel()][lr.getRight()]
.addTriangle(new VDTriangle(fill, vdRow.getRow().getId(),
vdRow.getDepth(), TriangleLocation.bottomRight));
}
{// table pagers
if (vdRow.isLast()) {
VDTreeNode vdNode = vdRow.getContainerVDNode();
String tableId = (vdNode == null) ? rootTableId : vdNode
.getNode().getNestedTable().getId();
TablePager pager = vWorksheet.getTablePager(tableId);
if (!pager.isAllRowsShown()) {
cells[vdRow.getLastLevel()][lr.getLeft()].addPager(pager);
}
}
}
for (VDTreeNode n : vdRow.getNodes()) {
populateFromVDTreeNode(n, vWorksheet, vWorkspace);
}
}
private void populateFromVDTreeNode(VDTreeNode n, VWorksheet vWorksheet,
VWorkspace vWorkspace) {
LeftRight lr = vdIndexTable.get(n.getHNode(vWorkspace).getId());
{// A none stroke on the right to create a space when there are nested
// tables.
// TODO: I suspect this needs to be done in the ROW part, the same
// way that the inner strokes are being done.
Stroke noneStroke = new Stroke(StrokeStyle.none,
n.getContainerHTableId(vWorkspace), n.getDepth());
if (!n.isLast() && n.getNumLevels() > 0) {
for (int i = n.getStartLevel(); i <= n.getLastLevel(); i++) {
VDCell c = cells[i][lr.getRight()];
c.addRightStroke(noneStroke);
}
}
}
Table nestedTable = n.getNode().getNestedTable();
if (nestedTable != null) {
// The table is empty
if (n.getNestedTableRows().isEmpty()) {
String fillHTableId = n.getNode().getNestedTable()
.getHTableId();
Stroke stroke = new Stroke(StrokeStyle.outer, fillHTableId,
n.getDepth() + 1);
for (int j = lr.getLeft(); j <= lr.getRight(); j++) {
VDCell c = cells[n.getStartLevel()][j];
// System.err.println("EMPTY TABLE row=" + n.getStartLevel()
// + ", col=" + j);
c.setDepth(n.getDepth() + 1);
c.setFillHTableId(fillHTableId);
c.addTopStroke(stroke);
c.addBottomStroke(stroke);
c.setNodeIdWhenPartOfEmptyTable(n.getNode());
}
cells[n.getStartLevel()][lr.getLeft()].addLeftStroke(stroke);
cells[n.getStartLevel()][lr.getRight()].addRightStroke(stroke);
}
// The table is not empty.
else {
for (VDRow vdRow : n.getNestedTableRows()) {
populateFromVDRow(vdRow, vWorksheet, vWorkspace);
}
}
}
// It is a leaf node.
else {
VDCell c = cells[n.getStartLevel()][lr.getLeft()];
c.setDepth(n.getDepth());
c.setNode(n.getNode());
}
}
private void setDefaultStrokes(VDTableData vdTableData,
VWorkspace vWorkspace) {
for (VDRow vdRow : vdTableData.getRows()) {
setDefaultStrokesVDRow(vdRow, vWorkspace);
}
}
private void setDefaultStrokesVDRow(VDRow vdRow, VWorkspace vWorkspace) {
String fill = vdRow.getFillHTableId();
LeftRight lr = vdIndexTable.get(vdRow.getContainerHNodeId(vWorkspace));
Stroke stroke = new Stroke(StrokeStyle.none, fill, vdRow.getDepth());
for (int i = vdRow.getStartLevel(); i <= vdRow.getLastLevel(); i++) {
for (int j = lr.getLeft(); j <= lr.getRight(); j++) {
cells[i][j].setDefaultStrokes(stroke, defaultStrokes);
}
}
for (VDTreeNode n : vdRow.getNodes()) {
setDefaultStrokesFromVDTreeNode(n, vWorkspace);
}
}
private void setDefaultStrokesFromVDTreeNode(VDTreeNode n,
VWorkspace vWorkspace) {
Table nestedTable = n.getNode().getNestedTable();
LeftRight lr = vdIndexTable.get(n.getHNode(vWorkspace).getId());
if (nestedTable != null) {
if (n.getNestedTableRows().isEmpty()) {
String fill = n.getNode().getNestedTable().getHTableId();
Stroke stroke = new Stroke(StrokeStyle.none, fill,
n.getDepth() + 1);
for (int j = lr.getLeft(); j <= lr.getRight(); j++) {
cells[n.getStartLevel()][j].setDefaultStrokes(stroke,
defaultStrokes);
}
} else {
for (VDRow vdRow : n.getNestedTableRows()) {
setDefaultStrokesVDRow(vdRow, vWorkspace);
}
}
}
// The table is not empty. Not sure this is needed.
else {
Stroke stroke = new Stroke(StrokeStyle.none,
n.getContainerHTableId(vWorkspace), n.getDepth());
cells[n.getStartLevel()][lr.getLeft()].setDefaultStrokes(stroke,
defaultStrokes);
}
}
public void generateJson(JSONWriter jw, VWorksheet vWorksheet,
VWorkspace vWorkspace) {
try {
jw.object()
.key(AbstractUpdate.GenericJsonKeys.updateType.name())
.value(WorksheetHierarchicalDataUpdate.class
.getSimpleName())
//
.key(worksheetId.name()).value(vWorksheet.getId())//
.key(rows.name()).array()//
;
generateAllJsonRows(jw, vWorksheet, vWorkspace);
jw.endArray();
jw.endObject();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Generate all the TRs for content and separators.
*
* @param jw
* @param vWorksheet
* @param vWorkspace
* @throws JSONException
*/
private void generateAllJsonRows(JSONWriter jw, VWorksheet vWorksheet,
VWorkspace vWorkspace) throws JSONException {
int index = 0;
while (index < numRows) {
generateJsonRows(index, jw, vWorksheet, vWorkspace);
index++;
}
}
/**
* Generate the TR rows for a specific row in the cells array.
*
* @param index
* in the cells array.
* @param jw
* @param vWorksheet
* @param vWorkspace
* @throws JSONException
*/
private void generateJsonRows(int index, JSONWriter jw,
VWorksheet vWorksheet, VWorkspace vWorkspace) throws JSONException {
MinMaxDepth topCombinedMinMaxDepth = getMinMaxDepth(index, Position.top);
MinMaxDepth bottomCombinedMinMaxDepth = getMinMaxDepth(index,
Position.bottom);
generateJsonSeparatorRows(index, Position.top, topCombinedMinMaxDepth,
jw, vWorksheet, vWorkspace);
generateJsonContentRow(index, jw, topCombinedMinMaxDepth,
bottomCombinedMinMaxDepth, vWorksheet, vWorkspace);
generateJsonSeparatorRows(index, Position.bottom,
bottomCombinedMinMaxDepth, jw, vWorksheet, vWorkspace);
}
/**
* Generate the separator rows for a specific row in the cells array.
*
* @param index
* of a row in the cells array.
* @param position
* either top or bottom.
* @param jw
* @param vWorksheet
* @param vWorkspace
* @throws JSONException
*/
private void generateJsonSeparatorRows(int index, Position position,
MinMaxDepth combinedMinMaxDepth, JSONWriter jw,
VWorksheet vWorksheet, VWorkspace vWorkspace) throws JSONException {
VDCell c = cells[index][0];
VDCellStrokes vdcs = c.getVdCellStrokes();
StrokeIterator it = vdcs.iterator(position);
int counter = 1;
while (it.hasNext()) {
generateJsonOneSeparatorRow(index, it.next().getDepth(), position,
counter, jw, vWorksheet, vWorkspace);
counter++;
}
}
/**
* Analyze the whole row and find the depths of all the strokes on all the
* cells. We need to know how many separator rows we need to generate.
*
* @param index
* of a row.
* @param position
* either top or bottom.
* @return objet containing the minimum and maximum depths of all the
* strokes (in a given position) in all the cells of a row.
*/
private MinMaxDepth getMinMaxDepth(int index, Position position) {
List<MinMaxDepth> rowMinMaxDepths = new LinkedList<MinMaxDepth>();
for (int j = 0; j < numCols; j++) {
rowMinMaxDepths.add(cells[index][j].getMinMaxStrokeDepth(position));
}
MinMaxDepth combinedMinMaxDepth = MinMaxDepth.combine(rowMinMaxDepths);
return combinedMinMaxDepth;
}
/**
* Generate a single separator TR row for a specific row in the cells array.
*
* @param index
* of the cells row we are generating separators for.
* @param separatorDepth
* @param position
* @param separatorRowCounter
* @param jw
* @param vWorksheet
* @param vWorkspace
* @throws JSONException
*/
private void generateJsonOneSeparatorRow(int index, int separatorDepth,
Position position, int separatorRowCounter, JSONWriter jw,
VWorksheet vWorksheet, VWorkspace vWorkspace) throws JSONException {
jw.object().key(rowType.name()).value(separatorRow.name());
Position strokePosition = position;
VTableCssTags css = vWorkspace.getViewFactory().getTableCssTags();
jw.key(rowCells.name()).array();
for (int j = 0; j < numCols; j++) {
VDCell c = cells[index][j];
int columnDepth = vdIndexTable.getColumnDepth(j) - 1;
// vertical separators.
generateJsonVerticalSeparators(Position.left, position, index, j,
separatorDepth, separatorRowCounter, jw, vWorksheet,
vWorkspace);
// Now the horizontal separator cell top/bottom strokes.
// Stroke strokeTB = c.getVdCellStrokes().getStroke(strokePosition,
// separatorDepth);
Stroke strokeTB = c.getVdCellStrokes().getStrokeByIndex(
strokePosition,
c.getVdCellStrokes().ordinalToIndex(strokePosition,
separatorRowCounter));
if (strokeTB == null) {// TODO
strokeTB = new Stroke(StrokeStyle.none, "root", 0);
}
// Now calculate the left and right strokes.
// TODO: refactor separatorDepth, should not be using it.
int cssDepth = 0;
StrokeStyle leftStrokeStyle = StrokeStyle.none;
if (separatorDepth >= columnDepth) {
leftStrokeStyle = c.getVdCellStrokes()
.getStroke(Position.left, separatorDepth).getStyle();
}
StrokeStyle rightStrokeStyle = StrokeStyle.none;
if (separatorDepth >= columnDepth) {
rightStrokeStyle = c.getVdCellStrokes()
.getStroke(Position.right, separatorDepth).getStyle();
}
StrokeStyles strokeStyles = new StrokeStyles();
strokeStyles.setStrokeStyle(strokePosition, strokeTB.getStyle());
strokeStyles.setStrokeStyle(Position.left, leftStrokeStyle);
strokeStyles.setStrokeStyle(Position.right, rightStrokeStyle);
if (separatorDepth >= columnDepth)
cssDepth = columnDepth;
else
cssDepth = separatorDepth;
String attributes = encodeForJson(CellType.rowSpace,
strokeTB.getHTableId(),
css.getCssTag(strokeTB.getHTableId(), cssDepth),
strokeStyles);
jw.object()
.key(JsonKeys.attr.name())
.value(attributes)
//
.key("_row")
.value(index)
//
.key("_col")
.value(j)
//
.key("_depth")
.value(c.getDepth())
//
.key("_columnDepth")
.value(columnDepth)
//
.key("_horizontalSeparatorDepth")
.value(separatorDepth)
//
.key("_corner")
.value(""
+ separatorRowCounter
+ ":"
+ c.getVdCellStrokes().ordinalToIndex(
strokePosition, separatorRowCounter)
+ " TB: " + strokeTB.toString())
//
.key("_leftStrokes")
.value(Stroke.toString(c.getLeftStrokes()))
//
.key("_rightStrokes")
.value(Stroke.toString(c.getRightStrokes()))
//
.key("_topStrokes")
.value(Stroke.toString(c.getTopStrokes()))
//
.key("_bottomStrokes")
.value(Stroke.toString(c.getBottomStrokes()))//
.key("_position").value(position.name())//
;
jw.key("_vdCellStrokes");
c.getVdCellStrokes().prettyPrintJson(jw, defaultStrokes);
jw.endObject();
// Now the vertical separators on the right.
generateJsonVerticalSeparators(Position.right, position, index, j,
separatorDepth, separatorRowCounter, jw, vWorksheet,
vWorkspace);
}
jw.endArray();
jw.endObject();
}
/**
* Generate the vertical separators, both in the horizontal separator rows
* and content rows.
*
* @param leftRight
* , is this separator left or right from its base cell.
* @param topBottom
* , is this separator top or bottom from its base cell.
* @param rowIndex
* , the row index of the base cell.
* @param columnIndex
* , the column index of the base cell.
* @param horizontalSeparatorDepth
* , when there are multiple horizontal separators, each one has
* a depth.
* @param jw
* @param vWorksheet
* @param vWorkspace
* @throws JSONException
*/
private void generateJsonVerticalSeparators(Position leftRight,
Position topBottom, int rowIndex, int columnIndex,
int horizontalSeparatorDepth, int separatorRowCounter,
JSONWriter jw, VWorksheet vWorksheet, VWorkspace vWorkspace)
throws JSONException {
VDCell c = cells[rowIndex][columnIndex];
VDCellStrokes vdcs = c.getVdCellStrokes();
StrokeIterator it = vdcs.iterator(leftRight);
int counter = 1;
while (it.hasNext()) {
generateJsonOneVerticalSeparators(leftRight, topBottom, rowIndex,
columnIndex, horizontalSeparatorDepth, separatorRowCounter,
it.next(), counter, jw, vWorksheet, vWorkspace);
counter++;
}
}
private void generateJsonOneVerticalSeparators(Position leftRight,
Position topBottom, int rowIndex, int colIndex,
int horizontalSeparatorDepth, int separatorRowCounter,
Stroke columnSeparatorStroke, int columnCounter, JSONWriter jw,
VWorksheet vWorksheet, VWorkspace vWorkspace) throws JSONException {
VTableCssTags css = vWorkspace.getViewFactory().getTableCssTags();
VDCell c = cells[rowIndex][colIndex];
VDCellStrokes vdcs = c.getVdCellStrokes();
int lrIndex = vdcs.ordinalToIndex(leftRight, columnCounter);
int tbIndex = vdcs.ordinalToIndex(topBottom, separatorRowCounter);
Stroke strokeLR = vdcs.getStrokeByIndex(leftRight, lrIndex);
Stroke strokeTB = vdcs.getStrokeByIndex(topBottom, tbIndex);
{// Handle dummy cells.
//
// TODO: we only need the fill, re-arrange the code so we don't need
// to make a stroke.
if (strokeLR.getDepth() > c.getDepth()) {
String fill = vdcs.getHTableId(c.getDepth());
strokeLR = new Stroke(StrokeStyle.none, fill, c.getDepth());
}
if (strokeTB.getDepth() > c.getDepth()) {
String fill = vdcs.getHTableId(c.getDepth());
strokeTB = new Stroke(StrokeStyle.none, fill, c.getDepth());
}
}
StrokeStyle leftRightStrokeStyle = StrokeStyle.none;
StrokeStyle topBottomStrokeStyle = StrokeStyle.none;
StrokeStyle leftRightOppositeStrokeStyle = StrokeStyle.none;
StrokeStyle topBottomOppositeStrokeStyle = StrokeStyle.none;
String hTableId = columnSeparatorStroke.getHTableId();
// For the case when the vertical separator is in the same TR row as the
// content.
if (tbIndex == -1) {
leftRightStrokeStyle = strokeLR.getStyle();
hTableId = strokeLR.getHTableId();
}
else if (strokeLR.getDepth() == strokeTB.getDepth()) {
leftRightStrokeStyle = strokeLR.getStyle();
topBottomStrokeStyle = strokeTB.getStyle();
hTableId = strokeLR.getHTableId();
}
else if (strokeLR.getDepth() < strokeTB.getDepth()) {
leftRightStrokeStyle = strokeLR.getStyle();
hTableId = strokeLR.getHTableId();
}
else {
topBottomStrokeStyle = strokeTB.getStyle();
hTableId = strokeTB.getHTableId();
}
// ColumnSeparatorLocation csl = vdcs.getColumnSeparatorLocation(
// leftRight, columnCounter, topBottom, separatorRowCounter);
// switch (csl) {
// case corner: {
// // Stroke strokeLR = vdcs.getStroke(leftRight,
// // horizontalSeparatorDepth);
// Stroke strokeLR = vdcs.getStrokeByIndex(leftRight, lrIndex);
// leftRightStrokeStyle = strokeLR.getStyle();
// hTableId = strokeLR.getHTableId();
//
// // Stroke strokeTB = vdcs.getStroke(topBottom,
// // columnSeparatorStroke.getDepth());
// Stroke strokeTB = vdcs.getStrokeByIndex(topBottom, tbIndex);
// if (strokeTB == null) {// TODO
// strokeTB = new Stroke(StrokeStyle.none, "strokeTB", 0);
// }
// topBottomStrokeStyle = strokeTB.getStyle();
//
// // For empty tables we need to draw the whole thing all around.
// if (c.isForEmptyTable() && horizontalSeparatorDepth == c.getDepth())
// {
// topBottomOppositeStrokeStyle = topBottomStrokeStyle;
// String hNodeId = c.getNodeIdWhenPartOfEmptyTable().getHNodeId();
// LeftRight lf = vdIndexTable.get(hNodeId);
// switch (leftRight) {
// case left:
// if (lf.getLeft() == colIndex) {
// leftRightOppositeStrokeStyle = topBottomStrokeStyle;
// }
// break;
// case right:
// if (lf.getRight() == colIndex) {
// leftRightOppositeStrokeStyle = topBottomStrokeStyle;
// }
// break;
// }
// }
// break;
// }
//
// case leftOrRightOfCorner: {
// leftRightStrokeStyle = StrokeStyle.none;
// Stroke stroke = vdcs.getStroke(topBottom, horizontalSeparatorDepth);
// if (stroke != null) {
// topBottomStrokeStyle = stroke.getStyle();
// hTableId = stroke.getHTableId();
// }
// break;
// }
//
// case topOrBottomOfCorner: {
// topBottomStrokeStyle = StrokeStyle.none;
// Stroke stroke = vdcs.getStroke(leftRight,
// columnSeparatorStroke.getDepth());
// if (stroke != null) {
// leftRightStrokeStyle = stroke.getStyle();
// hTableId = stroke.getHTableId();
// }
// break;
// }
// }
StrokeStyles strokeStyles = new StrokeStyles();
strokeStyles.setStrokeStyle(leftRight, leftRightStrokeStyle);
strokeStyles.setStrokeStyle(topBottom, topBottomStrokeStyle);
strokeStyles.setStrokeStyle(leftRight.getOpposite(),
leftRightOppositeStrokeStyle);
strokeStyles.setStrokeStyle(topBottom.getOpposite(),
topBottomOppositeStrokeStyle);
String attributes = encodeForJson(CellType.columnSpace, hTableId,
css.getCssTag(hTableId, columnSeparatorStroke.getDepth()),
strokeStyles);
int columnDepth = vdIndexTable.getColumnDepth(colIndex) - 1;
jw.object()
.key(JsonKeys.attr.name())
.value(attributes)
//
.key("_EmptyT")
.value("Empty= " + c.isForEmptyTable())
//
.key("_row")
.value(rowIndex)
//
.key("_col")
.value(colIndex)
//
.key("_columnDepth")
.value(columnDepth)
//
.key("_depth")
.value(c.getDepth())
//
.key("_horizontalSeparatorDepth")
.value(horizontalSeparatorDepth)
//
.key("columnSeparatorStroke")
.value(columnSeparatorStroke.toString())
//
.key("_corner")
.value("" + columnCounter + ":" + lrIndex + "||"
+ separatorRowCounter + ":" + tbIndex + " LR:"
+ strokeLR.toString() + " TB: " + strokeTB.toString())
//
.key("_LR")
.value(leftRight.name())
//
.key("_LR_strokes")
.value(Stroke.toString(c.getStrokeList(leftRight)))
//
.key("_TB")
.value(topBottom.name())
//
.key("_TB_Strokes")
.value(Stroke.toString(c.getStrokeList(topBottom)))
//
.key("_leftStrokes")
.value(Stroke.toString(c.getLeftStrokes()))
//
.key("_rightStrokes")
.value(Stroke.toString(c.getRightStrokes()))
//
.key("_topStrokes").value(Stroke.toString(c.getTopStrokes()))
//
.key("_bottomStrokes")
.value(Stroke.toString(c.getBottomStrokes()))//
;
jw.key("_vdCellStrokes");
c.getVdCellStrokes().prettyPrintJson(jw, defaultStrokes);
jw.endObject();
}
/**
* The content rows are the TRs that hold the cell values.
*
* @param index
* of the row to be generated.
* @param jw
* @param topCombinedMinMaxDepth
* @param bottomCombinedMinMaxDepth
* @param vWorksheet
* @param vWorkspace
* @throws JSONException
*/
private void generateJsonContentRow(int index, JSONWriter jw,
MinMaxDepth topCombinedMinMaxDepth,
MinMaxDepth bottomCombinedMinMaxDepth, VWorksheet vWorksheet,
VWorkspace vWorkspace) throws JSONException {
jw.object().key(rowType.name()).value(contentRow.name())//
.key("_row").value(index)//
;
jw.key(rowCells.name()).array();
for (int j = 0; j < numCols; j++) {
generateJsonContentCell(index, j, jw, vWorksheet, vWorkspace);
}
jw.endArray().endObject();
}
/**
* Generate the representation of what will be a TD in the browser.
*
* @param rowIndex
* @param colIndex
* @param topCombinedMinMaxDepth
* @param bottomCombinedMinMaxDepth
* @param jw
* @param vWorksheet
* @param vWorkspace
* @throws JSONException
*/
private void generateJsonContentCell(int rowIndex, int colIndex,
JSONWriter jw, VWorksheet vWorksheet, VWorkspace vWorkspace)
throws JSONException {
VTableCssTags css = vWorkspace.getViewFactory().getTableCssTags();
VDCell c = cells[rowIndex][colIndex];
// Cannot use columnDepth because the cell may have an empty table that
// has the potential to have further nested tables. When the table is
// empty, the columnDepth may be larger than the actual depth of the
// cell.
int columnDepth = vdIndexTable.getColumnDepth(colIndex) - 1;
int cellDepth = c.isForEmptyTable() ? c.getDepth() : columnDepth;
// vertical separators.
// Using Position.top is arbitrary, just testing to see whether it
// works.
generateJsonVerticalSeparators(Position.left, Position.top, rowIndex,
colIndex, cellDepth, 0, jw, vWorksheet, vWorkspace);
boolean isValueTruncated = false;
CellValue cellValue = c.getNode() == null ? null : c.getNode().getValue();
String valueString = (cellValue == null || cellValue.asString() == null) ? "" : cellValue.asString();
if(valueString.length() > vWorkspace.getPreferences().getIntViewPreferenceValue(
ViewPreference.maxCharactersInCell)) {
valueString = JSONUtil.truncateCellValue(
valueString,
vWorkspace.getPreferences().getIntViewPreferenceValue(
ViewPreference.maxCharactersInCell));
isValueTruncated = true;
}
String codedStatus = c.getNode() == null ? "" : c.getNode().getStatus()
.getCodedStatus();
StrokeStyles strokeStyles = new StrokeStyles();
c.getVdCellStrokes().populateStrokeStyles(strokeStyles);
String attributes = encodeForJson(
c.getNode() == null ? CellType.dummyContent : CellType.content,
c.getFillHTableId(),
css.getCssTag(c.getFillHTableId(), c.getDepth()), strokeStyles);
jw.object()
.key(JsonKeys.attr.name())
.value(attributes)
//
.key(value.name())
.value(valueString)
//
.key(status.name())
.value(codedStatus)
//
.key("_row")
.value(rowIndex)
//
.key("_col")
.value(colIndex)
// //
// .key("_topCombinedMinMaxDepth")
// .value(topCombinedMinMaxDepth.toString())
// //
// .key("_columnDepth").value(columnDepth)
//
.key("_depth")
.value(c.getDepth())
//
.key("_leftStrokes")
.value("LEF " + Stroke.toString(c.getLeftStrokes()))
//
.key("_rightStrokes")
.value("RIG " + Stroke.toString(c.getRightStrokes()))
//
.key("_topStrokes")
.value("TOP " + Stroke.toString(c.getTopStrokes()))
//
.key("_bottomStrokes")
.value("BOT " + Stroke.toString(c.getBottomStrokes()))//
;
// Add the node id
if(c.getNode() != null){
jw.key(JsonKeys.nodeId.name())
.value(c.getNode().getId());
}
// Add the full value if the display value was truncated
jw.key(isTruncated.name())
.value(isValueTruncated);
if(isValueTruncated) {
jw.key(fullValue.name())
.value(cellValue.asString());
}
jw.key("_vdCellStrokes");
c.getVdCellStrokes().prettyPrintJson(jw, defaultStrokes);
jw.endObject();
// vertical separators.
// Using Position.top is arbitrary, just testing to see whether it
// works.
// Need to clean up the code.
generateJsonVerticalSeparators(Position.right, Position.top, rowIndex,
colIndex, cellDepth, 0, jw, vWorksheet, vWorkspace);
}
private String encodeForJson(CellType cellType, String hTableId,
String fillId, StrokeStyles strokeStyles) {
return cellType.code()//
+ ":" + hTableId + ":" + fillId//
+ ":" + strokeStyles.getJsonEncoding();
}
/*****************************************************************
*
* Debugging Support
*
*****************************************************************/
void prettyPrintJson(JSONWriter jw) throws JSONException {
jw.array();
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
jw.object()//
.key("_ row").value(i)// //Want rows displayed before in
// the JSON output.
.key("__col").value(j)//
;
cells[i][j].prettyPrintJson(jw);
jw.endObject();
}
}
jw.endArray();
}
}