package org.geogebra.common.gui.view.spreadsheet; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import org.geogebra.common.awt.GColor; import org.geogebra.common.awt.GFont; import org.geogebra.common.awt.GPoint; import org.geogebra.common.gui.view.spreadsheet.CellRangeProcessor.Direction; import org.geogebra.common.main.App; /** * Helper class that handles cell formats for the spreadsheet table cell * renderer. * * Format values are stored in an array of hash tables. Each hash table holds * values for a given format (e.g text alignment, background color). Table keys * are Point objects that locate cells, rows or columns as follows: * * cell = (column index, row index) row = (-1, row index) column = (column * index, -1). * * @author George Sturr, 2010-4-4 * */ public class CellFormat implements CellFormatInterface { MyTableInterface table; App app; private int highestIndexRow = 0; private int highestIndexColumn = 0; private String cellFormatString; // Array of format tables private MyHashMap[] formatMapArray; // Format types. // These are also array indices, so they must be sequential: 0..n public static final int FORMAT_ALIGN = 0; public static final int FORMAT_BORDER = 1; public static final int FORMAT_BGCOLOR = 2; public static final int FORMAT_FONTSTYLE = 3; private int formatCount = 5; // Alignment constants public static final int ALIGN_LEFT = 2;// SwingConstants.LEFT; public static final int ALIGN_CENTER = 0;// SwingConstants.CENTER; public static final int ALIGN_RIGHT = 4;// SwingConstants.RIGHT; // Font syle constants public static final int STYLE_PLAIN = GFont.PLAIN;// Font.PLAIN; public static final int STYLE_BOLD = GFont.BOLD;// Font.BOLD; public static final int STYLE_ITALIC = GFont.ITALIC;// Font.ITALIC; public static final int STYLE_BOLD_ITALIC = GFont.BOLD + GFont.ITALIC; // Border style constants used by stylebar. // Keep this order, they are indices to the border popup button menu public static final int BORDER_STYLE_NONE = 0; public static final int BORDER_STYLE_FRAME = 1; public static final int BORDER_STYLE_INSIDE = 2; public static final int BORDER_STYLE_ALL = 3; public static final int BORDER_STYLE_TOP = 4; public static final int BORDER_STYLE_BOTTOM = 5; public static final int BORDER_STYLE_LEFT = 6; public static final int BORDER_STYLE_RIGHT = 7; // Border constants for painting // These are stored in a format map and are bit-decoded when painting // borders public static final byte BORDER_LEFT = 1; public static final byte BORDER_TOP = 2; public static final byte BORDER_RIGHT = 4; public static final byte BORDER_BOTTOM = 8; public static final byte BORDER_ALL = 15; // sum // XML tokens and delimiters private static final String formatDelimiter = ","; private static final String cellDelimiter = ":"; private static final String alignToken = "a"; private static final String borderToken = "b"; private static final String fontStyleToken = "f"; private static final String bgColorToken = "c"; // map to convert token to format type private static HashMap<String, Integer> formatTokenMap = new HashMap<String, Integer>(); static { formatTokenMap.put(alignToken, FORMAT_ALIGN); formatTokenMap.put(borderToken, FORMAT_BORDER); formatTokenMap.put(fontStyleToken, FORMAT_FONTSTYLE); formatTokenMap.put(bgColorToken, FORMAT_BGCOLOR); } /** * Constructor * * @param table */ public CellFormat(MyTableInterface table) { this.table = table; app = table.getApplication(); // Create instances of the format hash maps formatMapArray = new MyHashMap[formatCount]; for (int i = 0; i < formatCount; i++) { formatMapArray[i] = new MyHashMap(); } } // ======================================================== // MyHashMap // ======================================================== /** * Class that extends HashMap so that null values cannot be mapped and a * call to put(key, null) will remove a key if it exists already. * * TODO: It would be better practice to use an immutable key, e.g. a string * to record the cell location. */ private static class MyHashMap extends HashMap<GPoint, Object> { private static final long serialVersionUID = 1L; protected MyHashMap() { // Auto-generated constructor stub } @Override public Object put(GPoint key, Object value) { if (value == null) { super.remove(key); return null; } return super.put(key, value); } } // ======================================================== // Clear and Shift Formats // ======================================================== /** * Clears all format objects from the maps */ public void clearAll() { highestIndexRow = 0; highestIndexColumn = 0; for (int i = 0; i < formatMapArray.length; i++) { formatMapArray[i].clear(); } } /** * Shifts the formats a set of rows or columns over a given number indices. * The set of rows or columns to be shifted is a block that begins at a * specified start index and includes all larger indices. * * @param startIndex * Index of the first row or column to shift. * @param shiftAmount * Number of indices to increment each row or column * @param direction * Direction to shift rows or columns (Up or Down = shift rows, * Left or Right = columns) */ @Override public void shiftFormats(int startIndex, int shiftAmount, CellRangeProcessor.Direction direction) { if (startIndex - shiftAmount < 0) { return; } // shift rows for each format type map for (int i = 0; i < formatMapArray.length; i++) { if (direction == Direction.Up) { shiftRowsUp(formatMapArray[i], startIndex, shiftAmount); } if (direction == Direction.Down) { shiftRowsDown(formatMapArray[i], startIndex, shiftAmount); } if (direction == Direction.Left) { shiftColumnsLeft(formatMapArray[i], startIndex, shiftAmount); } else if (direction == Direction.Right) { shiftColumnsRight(formatMapArray[i], startIndex, shiftAmount); } } if (direction == Direction.Left) { highestIndexColumn = highestIndexColumn - shiftAmount; } else if (direction == Direction.Right) { highestIndexColumn = highestIndexColumn + shiftAmount; } else if ((direction == Direction.Up)) { highestIndexRow = highestIndexRow - shiftAmount; } else if (direction == Direction.Down) { highestIndexRow = highestIndexRow + shiftAmount; } } private void shiftRowsUp(MyHashMap formatMap, int rowStart, int shiftAmount) { if (formatMap == null || formatMap.isEmpty()) { return; } GPoint key = null; GPoint shiftKey = null; // clear first row to be shifted into clearRows(formatMap, rowStart - shiftAmount, rowStart - shiftAmount); // shift row formats for (int r = rowStart; r <= highestIndexRow; r++) { key = new GPoint(-1, r); if (formatMap.containsKey(key)) { shiftKey = new GPoint(-1, r - shiftAmount); formatMap.put(shiftKey, formatMap.remove(key)); } } // shift cell formats for (int r = rowStart; r <= highestIndexRow; r++) { for (int c = 0; c <= highestIndexColumn; c++) { key = new GPoint(c, r); if (formatMap.containsKey(key)) { shiftKey = new GPoint(c, r - shiftAmount); formatMap.put(shiftKey, formatMap.remove(key)); } } } } private void shiftRowsDown(MyHashMap formatMap, int rowStart, int shiftAmount) { if (formatMap == null || formatMap.isEmpty()) { return; } GPoint key = null; GPoint shiftKey = null; // shift row formats for (int r = highestIndexRow; r >= rowStart; r--) { key = new GPoint(-1, r); if (formatMap.containsKey(key)) { shiftKey = new GPoint(-1, r + shiftAmount); formatMap.put(shiftKey, formatMap.remove(key)); } } // shift cell formats for (int r = highestIndexRow; r >= rowStart; r--) { for (int c = 0; c <= highestIndexColumn; c++) { key = new GPoint(c, r); if (formatMap.containsKey(key)) { shiftKey = new GPoint(c, r + shiftAmount); formatMap.put(shiftKey, formatMap.remove(key)); } } } } private void clearRows(MyHashMap formatMap, int rowStart, int rowEnd) { if (formatMap == null || formatMap.isEmpty()) { return; } GPoint key = null; // clear all row formats for (int r = rowStart; r <= rowEnd; r++) { key = new GPoint(-1, r); if (formatMap.containsKey(key)) { formatMap.remove(key); } } // clear all cell formats for (int r = rowStart; r <= rowEnd; r++) { for (int c = 0; c <= highestIndexColumn; c++) { key = new GPoint(c, r); if (formatMap.containsKey(key)) { formatMap.remove(key); } } } } private void shiftColumnsLeft(MyHashMap formatMap, int columnStart, int shiftAmount) { if (formatMap == null || formatMap.isEmpty()) { return; } GPoint key = null; GPoint shiftKey = null; // clear first column to be shifted into clearColumns(formatMap, columnStart - shiftAmount, columnStart - shiftAmount); // shift column formats for (int c = columnStart; c <= highestIndexColumn; c++) { key = new GPoint(c, -1); if (formatMap.containsKey(key)) { shiftKey = new GPoint(c - shiftAmount, -1); formatMap.put(shiftKey, formatMap.remove(key)); } } // shift cell formats for (int c = columnStart; c <= highestIndexColumn; c++) { for (int r = 0; r <= highestIndexRow; r++) { key = new GPoint(c, r); if (formatMap.containsKey(key)) { shiftKey = new GPoint(c - shiftAmount, r); formatMap.put(shiftKey, formatMap.remove(key)); } } } } private void shiftColumnsRight(MyHashMap formatMap, int columnStart, int shiftAmount) { if (formatMap == null || formatMap.isEmpty()) { return; } GPoint key = null; GPoint shiftKey = null; // shift column formats for (int c = highestIndexColumn; c >= columnStart; c--) { key = new GPoint(c, -1); if (formatMap.containsKey(key)) { shiftKey = new GPoint(c + shiftAmount, -1); formatMap.put(shiftKey, formatMap.remove(key)); } } // shift cell formats for (int c = highestIndexColumn; c >= columnStart; c--) { for (int r = 0; r <= highestIndexRow; r++) { key = new GPoint(c, r); if (formatMap.containsKey(key)) { shiftKey = new GPoint(c + shiftAmount, r); formatMap.put(shiftKey, formatMap.remove(key)); } } } } private void clearColumns(MyHashMap formatMap, int columnStart, int columnEnd) { if (formatMap == null || formatMap.isEmpty()) { return; } GPoint key = null; // clear all column formats for (int c = columnStart; c <= columnEnd; c++) { key = new GPoint(c, -1); if (formatMap.containsKey(key)) { formatMap.remove(key); } } // clear all cell formats for (int c = columnStart; c <= columnEnd; c++) { for (int r = 0; r <= highestIndexRow; r++) { key = new GPoint(c, r); if (formatMap.containsKey(key)) { formatMap.remove(key); } } } } // ======================================================== // Getters // ======================================================== /** * Returns the format map for a given cell format * * @param formatType * @return */ @Override public HashMap<GPoint, Object> getFormatMap(int formatType) { return formatMapArray[formatType]; } /** * Returns the format object for a given cell and a given format type. If * format does not exist, returns null. */ @Override public Object getCellFormat(int x, int y, int formatType) { MyHashMap formatMap = formatMapArray[formatType]; if (formatMap == null || formatMap.isEmpty()) { return null; } Object formatObject = null; // Create special keys for the cell, row and column GPoint rowKey = new GPoint(-1, y); GPoint columnKey = new GPoint(x, -1); GPoint cellKey = new GPoint(x, y); // Check there is a format for this cell if (formatMap.containsKey(cellKey)) { // System.out.println("found" + cellKey.toString()); formatObject = formatMap.get(cellKey); } // Check if there is a row format for this cell else if (formatMap.containsKey(rowKey)) { formatObject = formatMap.get(rowKey); } // Check if there is a column format for this cell else if (formatMap.containsKey(columnKey)) { formatObject = formatMap.get(columnKey); } return formatObject; } /** * Returns the format object shared by all cells in the given cell range for * the given format type. If a format object does not exist, or not all * cells share the same format object, null is returned. * * @param cr * @param formatType * @return */ public Object getCellFormat(CellRange cr, int formatType) { // Get the format in the upper left cell Object format = getCellFormat(cr.getMinColumn(), cr.getMinRow(), formatType); if (format == null) { return null; } // Iterate through the range and test if they cells have the same format for (int r = 0; r > cr.getMaxRow(); r++) { for (int c = 0; c > cr.getMaxColumn(); c++) { if (!format.equals(getCellFormat(c, r, formatType))) { format = null; break; } } } return format; } // ======================================================== // Setters // ======================================================== /** * Add a format value to a single cell. */ public void setFormat(GPoint cell, int formatType, Object formatValue) { ArrayList<CellRange> crList = new ArrayList<CellRange>(); crList.add(new CellRange(app, cell.x, cell.y)); setFormat(crList, formatType, formatValue); } public void doSetFormat(GPoint cell, int formatType, Object formatValue) { ArrayList<CellRange> crList = new ArrayList<CellRange>(); crList.add(new CellRange(app, cell.x, cell.y)); doSetFormat(crList, formatType, formatValue); } /** * Add a format value to a cell range. */ public void setFormat(CellRange cr, int formatType, Object formatValue) { ArrayList<CellRange> crList = new ArrayList<CellRange>(); crList.add(cr); setFormat(crList, formatType, formatValue); } /** * Add a format value to a list of cell ranges. */ public void setFormat(ArrayList<CellRange> crList, int formatType, Object value) { doSetFormat(crList, formatType, value); setCellFormatString(); table.repaint(); } private void doSetFormat(ArrayList<CellRange> crList, int formatType, Object value) { HashMap<GPoint, Object> formatTable = formatMapArray[formatType]; // handle select all case first, then exit if (table.isSelectAll() && value == null) { formatTable.clear(); return; } GPoint testCell = new GPoint(); GPoint testRow = new GPoint(); GPoint testColumn = new GPoint(); for (CellRange cr : crList) { // cr.debug(); if (cr.isRow()) { if (highestIndexRow < cr.getMaxRow()) { highestIndexRow = cr.getMaxRow(); } // iterate through each row in the selection for (int r = cr.getMinRow(); r <= cr.getMaxRow(); ++r) { // format the row formatTable.put(new GPoint(-1, r), value); // handle cells in the row with prior formatting for (int col = 0; col < highestIndexColumn; col++) { testCell.setLocation(col, r); testColumn.setLocation(col, -1); formatTable.remove(testCell); if (formatTable.containsKey(testColumn)) { formatTable.put(testCell, value); } } } } else if (cr.isColumn()) { if (highestIndexColumn < cr.getMaxColumn()) { highestIndexColumn = cr.getMaxColumn(); } // iterate through each column in the selection for (int c = cr.getMinColumn(); c <= cr.getMaxColumn(); ++c) { // format the column formatTable.put(new GPoint(c, -1), value); // handle cells in the column with prior formatting for (int row = 0; row < highestIndexRow; row++) { testCell.setLocation(c, row); testRow.setLocation(-1, row); formatTable.remove(testCell); if (formatTable.containsKey(testRow)) { // System.out.println(row); formatTable.put(testCell, value); } } } } else { if (highestIndexRow < cr.getMaxRow()) { highestIndexRow = cr.getMaxRow(); } if (highestIndexColumn < cr.getMaxColumn()) { highestIndexColumn = cr.getMaxColumn(); } // System.out.println("other"); for (GPoint cellPoint : cr.toCellList(true)) { formatTable.put(cellPoint, value); } } } } private void setCellFormatString() { StringBuilder sb = encodeFormats(); if (sb == null) { cellFormatString = null; } else { cellFormatString = sb.toString(); } table.updateCellFormat(cellFormatString); } /** * Iterates through the cell ranges of the given list of cell ranges and * sets the border format needed for each cell in order to produce the * specified border style * * @param cr * @param borderStyle */ public void setBorderStyle(ArrayList<CellRange> list, int borderStyle) { for (CellRange cr : list) { setBorderStyle(cr, borderStyle); } } /** * Iterates through the cells of the given cell range and sets the border * format needed for each cell in order to produce the specified border * style * * @param cr * @param borderStyle */ public void setBorderStyle(CellRange cr, int borderStyle) { int r1 = cr.getMinRow(); int r2 = cr.getMaxRow(); int c1 = cr.getMinColumn(); int c2 = cr.getMaxColumn(); GPoint cell = new GPoint(); GPoint cell2 = new GPoint(); // handle select all case first, then exit if (table.isSelectAll() && borderStyle == BORDER_STYLE_NONE) { formatMapArray[FORMAT_BORDER].clear(); return; } if (cr.isRow()) { switch (borderStyle) { default: case BORDER_STYLE_NONE: setFormat(cr, FORMAT_BORDER, null); break; case BORDER_STYLE_LEFT: case BORDER_STYLE_RIGHT: // nothing to draw break; case BORDER_STYLE_TOP: setFormat(cr, FORMAT_BORDER, BORDER_TOP); break; case BORDER_STYLE_BOTTOM: setFormat(cr, FORMAT_BORDER, BORDER_BOTTOM); break; case BORDER_STYLE_ALL: setFormat(cr, FORMAT_BORDER, BORDER_ALL); break; case BORDER_STYLE_INSIDE: setFormat(new CellRange(app, -1, cr.getMinRow(), -1, cr.getMinRow()), FORMAT_BORDER, BORDER_LEFT); if (cr.getMinRow() < cr.getMaxRow()) { byte b = BORDER_LEFT + BORDER_TOP; setFormat(new CellRange(app, -1, cr.getMinRow() + 1, -1, cr.getMaxRow()), FORMAT_BORDER, b); } break; case BORDER_STYLE_FRAME: setFormat(new CellRange(app, -1, cr.getMinRow(), -1, cr.getMinRow()), FORMAT_BORDER, BORDER_TOP); setFormat(new CellRange(app, -1, cr.getMaxRow(), -1, cr.getMaxRow()), FORMAT_BORDER, BORDER_BOTTOM); break; } return; } if (cr.isColumn()) { switch (borderStyle) { default: case BORDER_STYLE_NONE: setFormat(cr, FORMAT_BORDER, null); break; case BORDER_STYLE_TOP: case BORDER_STYLE_BOTTOM: // nothing to draw break; case BORDER_STYLE_LEFT: setFormat(cr, FORMAT_BORDER, BORDER_LEFT); break; case BORDER_STYLE_RIGHT: setFormat(cr, FORMAT_BORDER, BORDER_RIGHT); break; case BORDER_STYLE_ALL: setFormat(cr, FORMAT_BORDER, BORDER_ALL); break; case BORDER_STYLE_INSIDE: setFormat( new CellRange(app, cr.getMinColumn(), -1, cr.getMinColumn(), -1), FORMAT_BORDER, BORDER_TOP); if (cr.getMinColumn() < cr.getMaxColumn()) { byte b = BORDER_LEFT + BORDER_TOP; setFormat(new CellRange(app, cr.getMinColumn() + 1, -1, cr.getMaxColumn(), -1), FORMAT_BORDER, b); } break; case BORDER_STYLE_FRAME: setFormat( new CellRange(app, cr.getMinColumn(), -1, cr.getMinColumn(), -1), FORMAT_BORDER, BORDER_LEFT); setFormat( new CellRange(app, cr.getMaxColumn(), -1, cr.getMaxColumn(), -1), FORMAT_BORDER, BORDER_RIGHT); break; } return; } // handle all other selection types switch (borderStyle) { case BORDER_STYLE_NONE: for (int r = r1; r <= r2; r++) { for (int c = c1; c <= c2; c++) { setFormat(cr, FORMAT_BORDER, null); } } break; case BORDER_STYLE_ALL: for (int r = r1; r <= r2; r++) { for (int c = c1; c <= c2; c++) { cell.x = c; cell.y = r; setFormat(cell, FORMAT_BORDER, BORDER_ALL); } } break; case BORDER_STYLE_FRAME: // single cell if (r1 == r2 && c1 == c2) { cell.x = c1; cell.y = r1; setFormat(cell, FORMAT_BORDER, BORDER_ALL); return; } // top & bottom cell.y = r1; cell2.y = r2; for (int c = c1 + 1; c <= c2 - 1; c++) { cell.x = c; cell2.x = c; if (r1 == r2) { byte b = BORDER_TOP + BORDER_BOTTOM; setFormat(cell, FORMAT_BORDER, b); } else { setFormat(cell, FORMAT_BORDER, BORDER_TOP); setFormat(cell2, FORMAT_BORDER, BORDER_BOTTOM); } } // left & right cell.x = c1; cell2.x = c2; for (int r = r1 + 1; r <= r2 - 1; r++) { cell.y = r; cell2.y = r; if (c1 == c2) { byte b = BORDER_LEFT + BORDER_RIGHT; setFormat(cell, FORMAT_BORDER, b); } else { setFormat(cell, FORMAT_BORDER, BORDER_LEFT); setFormat(cell2, FORMAT_BORDER, BORDER_RIGHT); } } // CORNERS // case 1: column corners if (c1 == c2) { cell.x = c1; cell.y = r1; byte b = BORDER_LEFT + BORDER_RIGHT + BORDER_TOP; setFormat(cell, FORMAT_BORDER, b); cell.x = c1; cell.y = r2; b = BORDER_LEFT + BORDER_RIGHT + BORDER_BOTTOM; setFormat(cell, FORMAT_BORDER, b); } // case 2: row corners else if (r1 == r2) { cell.x = c1; cell.y = r1; byte b = BORDER_LEFT + BORDER_TOP + BORDER_BOTTOM; setFormat(cell, FORMAT_BORDER, b); cell.x = c2; cell.y = r1; b = BORDER_RIGHT + BORDER_TOP + BORDER_BOTTOM; setFormat(cell, FORMAT_BORDER, b); } // case 3: block corners else { cell.y = r1; cell.x = c1; byte b = BORDER_LEFT + BORDER_TOP; setFormat(cell, FORMAT_BORDER, b); cell.y = r1; cell.x = c2; b = BORDER_RIGHT + BORDER_TOP; setFormat(cell, FORMAT_BORDER, b); cell.y = r2; cell.x = c2; b = BORDER_RIGHT + BORDER_BOTTOM; setFormat(cell, FORMAT_BORDER, b); cell.y = r2; cell.x = c1; b = BORDER_LEFT + BORDER_BOTTOM; setFormat(cell, FORMAT_BORDER, b); } break; case BORDER_STYLE_INSIDE: for (int r = r1 + 1; r <= r2; r++) { cell.x = c1; cell.y = r; setFormat(cell, FORMAT_BORDER, BORDER_TOP); } for (int c = c1 + 1; c <= c2; c++) { cell.x = c; cell.y = r1; setFormat(cell, FORMAT_BORDER, BORDER_LEFT); } for (int r = r1 + 1; r <= r2; r++) { for (int c = c1 + 1; c <= c2; c++) { cell.x = c; cell.y = r; byte b = BORDER_LEFT + BORDER_TOP; setFormat(cell, FORMAT_BORDER, b); } } break; case BORDER_STYLE_TOP: cell.y = r1; for (int c = c1; c <= c2; c++) { cell.x = c; setFormat(cell, FORMAT_BORDER, BORDER_TOP); } break; case BORDER_STYLE_BOTTOM: cell.y = r2; for (int c = c1; c <= c2; c++) { cell.x = c; setFormat(cell, FORMAT_BORDER, BORDER_BOTTOM); } break; case BORDER_STYLE_LEFT: cell.x = c1; for (int r = r1; r <= r2; r++) { cell.y = r; setFormat(cell, FORMAT_BORDER, BORDER_LEFT); } break; case BORDER_STYLE_RIGHT: cell.x = c2; for (int r = r1; r <= r2; r++) { cell.y = r; setFormat(cell, FORMAT_BORDER, BORDER_RIGHT); } break; } } // ======================================================== // XML handling // ======================================================== /** * Returns XML representation of the format maps */ @Override public void getXML(StringBuilder sb) { StringBuilder cellFormat = encodeFormats(); if (cellFormat == null) { return; } sb.append("\t<spreadsheetCellFormat "); sb.append(" formatMap=\""); sb.append(cellFormat); sb.append("\""); sb.append("/>\n"); } /** * * @return StringBuilder object containing all current formats encoded as * strings */ public StringBuilder encodeFormats() { StringBuilder sb = new StringBuilder(); // create a set containing all cells with formats HashSet<GPoint> masterKeySet = new HashSet<GPoint>(); for (int i = 0; i < formatMapArray.length; i++) { masterKeySet.addAll(formatMapArray[i].keySet()); } if (masterKeySet.size() == 0) { return null; } // iterate through the set creating XML tags for each cell and its // formats for (GPoint cell : masterKeySet) { sb.append(cellDelimiter); sb.append(cell.x); sb.append(formatDelimiter); sb.append(cell.y); Integer align = (Integer) formatMapArray[FORMAT_ALIGN].get(cell); if (align != null) { sb.append(formatDelimiter); sb.append(alignToken); sb.append(formatDelimiter); sb.append(align); } Byte border = (Byte) formatMapArray[FORMAT_BORDER].get(cell); if (border != null) { sb.append(formatDelimiter); sb.append(borderToken); sb.append(formatDelimiter); sb.append(border); } GColor bgColor = (GColor) formatMapArray[FORMAT_BGCOLOR].get(cell); if (bgColor != null) { sb.append(formatDelimiter); sb.append(bgColorToken); sb.append(formatDelimiter); sb.append(bgColor.getRGB()); // convert to RGB integer } Integer fStyle = (Integer) formatMapArray[FORMAT_FONTSTYLE] .get(cell); if (fStyle != null) { sb.append(formatDelimiter); sb.append(fontStyleToken); sb.append(formatDelimiter); sb.append(fStyle); } } // remove the first delimiter sb.deleteCharAt(0); return sb; } /** * Decodes XML string and puts format values into the format maps. * * @param xml * String to be decoded */ @Override public void processXMLString(String xml) { clearAll(); if (xml == null) { return; } String[] cellGroup = xml.split(cellDelimiter); // System.out.println("cellGroup: " + // java.util.Arrays.toString(cellGroup)); for (int i = 0; i < cellGroup.length; i++) { if (cellGroup.length > 0) { processCellFormatString(cellGroup[i]); } } setCellFormatString(); table.repaintAll(); } /** * Decodes a string representing the format objects for a single cell and * then puts these formats into the format maps. * * @param formatStr */ private void processCellFormatString(String formatStr) { if ("null".equals(formatStr)) { return; } // System.out.println("cellFormat: " + formatStr); String[] f = formatStr.split(formatDelimiter); GPoint cell = new GPoint(Integer.parseInt(f[0]), Integer.parseInt(f[1])); int formatType; Object formatValue; for (int i = 2; i < f.length; i = i + 2) { formatType = formatTokenMap.get(f[i]); if (formatType == FORMAT_BGCOLOR) { // #4299 changed to Long // this Integer is of the form 0xAARRGGBB, // so remove the alpha channel to make it positive int fv = (int) (Long.parseLong(f[i + 1]) & 0x00ffffff); formatValue = GColor.newColorRGB(fv); } else if (formatType == FORMAT_BORDER) { long b = Long.parseLong(f[i + 1]); formatValue = (byte) b; } else { formatValue = Integer.parseInt(f[i + 1]); } this.doSetFormat(cell, formatType, formatValue); } } public static boolean isZeroBit(int value, int position) { return (value & (1 << position)) == 0; } }