From c9a552af1020b5e6d4cf0da0a00bd758de772c2a Mon Sep 17 00:00:00 2001 From: Antti Villberg Date: Wed, 4 Dec 2019 17:47:12 +0200 Subject: [PATCH] SCL API for direct access to SpreadsheetBooks gitlab #429 Change-Id: Icb5090d9110034a4c9103cc2413084b222aed20c --- .../scl/Spreadsheet/All.scl | 46 ++-------- .../spreadsheet/graph/ExcelImport.java | 8 +- .../graph/SpreadsheetGraphUtils.java | 90 ++++++++++++++++++- .../build.properties | 3 +- .../scl/Spreadsheet/Solver.scl | 55 ++++++++++++ .../src/org/simantics/spreadsheet/Range.java | 4 + .../spreadsheet/solver/BinarySearch.java | 9 ++ .../spreadsheet/solver/SpreadsheetCell.java | 25 +++++- .../spreadsheet/solver/SpreadsheetEngine.java | 14 +++ .../spreadsheet/solver/SpreadsheetLine.java | 44 +++++++++ .../spreadsheet/solver/SpreadsheetLines.java | 30 +++++++ .../synchronization/LineUpdater.java | 1 - 12 files changed, 281 insertions(+), 48 deletions(-) create mode 100644 bundles/org.simantics.spreadsheet/scl/Spreadsheet/Solver.scl create mode 100644 bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/BinarySearch.java diff --git a/bundles/org.simantics.spreadsheet.graph/scl/Spreadsheet/All.scl b/bundles/org.simantics.spreadsheet.graph/scl/Spreadsheet/All.scl index aa58a7f73..22f8043ff 100644 --- a/bundles/org.simantics.spreadsheet.graph/scl/Spreadsheet/All.scl +++ b/bundles/org.simantics.spreadsheet.graph/scl/Spreadsheet/All.scl @@ -3,43 +3,16 @@ include "Simantics/Ontologies" include "Simantics/SCL" include "Simantics/UI" include "Document/All" +include "Spreadsheet/Solver" include "File" - -effect SpreadsheetTransaction - "spreadsheetTransaction" - "org.simantics.spreadsheet.Transaction" - -importJava "org.simantics.spreadsheet.graph.ExternalRef" where - data ExternalRef - importJava "org.simantics.spreadsheet.common.TableCell" where data TableCell -importJava "java.util.function.Consumer" where - data Consumer - -importJava "org.simantics.spreadsheet.CellEditor" where - data CellEditor - startTransaction :: CellEditor -> OperationMode -> Transaction - @JavaName "edit" - editProperty_ :: CellEditor -> String -> String -> a -> Binding a -> Maybe Consumer -> () - @JavaName "edit" - editContent :: CellEditor -> String -> Variant -> Maybe Consumer -> () - @inline editProperty :: Serializable a => CellEditor -> String -> String -> a -> Maybe Consumer -> () editProperty editor location property value consumer = editProperty_ editor location property value binding consumer -importJava "org.simantics.spreadsheet.OperationMode" where - data OperationMode - OPERATION :: OperationMode - EDIT_MODE :: OperationMode - -importJava "org.simantics.spreadsheet.Transaction" where - data Transaction - commit :: Transaction -> () - importJava "org.simantics.spreadsheet.common.TreeTableCell" where data TreeTableCell @@ -58,9 +31,6 @@ importJava "org.simantics.spreadsheet.common.TreeTableCell" where treeTableCellRow :: TreeTableCell -> Integer @JavaName getColumn treeTableCellColumn :: TreeTableCell -> Integer - -importJava "org.simantics.spreadsheet.common.SpreadsheetCell" where - data SpreadsheetCell importJava "org.simantics.spreadsheet.graph.SCL" where toVariant :: a -> Variant @@ -76,12 +46,13 @@ importJava "org.simantics.spreadsheet.graph.SpreadsheetGraphUtils" where invalidateAll :: Variable -> () extRefVariable :: Variable -> Variant extRefActiveVariable :: Variable -> Variant + forRows :: Variable -> String -> Integer -> Integer -> (Variable -> ()) -> () + rowCell :: Variable -> Integer -> Maybe Variable + offsetCell :: Variable -> Integer -> Integer -> Maybe Variable cellEditor :: Resource -> CellEditor syncExec :: CellEditor -> OperationMode -> ( a) -> a cellColumn :: Variable -> Integer - -importJava "org.simantics.spreadsheet.Spreadsheets" where - cellName :: Integer -> Integer -> String + spreadsheetBook :: Variable -> SpreadsheetBook importJava "org.simantics.spreadsheet.util.SpreadsheetUtils" where createSheet :: Resource -> String -> Resource @@ -102,11 +73,10 @@ importJava "org.simantics.spreadsheet.util.SpreadsheetUtils" where @JavaName "sheetRun" bookRun :: Resource -> Variable -> Variable -sheetRunDefault :: Resource -> Variable -sheetRunDefault sheet = sheetRun sheet (resourceVariable sheet) +sheetRunDefault = bookRunDefault -importJava "org.simantics.spreadsheet.graph.SpreadsheetSessionManager" where - removeSpreadsheetSession :: Variable -> () +bookRunDefault :: Resource -> Variable +bookRunDefault book = bookRun book (resourceVariable book) importJava "org.simantics.spreadsheet.graph.ExcelImport" where importBook :: Resource -> File -> () diff --git a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/ExcelImport.java b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/ExcelImport.java index 24a0a85d0..a8bb342b3 100644 --- a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/ExcelImport.java +++ b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/ExcelImport.java @@ -224,8 +224,12 @@ public class ExcelImport { } else if(Cell.CELL_TYPE_STRING == val.getCellType()) { graph.claimLiteral(cell, SR.Cell_content, SR.Cell_content_Inverse, L0.Variant, Variant.ofInstance(val.toString()), Bindings.VARIANT); } else if(Cell.CELL_TYPE_NUMERIC == val.getCellType()) { - Double value = Double.parseDouble(val.toString()); - graph.claimLiteral(cell, SR.Cell_content, SR.Cell_content_Inverse, L0.Variant, Variant.ofInstance(value), Bindings.VARIANT); + try { + Double value = Double.parseDouble(val.toString()); + graph.claimLiteral(cell, SR.Cell_content, SR.Cell_content_Inverse, L0.Variant, Variant.ofInstance(value), Bindings.VARIANT); + } catch (Exception e) { + graph.claimLiteral(cell, SR.Cell_content, SR.Cell_content_Inverse, L0.Variant, Variant.ofInstance(val.toString()), Bindings.VARIANT); + } } else { graph.claimLiteral(cell, SR.Cell_content, SR.Cell_content_Inverse, L0.Variant, Variant.ofInstance(val.toString()), Bindings.VARIANT); System.err.println("Unprocessed cell type " + val.getCellType() + ", SheetName: " + sheetName + ", Row: " + rowN + ", Col:" + i); diff --git a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetGraphUtils.java b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetGraphUtils.java index 35a05d7aa..3938e478b 100644 --- a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetGraphUtils.java +++ b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetGraphUtils.java @@ -12,6 +12,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import javax.xml.soap.Node; + import org.simantics.Simantics; import org.simantics.databoard.Bindings; import org.simantics.databoard.binding.mutable.Variant; @@ -33,13 +35,15 @@ import org.simantics.db.exception.ServiceException; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.layer0.variable.StandardGraphChildVariable; import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.layer0.variable.VariableNode; import org.simantics.db.layer0.variable.Variables; import org.simantics.db.procedure.Listener; import org.simantics.db.service.ClusteringSupport; import org.simantics.layer0.Layer0; -import org.simantics.scl.compiler.commands.CommandSession; import org.simantics.scl.runtime.SCLContext; import org.simantics.scl.runtime.function.Function; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.tuple.Tuple; import org.simantics.scl.runtime.tuple.Tuple0; import org.simantics.scl.runtime.tuple.Tuple2; import org.simantics.simulator.toolkit.StandardRealm; @@ -242,8 +246,31 @@ public class SpreadsheetGraphUtils { } - + public static void forRows(ReadGraph graph, Variable run, String sheetName, int min, int max, Function1 fn) throws DatabaseException { + + String sessionName = run.getParent(graph).getURI(graph); + StandardRealm realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName); + SpreadsheetBook book = realm.getEngine(); + SpreadsheetEngine engine = book.getEngine(sheetName); + if(engine == null) return; + + engine.forLines(line -> { + + String path = line.getPath(); + if(path == null) return; + try { + Variable lineVariable = run.browse(graph, path); + if(lineVariable != null) + fn.apply(lineVariable); + } catch (DatabaseException e) { + // This is not reported here + } + + } , min, max); + + } + public static List possibleConfigurationCellVariables(ReadGraph graph, Variable sheet, Range range) throws DatabaseException { List rowVariables = possibleConfigurationLineVariables(graph, sheet, range); List result = new ArrayList<>(); @@ -651,4 +678,63 @@ public class SpreadsheetGraphUtils { throw new IllegalStateException("Expected StandardGraphChildVariable, got " + cell.getClass().getName()); } + private static SpreadsheetCell getCellFromVariable(Variable cell) { + StandardGraphChildVariable std = (StandardGraphChildVariable)cell; + return (SpreadsheetCell)std.node.node; + } + + private static SpreadsheetLine getLineFromVariable(Variable cell) { + StandardGraphChildVariable std = (StandardGraphChildVariable)cell; + return (SpreadsheetLine)std.node.node; + } + + public static Variable linesVariable(ReadGraph graph, Variable sheetVariable) throws DatabaseException { + while(!"Lines".equals(sheetVariable.getName(graph))) + sheetVariable = sheetVariable.getParent(graph); + return sheetVariable; + } + + public static Variable offsetCell(ReadGraph graph, Variable cellVariable, int x, int y) throws DatabaseException { + + Variable lineVariable = cellVariable.getParent(graph); + Variable offsetLine = offsetRow(graph, lineVariable, y); + if(offsetLine == null) return null; + SpreadsheetCell cell = getCellFromVariable(cellVariable); + return rowCell(graph, offsetLine, cell.column + x); + + } + + public static Variable offsetRow(ReadGraph graph, Variable lineVariable, int offset) throws DatabaseException { + + if(offset == 0) return lineVariable; + + SpreadsheetLine line = getLineFromVariable(lineVariable); + SpreadsheetLine offsetLine = line.possibleOffset(offset); + if(offsetLine == null) return null; + + Variable linesVariable = linesVariable(graph, lineVariable); + String path = offsetLine.getLinesPath(); + return linesVariable.browsePossible(graph, path); + + } + + public static Variable rowCell(ReadGraph graph, Variable lineVariable, int column) throws DatabaseException { + + SpreadsheetLine line = getLineFromVariable(lineVariable); + + return lineVariable.getPossibleChild(graph, Spreadsheets.cellName(line.row, column)); + + } + + public static SpreadsheetBook spreadsheetBook(Variable variable) { + if(variable instanceof StandardGraphChildVariable) { + VariableNode node = ((StandardGraphChildVariable)variable).node; + if(node != null) { + if(node.node instanceof SpreadsheetBook) + return (SpreadsheetBook) node.node; + } + } + return null; + } + } diff --git a/bundles/org.simantics.spreadsheet/build.properties b/bundles/org.simantics.spreadsheet/build.properties index dfa46571b..3e4e0e1f1 100644 --- a/bundles/org.simantics.spreadsheet/build.properties +++ b/bundles/org.simantics.spreadsheet/build.properties @@ -12,4 +12,5 @@ source.. = src/ output.. = bin/ bin.includes = META-INF/,\ - . + .,\ + scl/ diff --git a/bundles/org.simantics.spreadsheet/scl/Spreadsheet/Solver.scl b/bundles/org.simantics.spreadsheet/scl/Spreadsheet/Solver.scl new file mode 100644 index 000000000..629767c8b --- /dev/null +++ b/bundles/org.simantics.spreadsheet/scl/Spreadsheet/Solver.scl @@ -0,0 +1,55 @@ + +importJava "org.simantics.spreadsheet.ExternalRef" where + data ExternalRef + +importJava "org.simantics.spreadsheet.solver.SpreadsheetBook" where + data SpreadsheetBook + @JavaName "getEngine" + spreadsheetBookEngine :: SpreadsheetBook -> String -> SpreadsheetEngine + +importJava "org.simantics.spreadsheet.solver.SpreadsheetEngine" where + data SpreadsheetEngine + @JavaName "getLines" + spreadsheetEngineLines :: SpreadsheetEngine -> Integer -> Integer -> [SpreadsheetLine] + +importJava "org.simantics.spreadsheet.solver.SpreadsheetLine" where + data SpreadsheetLine + @JavaName "getRow" + spreadsheetLineRow :: SpreadsheetLine -> Integer + @JavaName "getCells" + spreadsheetLineCells :: SpreadsheetLine -> Integer -> Integer -> [SpreadsheetCell] + +importJava "org.simantics.spreadsheet.solver.SpreadsheetCell" where + data SpreadsheetCell + @JavaName "getColumn" + spreadsheetCellColumn :: SpreadsheetCell -> Integer + @JavaName "getContentVariant" + spreadsheetCellContentVariant :: SpreadsheetCell -> SpreadsheetBook -> Maybe Variant + +importJava "java.util.function.Consumer" where + data Consumer + +importJava "org.simantics.spreadsheet.Spreadsheets" where + cellName :: Integer -> Integer -> String + +importJava "org.simantics.spreadsheet.OperationMode" where + data OperationMode + OPERATION :: OperationMode + EDIT_MODE :: OperationMode + +importJava "org.simantics.spreadsheet.Transaction" where + data Transaction + commit :: Transaction -> () + +effect SpreadsheetTransaction + "spreadsheetTransaction" + "org.simantics.spreadsheet.Transaction" + +importJava "org.simantics.spreadsheet.CellEditor" where + data CellEditor + startTransaction :: CellEditor -> OperationMode -> Transaction + @JavaName "edit" + editProperty_ :: CellEditor -> String -> String -> a -> Binding a -> Maybe Consumer -> () + @JavaName "edit" + editContent :: CellEditor -> String -> Variant -> Maybe Consumer -> () + diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/Range.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/Range.java index b4a31c316..5ac98e084 100644 --- a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/Range.java +++ b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/Range.java @@ -39,6 +39,10 @@ public class Range { this.startColumn = copy.startColumn; this.endColumn = copy.endColumn; } + + public static Range parse(String identifier) { + return Spreadsheets.decodeCellAbsolute(identifier); + } public static Range combine(Range from, Range to) { return new Range(from.startRow, to.endRow, from.startColumn, to.endColumn); diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/BinarySearch.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/BinarySearch.java new file mode 100644 index 000000000..e005cab61 --- /dev/null +++ b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/BinarySearch.java @@ -0,0 +1,9 @@ +package org.simantics.spreadsheet.solver; + +public class BinarySearch { + public int column; + BinarySearch() {} + BinarySearch(int column) { + this.column = column; + } +} diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetCell.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetCell.java index 5b732cf86..71566482f 100644 --- a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetCell.java +++ b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetCell.java @@ -17,7 +17,7 @@ import org.simantics.spreadsheet.solver.formula.SpreadsheetEvaluationEnvironment import org.simantics.spreadsheet.solver.formula.parser.ast.AstValue; @SuppressWarnings("rawtypes") -public class SpreadsheetCell implements SpreadsheetElement, SheetNode { +public class SpreadsheetCell extends BinarySearch implements SpreadsheetElement, SheetNode { private static final long serialVersionUID = 6616793596542239339L; @@ -33,15 +33,14 @@ public class SpreadsheetCell implements SpreadsheetElement, SheetNode { private int iterations = 0; final private SpreadsheetLine line; - final private int column; int style; - private Object content; + Object content; final private Map properties; public SpreadsheetCell(SpreadsheetLine line, int column) { + super(column); this.properties = createProperties(); this.line = line; - this.column = column; } //All SpreadsheetCells have these properties - create them when object is created @@ -219,6 +218,24 @@ public class SpreadsheetCell implements SpreadsheetElement, SheetNode { public Object getContent() { return content; } + + public Variant getContentVariant(SpreadsheetBook book) { + + try { + Object content = evaluate(SpreadsheetEvaluationEnvironment.getInstance(book)); + if(content == null) return Variant.ofInstance(""); + if(content instanceof Variant) return (Variant)content; + if(content instanceof ExternalRefData) return ((ExternalRefData)content).getContent(); + else return Variant.ofInstance(content); + } catch (Throwable t) { + t.printStackTrace(); + return Variant.ofInstance(t.toString()); + } + } + + public SpreadsheetLine getLine() { + return line; + } public static SpreadsheetCell empty(SpreadsheetLine line, int column) { SpreadsheetCell cell = new SpreadsheetCell(line, column); diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetEngine.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetEngine.java index 9ccbc6d1e..a562b9d62 100644 --- a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetEngine.java +++ b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetEngine.java @@ -1,10 +1,12 @@ package org.simantics.spreadsheet.solver; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Consumer; import org.simantics.spreadsheet.Range; import org.simantics.spreadsheet.SpreadsheetVisitor; @@ -96,6 +98,18 @@ public class SpreadsheetEngine implements SpreadsheetElement, SheetNode { return root.getLine(row); } + public void forLines(Consumer consumer, int min, int max) { + assert(lines.nodes.size() == 1); + SpreadsheetLines root = lines.nodes.values().iterator().next(); + root.forLines(consumer, min, max); + } + + public List getLines(int min, int max) { + ArrayList result = new ArrayList<>(); + forLines(line -> result.add(line), min, max); + return result; + } + @Override public void accept(SpreadsheetVisitor v) { v.visit(this); diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetLine.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetLine.java index d11fdc6d2..43df74c10 100644 --- a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetLine.java +++ b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetLine.java @@ -1,11 +1,16 @@ package org.simantics.spreadsheet.solver; +import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Consumer; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.tuple.Tuple; import org.simantics.spreadsheet.Range; import org.simantics.spreadsheet.SpreadsheetVisitor; import org.simantics.spreadsheet.Spreadsheets; @@ -36,6 +41,45 @@ public class SpreadsheetLine implements SpreadsheetElement() { + @Override + public int compare(BinarySearch bs1, BinarySearch bs2) { + return Integer.compare(bs1.column, bs2.column); + } + }); + if(index >= 0) + return cells.get(index); + else + return null; + } + + public String getLinesPath() { + return "/" + ((SpreadsheetLines)parent).getLinesPath() + "/" + getName(); + } + + public void forCells(Consumer consumer, int min, int max) { + for(int i=min;i getCells(int min, int max) { + ArrayList result = new ArrayList<>(); + forCells(cell -> result.add(cell), min, max); + return result; + } @Override public String getName() { diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetLines.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetLines.java index e53d7cb61..b42e722df 100644 --- a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetLines.java +++ b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetLines.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Optional; +import java.util.function.Consumer; import org.simantics.spreadsheet.SpreadsheetVisitor; import org.simantics.spreadsheet.Spreadsheets; @@ -140,6 +141,35 @@ public class SpreadsheetLines implements SpreadsheetElement consumer, int min, int max) { + + int i=1; + int n = (keys.length - 1) / 2; + + // Smaller keys + while(i <= n && min > getKey(i-1)) i++; + + while(i <= n && max > getKey(i-1)) { + + int nodeName = getChild(i-1); + + SpreadsheetLines node = nodes.get(nodeName); + if(node == null) { + consumer.accept(lines.get(-getKey(i-1))); + } else { + node.forLines(consumer, min, max); + } + + i++; + + } + + } + public int getMaxRow() { // if keys == null then this is the root of BTree which has only one child if (keys == null) { diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/synchronization/LineUpdater.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/synchronization/LineUpdater.java index 95c601b50..d752479df 100644 --- a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/synchronization/LineUpdater.java +++ b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/synchronization/LineUpdater.java @@ -23,7 +23,6 @@ public class LineUpdater extends ModuleUpdaterBase { @Override public void apply(ModuleUpdateContext context, boolean isCreating, Map propertyMap, Map> connectionMap, Variant value) { -// System.err.println("LineUpdater.apply " + value); LineCommandBuilder builder = context.getConcreteCommand(); try { LineContentBean valuee = (LineContentBean) value.getValue(LineContentBean.BINDING); -- 2.43.2