--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.spreadsheet.util;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.apache.poi.ss.usermodel.DataFormatter;\r
+import org.simantics.Simantics;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.mutable.MutableVariant;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.datatypes.utils.BTree;\r
+import org.simantics.datatypes.utils.BTreeUtils;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.PossibleChild;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.exception.VariableException;\r
+import org.simantics.db.layer0.util.Layer0Utils;\r
+import org.simantics.db.layer0.variable.ProxyVariables;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.layer0.variable.VariableSpaceManipulator.PropertyCreationData;\r
+import org.simantics.db.layer0.variable.Variables;\r
+import org.simantics.db.request.Write;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.document.server.io.IColor;\r
+import org.simantics.document.server.io.IFont;\r
+import org.simantics.document.server.io.RGBColor;\r
+import org.simantics.document.server.io.SimpleFont;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.scl.runtime.function.Function1;\r
+import org.simantics.scl.runtime.tuple.Tuple;\r
+import org.simantics.spreadsheet.CellEditor;\r
+import org.simantics.spreadsheet.CellEditor.Transaction;\r
+import org.simantics.spreadsheet.ClientModel.OperationMode;\r
+import org.simantics.spreadsheet.ClientModel;\r
+import org.simantics.spreadsheet.Range;\r
+import org.simantics.spreadsheet.common.TableCell;\r
+import org.simantics.spreadsheet.common.cell.StringCellParser;\r
+import org.simantics.spreadsheet.common.exception.CellParseException;\r
+import org.simantics.spreadsheet.resource.SpreadsheetResource;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+public class SpreadsheetUtils {\r
+ \r
+ public static final int SPREADSHEET_BTREE_SIZE = 100;\r
+ \r
+ public static String offset(String location, int rowOffset, int columnOffset) {\r
+\r
+ Range range = decodeCellAbsolute(location);\r
+ String result = cellName(range.startRow + rowOffset, range.startColumn + columnOffset); \r
+ // System.err.println("offset " + location + "(" + rowOffset + " " + columnOffset + ") = >" + result);\r
+ return result;\r
+\r
+ }\r
+\r
+ public static Object extract(Object object, int row, int column) {\r
+ if(object instanceof List) {\r
+ List list = (List)object;\r
+ if(list.size() <= row) return null;\r
+ Object item = list.get(row);\r
+ if(item instanceof Tuple) {\r
+ Tuple tuple = (Tuple)item;\r
+ if(tuple.length() <= column) return null;\r
+ return tuple.get(column);\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ // 1 kirjain, 'A' + column\r
+ // 2 kirjainta, 'A' + column % 26 , 'A' + int((column-26)/26)\r
+ // 3 kirjainta 'A' + column % 26 , 'A' + int(column-(26*(26+1)) / 26) % 26\r
+\r
+ // 0 26\r
+ // 26 26 + 26*26\r
+ // 26 + 26*26 26 + 26*26 + 26*26*26\r
+\r
+ public static String columnName(int column, int current, int limit, int chars) {\r
+\r
+ if(column < limit) {\r
+\r
+ char[] buf = new char[chars];\r
+ column -= current;\r
+ for(int i=chars-1;i>=0;i--) {\r
+ char rem = (char)(column % 26);\r
+ column = (column / 26);\r
+ buf[i] = (char)('A' + rem); \r
+ }\r
+ return new String(buf);\r
+\r
+ } else return columnName(column, limit, 26*(limit+1), chars+1);\r
+\r
+ }\r
+\r
+ public static String columnName(int column) {\r
+ return columnName(column, 0, 26, 1);\r
+ } \r
+\r
+ public static String cellName(int row, int column) {\r
+\r
+ String result = columnName(column);\r
+ result += (row+1);\r
+ return result;\r
+\r
+ } \r
+\r
+ public static Range decodeCellAbsolute(String identifier) {\r
+ long l = decodeCellCoded(identifier);\r
+ int row = (int)(l & 0xffffffff) - 1;\r
+ int column = (int)((l>>32) & 0xffffffff);\r
+ return new Range(row, row, column, column);\r
+ }\r
+\r
+ public static Range decodePossibleCellAbsolute(String identifier) {\r
+ try {\r
+ return decodeCellAbsolute(identifier);\r
+ } catch (CellParseException e) {\r
+ return null;\r
+ }\r
+ }\r
+\r
+ public static long decodeCellCoded(String identifier) {\r
+\r
+ // System.out.println("decodecellabsolute " + identifier);\r
+\r
+ int row = 0;\r
+ int column = 0;\r
+ \r
+// identifier.\r
+ \r
+ int position = 0;\r
+ \r
+ // We skip $ here\r
+ if(identifier.charAt(position) == '$') position++;\r
+ \r
+ int length = identifier.length();\r
+ \r
+ while(position < length) {\r
+ char b = identifier.charAt(position);\r
+ if(b >= 'A' && b <= 'Z') column = column * 26 + (b-'A' + 1);\r
+ else break;\r
+ position++;\r
+ }\r
+\r
+ // We skip $ here\r
+ if(position < length)\r
+ if(identifier.charAt(position) == '$')\r
+ position++;\r
+\r
+ while(position < length) {\r
+ char b = identifier.charAt(position);\r
+ if(b >= '0' && b <= '9'){\r
+ row = row * 10 + b-'0';\r
+ }\r
+ else if(b=='-' && position < (length-1)){//identify use of full row range here.\r
+ position++;\r
+ char b2 = identifier.charAt(position);\r
+ if(b2=='1'){\r
+ row = 0;\r
+ position++;\r
+ break;\r
+ }\r
+ }\r
+ else {\r
+ break;\r
+ }\r
+ position++;\r
+ }\r
+\r
+ if(position == length) {\r
+\r
+ // We need to be able to express -1 in row => report row + 1 here\r
+ column--;\r
+ // System.err.println("ra " + identifier + " => " + row + " " + column);\r
+ return row + (((long)column)<<32);\r
+\r
+ } else {\r
+\r
+ throw new CellParseException("Cell identifier '" + identifier + "' is not a valid cell reference.");\r
+\r
+ }\r
+\r
+ }\r
+\r
+ public static Range decodeCellRelative(String identifier, int row, int column) {\r
+\r
+ int offset = Integer.valueOf(identifier.substring(1).trim());\r
+ // System.out.println("offset=" + offset);\r
+\r
+ if(identifier.startsWith("L") || identifier.startsWith("l")) {\r
+ return new Range(row, row, column-offset, column-offset);\r
+ } else if(identifier.startsWith("R") || identifier.startsWith("r")) {\r
+ return new Range(row, row, column+offset, column+offset);\r
+ } else if(identifier.startsWith("U") || identifier.startsWith("u")) {\r
+ return new Range(row-offset, row-offset, column, column);\r
+ } else if(identifier.startsWith("D") || identifier.startsWith("d")) {\r
+ return new Range(row+offset, row+offset, column, column);\r
+ } else {\r
+ throw new CellParseException("Relative cell syntax must begin with L|R|U|D.");\r
+ }\r
+\r
+ }\r
+\r
+ public static Range decodeCell(String identifier, int row, int column) {\r
+\r
+ if(identifier.startsWith("_")) {\r
+ return decodeCellRelative(identifier.substring(1), row, column);\r
+ } else {\r
+ return decodeCellAbsolute(identifier);\r
+ }\r
+\r
+ }\r
+\r
+ public static Range decodeReference(String identifier, int row, int column) {\r
+ if(!identifier.startsWith("&")) throw new CellParseException("A reference cell was expected.");\r
+ return decodeRange(identifier.substring(1), row, column);\r
+ }\r
+\r
+ public static List<Range> decodeRanges(String ranges){\r
+ String[] splitted = ranges.split(",");\r
+ List<Range> result = new ArrayList<>();\r
+ for(String split : splitted){\r
+ result.add(decodeRange(split));\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ public static int startRow(List<Range> ranges){\r
+ int s = -1;\r
+ for(Range r : ranges){\r
+ if(r.startRow<s || s==-1){\r
+ s = r.startRow;\r
+ }\r
+ }\r
+ return s;\r
+ }\r
+ \r
+ public static int startColumn(List<Range> ranges){\r
+ int s = -1;\r
+ for(Range r : ranges){\r
+ if(r.startColumn<s || s==-1){\r
+ s = r.startColumn;\r
+ }\r
+ }\r
+ return s;\r
+ }\r
+ \r
+ public static int amountOfRows(Range r){\r
+ int endRow = -2;\r
+ int startRow = -2;\r
+ if(r.isFullRows()){\r
+ return Range.MAXROWSPEC;\r
+ }\r
+ if(endRow == -2 && startRow == -2){\r
+ endRow = r.endRow;\r
+ startRow = r.startRow;\r
+ }\r
+ if(r.startRow<startRow){\r
+ startRow = r.startRow;\r
+ }\r
+ if(r.endRow>endRow){\r
+ endRow = r.endRow;\r
+ }\r
+ return endRow - startRow +1;\r
+ }\r
+ \r
+ public static int amountOfColumns(Range r){\r
+ int endColumn = -2;\r
+ int startColumn = -2;\r
+ if(r.isFullColumns()){\r
+ return Range.MAXCOLUMNSPEC;\r
+ }\r
+ if(endColumn == -2 && startColumn == -2){\r
+ endColumn = r.endColumn; \r
+ startColumn = r.startColumn;\r
+ }\r
+ if(r.startColumn<startColumn){\r
+ startColumn = r.startColumn;\r
+ }\r
+ if(r.endColumn>endColumn){\r
+ endColumn = r.endColumn;\r
+ }\r
+ return endColumn - startColumn +1;\r
+ }\r
+ \r
+ public static Range decodeRange(String rangeOrCell) {\r
+ if(rangeOrCell.isEmpty()) return fullRange();\r
+ return decodeRange(rangeOrCell, 0, 0);\r
+ }\r
+ \r
+ public static Range fullRange() {\r
+ return new Range(0, -1, 0, -1);\r
+ }\r
+\r
+ public static Range decodeRange(String rangeOrCell, int row, int column) {\r
+ \r
+ String[] parts = rangeOrCell.split(":");\r
+ if(parts.length == 1) {\r
+\r
+ return decodeCell(rangeOrCell, row, column);\r
+\r
+ } else if (parts.length == 2) {\r
+\r
+ Range from = decodeCell(parts[0].trim(), row, column);\r
+ // System.out.println("decodefrom=" + from);\r
+ Range to = decodeCell(parts[1].trim(), row, column);\r
+ // System.out.println("decodeto=" + to);\r
+ return Range.combine(from, to);\r
+\r
+ } else {\r
+\r
+ throw new CellParseException("The reference cell syntax was invalid. At most 1 occurrence of ':' is expected.");\r
+\r
+ }\r
+\r
+ }\r
+\r
+ public static Pair<String, Collection<PropertyCreationData>> parse(String text, StringCellParser[] parsers) {\r
+\r
+ try {\r
+\r
+ for(StringCellParser parser : parsers) { \r
+ Collection<PropertyCreationData> parsed = parser.parse(text);\r
+ if(parsed != null) return Pair.make(parser.getType(), parsed);\r
+ }\r
+\r
+ } catch (Throwable t) {\r
+ t.printStackTrace();\r
+ }\r
+\r
+ return null;\r
+\r
+ }\r
+\r
+ public static boolean isImmutable(Object object) {\r
+ return !(object instanceof Resource) && !(object instanceof Variable); \r
+ }\r
+\r
+ public static String getLabel(ReadGraph graph, Object object) throws DatabaseException {\r
+\r
+ if(object == null) {\r
+ return "no data";\r
+ }\r
+\r
+ if(object instanceof Resource) {\r
+ return NameUtils.getSafeName(graph, (Resource)object);\r
+ } else if (object instanceof Variable) {\r
+ try {\r
+ Object value = ((Variable)object).getValue(graph);\r
+ return value.toString();\r
+ //return toString(value);\r
+ } catch (VariableException e) {\r
+ Object value = ((Variable)object).getPropertyValue(graph, "Label"); \r
+ return value.toString();\r
+ }\r
+ } else if (object instanceof double[]) {\r
+ return object.toString();\r
+ // return toString(object); \r
+ } else {\r
+ return object.toString();\r
+ }\r
+\r
+ }\r
+\r
+ private static String toString(Object object) {\r
+ if(object instanceof double[]) {\r
+ try {\r
+ return Bindings.DOUBLE_ARRAY.toString(object);\r
+ } catch (BindingException e) {\r
+ return object.toString();\r
+ }\r
+ } else {\r
+ return object.toString();\r
+ }\r
+ }\r
+\r
+ public static String getContent(ReadGraph graph, Object object) throws DatabaseException {\r
+\r
+ if(object == null) {\r
+ return null;\r
+ }\r
+\r
+ if(object instanceof Resource) {\r
+ SerialisationSupport support = graph.getService(SerialisationSupport.class);\r
+ return support.getResourceSerializer().createRandomAccessId((Resource)object);\r
+ } else if (object instanceof Variable) {\r
+ return ((Variable)object).getURI(graph);\r
+ } else {\r
+ return "";\r
+ }\r
+\r
+ }\r
+\r
+ public static void main(String[] args) {\r
+ for(int i=0;i<16384;i++) {\r
+ String name = columnName(i);\r
+ Range r = decodeCellAbsolute(name + "1");\r
+ System.err.println(i + " " + name + " " + r);\r
+ }\r
+ }\r
+\r
+ public static String getLabel(ClientModel model, int row, int column) {\r
+ try {\r
+ String location = SpreadsheetUtils.cellName(row, column);\r
+ String label = model.getPropertyAt(location, ClientModel.LABEL);\r
+ if(label != null) return label;\r
+ Variant content = SpreadsheetUtils.getSafeClientVariant(model, location, ClientModel.CONTENT);\r
+ if(content != null) return SpreadsheetUtils.getContentString(content);\r
+ else return null;\r
+ } catch (Throwable e) {\r
+ e.printStackTrace();\r
+ return null;\r
+ }\r
+ }\r
+\r
+ public static String getContentString(Variant content) {\r
+ return content.getValue().toString();\r
+ }\r
+\r
+ public static boolean isInBounds(String base, String location, int wBounds, int hBounds) {\r
+ Range baseRange = decodeCellAbsolute(base);\r
+ Range locationRange = decodeCellAbsolute(location);\r
+ if(locationRange.startColumn < baseRange.startColumn) return false;\r
+ if(locationRange.startRow < baseRange.startRow) return false;\r
+ int wb = wBounds == -1 ? (Integer.MAX_VALUE / 3) : wBounds;\r
+ int hb = hBounds == -1 ? (Integer.MAX_VALUE / 3) : hBounds;\r
+ if(locationRange.startColumn > (baseRange.startColumn+wb-1)) return false;\r
+ if(locationRange.startRow > (baseRange.startRow+hb-1)) return false;\r
+ return true;\r
+ }\r
+\r
+ public static void schedule(CellEditor.Transaction<?> transaction, Write write) {\r
+\r
+ if(transaction == null) {\r
+\r
+ TransactionImpl impl = (TransactionImpl)startTransaction(OperationMode.OPERATION);\r
+ impl.add(write);\r
+ impl.commit();\r
+\r
+ } else {\r
+\r
+ TransactionImpl impl = (TransactionImpl)transaction;\r
+ impl.add(write);\r
+\r
+ }\r
+\r
+ }\r
+ \r
+ public static Transaction<Write> startTransaction() {\r
+ return startTransaction(OperationMode.EDIT_MODE);\r
+ }\r
+\r
+ public static Transaction<Write> startTransaction(OperationMode mode) {\r
+ return new TransactionImpl(mode);\r
+ } \r
+\r
+ static class TransactionImpl implements CellEditor.Transaction<Write> {\r
+\r
+ private ArrayList<Write> writes = new ArrayList<>();\r
+ private final OperationMode mode;\r
+ private Object context;\r
+ private List<Object> needSync;\r
+ \r
+ public TransactionImpl(OperationMode mode) {\r
+ this.mode = mode;\r
+ }\r
+\r
+ public void commit() {\r
+\r
+ Simantics.async(new WriteRequest() {\r
+\r
+ @Override\r
+ public void perform(WriteGraph graph) throws DatabaseException {\r
+ graph.markUndoPoint();\r
+ for(int i=0;i<writes.size();i++) {\r
+ Write write = writes.get(i);\r
+ try {\r
+ write.perform(graph);\r
+ } catch (DatabaseException e) {\r
+ e.printStackTrace();\r
+ Logger.defaultLogError(e);\r
+ }\r
+ // This can schedule more writes\r
+ //graph.syncRequest(write);\r
+ }\r
+ writes.clear();\r
+ }\r
+ });\r
+ }\r
+\r
+ @Override\r
+ public void add(Write write) {\r
+ writes.add(write);\r
+ }\r
+\r
+ @Override\r
+ public boolean isOperationMode() {\r
+ return mode.equals(OperationMode.OPERATION);\r
+ }\r
+\r
+ @Override\r
+ public void setContext(Object context) {\r
+ this.context = context;\r
+ }\r
+\r
+ @Override\r
+ public Object getContext() {\r
+ return context;\r
+ }\r
+\r
+ @Override\r
+ public void needSynchronization(Object object) {\r
+ if (needSync == null)\r
+ needSync = new ArrayList<>();\r
+ needSync.add(object);\r
+ }\r
+\r
+ @Override\r
+ public List<Object> needSynchronization() {\r
+ return needSync;\r
+ }\r
+ }\r
+ \r
+ public static MutableVariant createVariant() {\r
+ return new MutableVariant();\r
+ }\r
+\r
+ public static Variant getSafeClientVariant(ClientModel clientModel, String location, String property) {\r
+ try {\r
+ return clientModel.getPossiblePropertyAt(location, property);\r
+ } catch (Throwable t) {\r
+ Logger.defaultLogError(t);\r
+ return Variant.ofInstance(t.getMessage());\r
+ }\r
+ }\r
+\r
+ public static Resource createSheet(WriteGraph graph, Resource book, String name) throws DatabaseException {\r
+ \r
+ return createSheet(graph, book, name, new String[] {}, new int[] {});\r
+ \r
+ }\r
+\r
+ public static Resource createSheet(WriteGraph graph, Resource book, String name, String[] colNames, int[] colWidths) throws DatabaseException {\r
+\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ SpreadsheetResource sr = SpreadsheetResource.getInstance(graph);\r
+\r
+ Resource result = graph.newResource();\r
+ graph.claim(result, L0.InstanceOf, null, sr.Spreadsheet);\r
+\r
+ if(name == null) {\r
+ name = NameUtils.findFreshEscapedName(graph, "Sheet", book, L0.ConsistsOf);\r
+ }\r
+ graph.claimLiteral(result, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);\r
+ graph.claim(book, L0.ConsistsOf, L0.PartOf, result);\r
+\r
+// Resource newCell = graph.newResource();\r
+// graph.claim(newCell, L0.InstanceOf, null, sr.Lines);\r
+// graph.claimLiteral(newCell, L0.HasName, L0.NameOf, L0.String, "Lines", Bindings.STRING);\r
+// graph.claim(result, L0.ConsistsOf, L0.PartOf, newCell);\r
+// BTree bt = new BTree(graph, SpreadsheetUtils.SPREADSHEET_BTREE_SIZE, SR.Lines, SR.LineNode, L0.PartOf, true);\r
+ \r
+ BTree bt = new BTree(graph, SpreadsheetUtils.SPREADSHEET_BTREE_SIZE, sr.Lines, sr.LineNode, L0.PartOf, false);\r
+// BTree bt = BTreeUtils.create(graph, sr.Lines, sr.LineNode, L0.PartOf, SpreadsheetUtils.SPREADSHEET_BTREE_SIZE, false);\r
+ Resource lines = bt.rootOfBTree();\r
+ \r
+ graph.claimLiteral(lines, L0.HasName, L0.NameOf, L0.String, "Lines", Bindings.STRING);\r
+ graph.claim(result, L0.ConsistsOf, L0.PartOf, lines);\r
+ \r
+ {\r
+ Resource newCell = graph.newResource();\r
+ graph.claim(newCell, L0.InstanceOf, null, sr.Dimensions);\r
+ graph.claimLiteral(newCell, L0.HasName, L0.NameOf, L0.String, "Dimensions", Bindings.STRING);\r
+ graph.addLiteral(newCell, sr.Dimensions_fitColumns, sr.Dimensions_fitColumns_Inverse, L0.Boolean, false, Bindings.BOOLEAN);\r
+ graph.addLiteral(newCell, sr.Dimensions_fitRows, sr.Dimensions_fitRows_Inverse, L0.Boolean, false, Bindings.BOOLEAN);\r
+ graph.addLiteral(newCell, sr.Dimensions_columnCount, sr.Dimensions_columnCount_Inverse, L0.Integer, 128, Bindings.INTEGER);\r
+ graph.addLiteral(newCell, sr.Dimensions_rowCount, sr.Dimensions_rowCount_Inverse, L0.Integer, 256, Bindings.INTEGER);\r
+ graph.claim(result, L0.ConsistsOf, L0.PartOf, newCell);\r
+ }\r
+\r
+ {\r
+ Resource newCell = graph.newResource();\r
+ graph.claim(newCell, L0.InstanceOf, null, sr.Headers);\r
+ graph.claimLiteral(newCell, L0.HasName, L0.NameOf, L0.String, "Headers", Bindings.STRING);\r
+ graph.addLiteral(newCell, sr.Headers_columnLabels, sr.Headers_columnLabels_Inverse, L0.StringArray, colNames, Bindings.STRING_ARRAY);\r
+ graph.addLiteral(newCell, sr.Headers_columnWidths, sr.Headers_columnWidths_Inverse, L0.IntegerArray, colWidths, Bindings.INT_ARRAY);\r
+ graph.claim(result, L0.ConsistsOf, L0.PartOf, newCell);\r
+ }\r
+\r
+ return result;\r
+\r
+ }\r
+ \r
+\r
+ public static Variable getBookVariable(ReadGraph graph, Resource book) throws DatabaseException {\r
+ Variable variable = Variables.getVariable(graph, book);\r
+ return ProxyVariables.makeProxyVariable(graph, variable, variable);\r
+ }\r
+\r
+ public static Variable sheetRun(ReadGraph graph, Resource book, Variable context) throws DatabaseException {\r
+ Variable root = Variables.getVariable(graph, book);\r
+ return ProxyVariables.makeProxyVariable(graph, root, context);\r
+ }\r
+\r
+ private static TableCell constructCell(int row, int column, Object data) {\r
+ TableCell cell = new TableCell();\r
+ cell.row = row;\r
+ cell.column = column;\r
+ cell.text = data.toString();\r
+ return cell;\r
+ }\r
+ \r
+ public static List<TableCell> queryCells(Object data) {\r
+ ArrayList<TableCell> result = new ArrayList<TableCell>();\r
+ if(data instanceof List) {\r
+ List<?> list = (List<?>)data;\r
+ int row = 0;\r
+ for(Object o : list) {\r
+ if(o instanceof Tuple) {\r
+ Tuple t = (Tuple)o;\r
+ for(int i=0;i<t.length();i++) {\r
+ result.add(constructCell(row, i, t.get(i)));\r
+ }\r
+ } else if (o instanceof List) {\r
+ List<?> rowList = (List<?>)o;\r
+ int index = 0;\r
+ for(Object obj : rowList) {\r
+ result.add(constructCell(row, index++, obj));\r
+ }\r
+ } else {\r
+ result.add(constructCell(row, 0, o));\r
+ }\r
+ row++;\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ public static List<TableCell> organizeCells(int columns, List<String> headers_, List<TableCell> cells) throws DatabaseException {\r
+ \r
+ ArrayList<TableCell> result = new ArrayList<TableCell>();\r
+ \r
+ int w = 0; // name + fields \r
+ int h = 0; // number or rows excluding headers\r
+ \r
+ if(columns < 2) throw new DatabaseException("organizeCells: number of columns needs to be greater than 1");\r
+ \r
+ for(TableCell cell : cells) {\r
+ if((cell.column+1)>w) w = cell.column+1;\r
+ if((cell.row)>h) h = cell.row;\r
+ }\r
+ \r
+ int fields = w - 1;\r
+ \r
+ if(columns > (fields + 1)) columns = fields + 1;//throw new DatabaseException("organizeCells: number of block columns cannot be greater than the amount of columns in data");\r
+ \r
+ int fieldsPerRow = columns - 1;\r
+ \r
+ int blocks = fields / fieldsPerRow;\r
+ if(fields%fieldsPerRow > 0) blocks++;\r
+\r
+ TableCell[] names = new TableCell[h];\r
+ TableCell[] headers = new TableCell[w];\r
+ \r
+ for(TableCell cell : cells) {\r
+ \r
+ if(cell.row == 0) {\r
+ headers[cell.column] = cell;\r
+ } else if(cell.column == 0) {\r
+ names[cell.row-1] = cell;\r
+ } else {\r
+ TableCell copy = new TableCell(cell);\r
+ int block = (copy.column-1) / fieldsPerRow;\r
+ copy.row = block*(h+1) + copy.row;\r
+ copy.column = 1 + (copy.column-1) % fieldsPerRow;\r
+ result.add(copy);\r
+ }\r
+ \r
+ }\r
+ \r
+ for(int j=0;j<blocks;j++) {\r
+\r
+ int rowBase = j*(h+1);\r
+ \r
+ for(int i=0;i<h;i++) {\r
+ TableCell copy = new TableCell(names[i]);\r
+ copy.row = rowBase + copy.row;\r
+ result.add(copy);\r
+ }\r
+ \r
+ TableCell legend = new TableCell(headers[0]);\r
+ legend.row = rowBase;\r
+ result.add(legend);\r
+\r
+ for(int i=1;i<columns;i++) {\r
+\r
+ int index = (j*fieldsPerRow) + i;\r
+ if(index >= w) continue;\r
+ \r
+ TableCell header = new TableCell(headers[index]);\r
+ header.row = rowBase;\r
+ header.column = i;\r
+ result.add(header);\r
+ \r
+ }\r
+ \r
+ }\r
+ \r
+ return result;\r
+ \r
+ }\r
+ \r
+ public static List<TableCell> modifyCells1(List<TableCell> cells, Function1<TableCell, TableCell> fn) {\r
+ ArrayList<TableCell> result = new ArrayList<TableCell>();\r
+ for(TableCell cell : cells)\r
+ result.add(fn.apply(cell));\r
+ return result;\r
+ }\r
+\r
+ public static List<TableCell> modifyCells(List<TableCell> cells, List<Function1<TableCell, TableCell>> fns) {\r
+ ArrayList<TableCell> result = new ArrayList<TableCell>();\r
+ for(TableCell cell : cells) {\r
+ for(Function1<TableCell,TableCell> fn : fns)\r
+ cell = fn.apply(cell);\r
+ result.add(cell);\r
+ }\r
+ return result;\r
+ }\r
+\r
+ public static TableCell applyFont(IFont font, Function1<TableCell,Boolean> filter, TableCell cell) {\r
+ if(!filter.apply(cell)) return cell;\r
+ TableCell result = new TableCell(cell);\r
+ result.font = font;\r
+ return result;\r
+ }\r
+\r
+ public static TableCell applyAlign(int align, Function1<TableCell,Boolean> filter, TableCell cell) {\r
+ if(!filter.apply(cell)) return cell;\r
+ TableCell result = new TableCell(cell);\r
+ result.align = align;\r
+ return result;\r
+ }\r
+\r
+ public static TableCell applyForeground(IColor color, Function1<TableCell,Boolean> filter, TableCell cell) {\r
+ if(!filter.apply(cell)) return cell;\r
+ TableCell result = new TableCell(cell);\r
+ result.foreground = color;\r
+ return result;\r
+ }\r
+\r
+ public static TableCell applyBackground(IColor color,Function1<TableCell,Boolean> filter, TableCell cell) {\r
+ if(!filter.apply(cell)) return cell;\r
+ TableCell result = new TableCell(cell);\r
+ result.background = color;\r
+ return result;\r
+ }\r
+\r
+ public static IFont simpleFont(String family, String style, int height) {\r
+ return new SimpleFont(family, style, height);\r
+ }\r
+\r
+ public static IColor rgbColor(int r, int g, int b) {\r
+ return new RGBColor(r, g, b);\r
+ }\r
+\r
+ public static boolean selectRow(int row, TableCell cell) {\r
+ return cell.row == row;\r
+ }\r
+\r
+ public static boolean selectColumn(int column, TableCell cell) {\r
+ return cell.column == column;\r
+ }\r
+\r
+ public static void setSCLLine(WriteGraph graph, Resource spreadsheet, int row, String expression) throws DatabaseException {\r
+\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Resource lines = graph.syncRequest(new PossibleChild(spreadsheet, "Lines"));\r
+ BTree bt = new BTree(graph, lines);\r
+ SpreadsheetResource SR = SpreadsheetResource.getInstance(graph);\r
+ \r
+ Resource line = graph.newResource();\r
+ graph.claim(line, L0.InstanceOf, SR.Line);\r
+ graph.addLiteral(line, L0.HasName, L0.NameOf, "" + row, Bindings.STRING);\r
+ Layer0Utils.setExpression(graph, line, SR.Line_content, null, "[spreadsheetCell ]", L0.SCLValue);\r
+ bt.insertBTree(graph, Variant.ofInstance(row), line);\r
+ \r
+ }\r
+\r
+ public static String getFormattedLabel(ClientModel model, int row, int column, int formatIndex, String formatString) {\r
+ if (formatString == null)\r
+ return getLabel(model, row, column); \r
+ try {\r
+ String location = SpreadsheetUtils.cellName(row, column);\r
+ Variant content = SpreadsheetUtils.getSafeClientVariant(model, location, ClientModel.CONTENT);\r
+ if(content != null) {\r
+ \r
+ String contentString = SpreadsheetUtils.getContentString(content);\r
+ if(contentString.equals("~CIRCULAR~REF~"))\r
+ return "0";\r
+ \r
+ double value = Double.valueOf(contentString);\r
+ if (Double.isNaN(value))\r
+ return getLabel(model, row, column);\r
+ \r
+ DataFormatter formatter = new DataFormatter();\r
+ return formatter.formatRawCellContents(value, formatIndex, formatString);\r
+ }\r
+ return null;\r
+ } catch (NumberFormatException e) {\r
+ return getLabel(model, row, column);\r
+ } catch (Throwable e) {\r
+ e.printStackTrace();\r
+ return null;\r
+ }\r
+ }\r
+ \r
+}\r