From: lempinen Date: Mon, 15 Oct 2012 12:31:49 +0000 (+0000) Subject: Better issues. Added new issue types and remove issue sources from module types.... X-Git-Tag: simantics-1.10.1~124 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=b88ba518c1980045e8774eb29482d0723dcece1c;p=simantics%2Fsysdyn.git Better issues. Added new issue types and remove issue sources from module types. (refs #3017) git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@26014 ac1ea38d-2e2b-0410-8846-a27921b304fc --- diff --git a/org.simantics.sysdyn.ontology/graph.tg b/org.simantics.sysdyn.ontology/graph.tg index 0475c6b5..6e0ebb77 100644 Binary files a/org.simantics.sysdyn.ontology/graph.tg and b/org.simantics.sysdyn.ontology/graph.tg differ diff --git a/org.simantics.sysdyn.ontology/graph/Validation.pgraph b/org.simantics.sysdyn.ontology/graph/Validation.pgraph index 363c9d29..2932a309 100644 --- a/org.simantics.sysdyn.ontology/graph/Validation.pgraph +++ b/org.simantics.sysdyn.ontology/graph/Validation.pgraph @@ -5,8 +5,9 @@ SYSDYN = VALIDATIONS = SYSDYN.Validations : L0.Library -SYSDYN.SysdynIssue -- VALIDATIONS.Issue.stringContexts --> L0.List links = new ArrayList(); diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/ExpressionField.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/ExpressionField.java index 39e7381d..24c02b7e 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/ExpressionField.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/ExpressionField.java @@ -15,7 +15,6 @@ import java.util.List; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; -import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.PaintManager; @@ -36,13 +35,13 @@ import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.VerifyEvent; import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Table; import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess; -import org.eclipse.swt.graphics.Point; -import org.simantics.sysdyn.expressionParser.Token; +import org.simantics.sysdyn.ui.utils.SyntaxError; /** * Field for displaying a part of an expression. Expression field uses SourceViewer @@ -62,7 +61,8 @@ public class ExpressionField extends Composite { public static final String MISSING_LINK = "MissingLink"; public static final String NO_SUCH_VARIABLE = "NoSuchVariable"; public static final String SYNTAX_ERROR = "SyntaxError"; - + public static final String SYNTAX_WARNING = "SyntaxWarning"; + String oldExpression; ColorManager cManager = new ColorManager(); @@ -112,6 +112,8 @@ public class ExpressionField extends Composite { painter.setAnnotationTypeColor(NO_SUCH_VARIABLE, new Color(this.getDisplay(), 255,0,0)); painter.addAnnotationType(SYNTAX_ERROR); painter.setAnnotationTypeColor(SYNTAX_ERROR, new Color(this.getDisplay(), 255,0,0)); + painter.addAnnotationType(SYNTAX_WARNING); + painter.setAnnotationTypeColor(SYNTAX_WARNING, new Color(this.getDisplay(), 255,215,0)); _sourceViewer.setDocument(_document, _annotationModel); @@ -221,59 +223,16 @@ public class ExpressionField extends Composite { } } - /** - * Sets syntax error for the given token - * @param token Token with syntax error - * @param message Message to be displayed in tool tips - */ - public void setSyntaxError(Token token, String message){ - setSyntaxError(token.image, message, token.beginLine, token.beginColumn, token.endLine, token.endColumn); - } - - /** - * Sets syntax error for the given token - * @param token Token with syntax error - * @param message Message to be displayed in tool tips - */ - public void setSyntaxError(org.simantics.sysdyn.tableParser.Token token, String message){ - setSyntaxError(token.image, message, token.beginLine, token.beginColumn, token.endLine, token.endColumn); - } - - /** - * Sets syntax error to given location - * @param image Token image - * @param message Message to be displayed in tool tips - * @param beginLine Begin line - * @param beginColumn Begin column - * @param endLine End line - * @param endColumn End column - */ - public void setSyntaxError(String image, String message, int beginLine, int beginColumn, int endLine, int endColumn) { - int start = 0; - int offset = this._document.getLength(); - if(image != null && this._document.getLength() > 0) { - try { - start = this._document.getLineOffset(beginLine - 1) + beginColumn - 1; - offset = this._document.getLineOffset(endLine - 1) + endColumn - start; - } catch (BadLocationException e) { - e.printStackTrace(); - } - } - setSyntaxError(start, offset, SYNTAX_ERROR, message == null ? "Syntax Error" : message); - } /** - * Sets syntax error to given start and offset - * @param start Start location - * @param offset Offset - * @param type Error type (SYNTAX_ERROR, MISSING_LINK, NO_SUCH_VARIABLE) - * @param text Message to be displayedin tool tips + * Sets a syntax error annoattion to the expression field + * @param syntaxError */ - public void setSyntaxError(int start, int offset, String type, String text) { + public void setSyntaxError(SyntaxError syntaxError) { Annotation annotation = new Annotation(false); - annotation.setType(type); - annotation.setText(text); - Position p = new Position(start, offset); + annotation.setType(syntaxError.getType()); + annotation.setText(syntaxError.getMessage()); + Position p = new Position(syntaxError.getStart(_document), syntaxError.getOffset(_document)); _annotationModel.addAnnotation(annotation, p); } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/WithLookupExpression.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/WithLookupExpression.java index 5d2fa12e..8da88f5d 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/WithLookupExpression.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/WithLookupExpression.java @@ -64,6 +64,7 @@ import org.simantics.sysdyn.SysdynResource; import org.simantics.sysdyn.tableParser.ParseException; import org.simantics.sysdyn.tableParser.TableParser; import org.simantics.sysdyn.tableParser.Token; +import org.simantics.sysdyn.ui.utils.SyntaxError; import org.simantics.ui.SimanticsUI; public class WithLookupExpression implements IExpression { @@ -392,7 +393,7 @@ public class WithLookupExpression implements IExpression { Double.parseDouble(yTokens.get(i).image))); } } catch (ParseException e1) { - this.lookup.setSyntaxError(e1.currentToken, "Syntax Error"); + this.lookup.setSyntaxError(new SyntaxError(e1.currentToken, "Syntax Error")); System.out.println("MESSAGE: " + e1.getMessage()); return; } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/functions/FunctionCodeWidget.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/functions/FunctionCodeWidget.java index 8fd7bdb8..2d0cb58d 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/functions/FunctionCodeWidget.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/functions/FunctionCodeWidget.java @@ -43,6 +43,7 @@ import org.simantics.sysdyn.modelParser.ParseException; import org.simantics.sysdyn.modelParser.Token; import org.simantics.sysdyn.modelParser.TokenMgrError; import org.simantics.sysdyn.ui.properties.widgets.expressions.ExpressionField; +import org.simantics.sysdyn.ui.utils.SyntaxError; import org.simantics.ui.SimanticsUI; import org.simantics.ui.utils.AdaptionUtils; @@ -164,7 +165,7 @@ public class FunctionCodeWidget implements Widget { modelParser.parse_composition(); } catch (ParseException e1) { Token token = e1.currentToken; - modelicaCode.setSyntaxError(token.image, "Syntax error", token.beginLine, token.beginColumn, token.endLine, token.endColumn); + modelicaCode.setSyntaxError(new SyntaxError(token.image, "Syntax error", token.beginLine, token.beginColumn, token.endLine, token.endColumn)); } catch (TokenMgrError err) { String message = err.getMessage(); String line = message.substring(0, message.indexOf(",")); @@ -175,7 +176,7 @@ public class FunctionCodeWidget implements Widget { Integer endLine = Integer.parseInt(line); Integer endColumn = Integer.parseInt(column); Token token = modelParser.token; - modelicaCode.setSyntaxError(token.image, "Syntax error", token.endLine, token.endColumn, endLine, endColumn); + modelicaCode.setSyntaxError(new SyntaxError(token.image, "Syntax error", token.endLine, token.endColumn, endLine, endColumn)); } catch (NumberFormatException e) { } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ArrayVariableUtils.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ArrayVariableUtils.java index 574f71b8..88cc7229 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ArrayVariableUtils.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ArrayVariableUtils.java @@ -12,102 +12,143 @@ import org.simantics.sysdyn.representation.Enumeration; import org.simantics.sysdyn.representation.EnumerationIndex; import org.simantics.sysdyn.representation.IElement; import org.simantics.sysdyn.representation.Variable; +import org.simantics.sysdyn.ui.properties.widgets.expressions.ExpressionField; public class ArrayVariableUtils { - /** - * Checks if the given range elements can be applied to the given variable. - * - * @param graph ReadGraph - * @param variable Resource of the variable - * @param range Range elements in the correct order. Elements are separated in range definition by ',' - * @return true if range is valid, false if not - * @throws DatabaseException - */ - public static Map isRangeValid(ReadGraph graph, Variable variable, String[] elements) throws DatabaseException { - if(variable == null) - return null; - Map result = new HashMap(); - // Not an array variable - if(variable.getArrayIndexes() == null || - variable.getArrayIndexes().getEnumerations() == null || - variable.getArrayIndexes().getEnumerations().size() == 0) { - for(int i = 0; i < elements.length ; i++) - result.put(i, "Variable is not an array variable"); - return result; - } - ArrayList enumerations = variable.getArrayIndexes().getEnumerations(); - // Too many elements - if(elements.length > enumerations.size()) { - result.put( enumerations.size(), "Too many elements"); - } else if(elements.length < enumerations.size()) { - result.put( elements.length > 0 ? elements.length - 1 : 0, "Too few elements"); - } - - - for(int i = 0; i < elements.length && i < enumerations.size(); i++) { - if(elements[i].trim().equals(":")) - continue; - if(elements[i].indexOf(":") != elements[i].lastIndexOf(":")) { - result.put( i, "Too many ':' elements"); - continue; - } + /** + * Checks if the given range elements can be applied to the given variable. + * + * @param graph ReadGraph + * @param variable Resource of the variable + * @param range Range elements in the correct order. Elements are separated in range definition by ',' + * @return true if range is valid, false if not + * @throws DatabaseException + */ + public static Map isRangeValid(ReadGraph graph, Variable variable, String[] elements) throws DatabaseException { + SyntaxError error; + if(variable == null) + return null; + Map result = new HashMap(); + // Not an array variable + if(variable.getArrayIndexes() == null || + variable.getArrayIndexes().getEnumerations() == null || + variable.getArrayIndexes().getEnumerations().size() == 0) { + for(int i = 0; i < elements.length ; i++) { + error = new SyntaxError(); + error.setMessage("Variable is not an array variable"); + error.setType(ExpressionField.SYNTAX_ERROR); + result.put(i, error); + } - String[] rangeComponents = elements[i].split(":"); - if(rangeComponents.length > 2){ - result.put( i, "Too many ':' elements"); - continue; - } - // Single range component, equals to the enumeration at that index - if(rangeComponents.length == 1 && rangeComponents[0].trim().equals(enumerations.get(i).getName())) - continue; - // one or two range components, they all equal to individual indexes in the enumeration - for(String r : rangeComponents) { - r = r.trim(); - boolean componentIsValid = false; - for(EnumerationIndex ei : enumerations.get(i).getEnumerationIndexes()) { - if(ei.getName().equals(r)) { - componentIsValid = true; - break; - } - } - if(!componentIsValid) - result.put( i, "Invalid range"); - } - } - if(result.isEmpty()) - return null; - else - return result; - } + return result; + } + ArrayList enumerations = variable.getArrayIndexes().getEnumerations(); + // Too many elements + if(elements.length > enumerations.size()) { + error = new SyntaxError(); + error.setMessage( "Too many elements"); + error.setType(ExpressionField.SYNTAX_ERROR); + result.put(enumerations.size(), error); + } else if(elements.length < enumerations.size()) { + error = new SyntaxError(); + error.setMessage("Too few elements"); + error.setType(ExpressionField.SYNTAX_ERROR); + result.put(elements.length > 0 ? elements.length - 1 : 0, error); + } - /** - * Checks if the given range can be applied to the given variable. - * - * @param graph ReadGraph - * @param variable Resource of the variable - * @param range Range WITHOUT [ and ] brackets - * @return true if range is valid, false if not - * @throws DatabaseException - */ - public static boolean isRangeValid(ReadGraph graph, Resource variable, String range) throws DatabaseException { - if(variable == null) - return true; - String[] elements = range.split(","); - SysdynModel model = ModelUtils.getModel(graph, variable); - if(model == null) - return false; - IElement e = model.getElement(variable); - if(e != null && e instanceof Variable) { - Variable v = (Variable) e; - Map result = isRangeValid(graph, v, elements); - if(result == null) - return true; - else - return false; - } else { - return false; - } - } + + for(int i = 0; i < elements.length && i < enumerations.size(); i++) { + if(elements[i].trim().equals(":")) + continue; + if(elements[i].indexOf(":") != elements[i].lastIndexOf(":")) { + error = new SyntaxError(); + error.setMessage( "Too many ':' elements"); + error.setType(ExpressionField.SYNTAX_ERROR); + result.put(i, error); + continue; + } + + String[] rangeComponents = elements[i].split(":"); + if(rangeComponents.length > 2){ + error = new SyntaxError(); + error.setMessage( "Too many ':' elements"); + error.setType(ExpressionField.SYNTAX_ERROR); + result.put(i, error); + continue; + } + // Single range component, equals to the enumeration at that index + if(rangeComponents.length == 1 && rangeComponents[0].trim().equals(enumerations.get(i).getName())) + continue; + // one or two range components, they all equal to individual indexes in the enumeration + for(String r : rangeComponents) { + r = r.trim(); + boolean componentIsValid = false; + for(EnumerationIndex ei : enumerations.get(i).getEnumerationIndexes()) { + if(ei.getName().equals(r)) { + componentIsValid = true; + break; + } + } + if(!componentIsValid) { + // Check if the range is an integer that is between 0 and enumeration indexes size + try { + int index = Integer.parseInt(r); + int min = 1; + int max = enumerations.get(i).getEnumerationIndexes().size(); + if(index >= min && index <= max) { + componentIsValid = true; + error = new SyntaxError(); + error.setMessage("Using numbers as array indexes is not encouraged"); + error.setType(ExpressionField.SYNTAX_WARNING); + result.put(i, error); + } else { + error = new SyntaxError(); + error.setMessage("Invalid array index " + index + ". Numbered index must be between " + min + " and " + max + " unless the enumeration is overridden. In that case, ignore this warning."); + error.setType(ExpressionField.SYNTAX_ERROR); + result.put(i, error); + } + } catch (NumberFormatException e) { + error = new SyntaxError(); + error.setMessage("Invalid range"); + error.setType(ExpressionField.SYNTAX_ERROR); + result.put(i, error); + } + } + } + } + if(result.isEmpty()) + return null; + else + return result; + } + + /** + * Checks if the given range can be applied to the given variable. + * + * @param graph ReadGraph + * @param variable Resource of the variable + * @param range Range WITHOUT [ and ] brackets + * @return true if range is valid, false if not + * @throws DatabaseException + */ + public static boolean isRangeValid(ReadGraph graph, Resource variable, String range) throws DatabaseException { + if(variable == null) + return true; + String[] elements = range.split(","); + SysdynModel model = ModelUtils.getModel(graph, variable); + if(model == null) + return false; + IElement e = model.getElement(variable); + if(e != null && e instanceof Variable) { + Variable v = (Variable) e; + if(isRangeValid(graph, v, elements) == null) + return true; + else + return false; + } else { + return false; + } + } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ExpressionUtils.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ExpressionUtils.java index c9419675..758b90f8 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ExpressionUtils.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ExpressionUtils.java @@ -13,6 +13,7 @@ package org.simantics.sysdyn.ui.utils; import java.io.StringReader; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -141,27 +142,28 @@ public class ExpressionUtils { functionReferences.put(ef, parser.getFunctionCallReferences()); } catch (ParseException e1) { - ef.setSyntaxError(e1.currentToken, "Syntax Error"); + ef.setSyntaxError(new SyntaxError(e1.currentToken, "Syntax Error")); } catch (TokenMgrError err) { - ef.setSyntaxError(0, textString.length(), ExpressionField.SYNTAX_ERROR, "Expression contains unsupported characters"); + ef.setSyntaxError(new SyntaxError(0, textString.length(), ExpressionField.SYNTAX_ERROR, "Expression contains unsupported characters")); } } + // Get model configuration + SysdynModelManager sdm = SysdynModelManager.getInstance(SimanticsUI.getSession()); + SysdynModel model = sdm.getModel(configuration); + try { + model.update(); + } catch (DatabaseException e1) { + e1.printStackTrace(); + } + Configuration conf = model.getConfiguration(); + + // Check variable references final HashMap modelVariables = new HashMap(); HashSet ignoreVariables = new HashSet(); - if(!variables.isEmpty() || !functionReferences.isEmpty()) { Set noSuchVariables = new HashSet(); - SysdynModelManager sdm = SysdynModelManager.getInstance(SimanticsUI.getSession()); - SysdynModel model = sdm.getModel(configuration); - try { - model.update(); - } catch (DatabaseException e1) { - e1.printStackTrace(); - } - - Configuration conf = model.getConfiguration(); ArrayList elements = conf.getElements(); for(IElement e : elements) { if(e instanceof Variable) { @@ -180,71 +182,26 @@ public class ExpressionUtils { // Examine sheets for(ExpressionField ef : functionReferences.keySet()) { for(String key : functionReferences.get(ef).keySet()) { - String[] parts = key.split("\\."); - Object current = conf; - for(int i = 0; i < parts.length && current != null; i++) { - current = getElement(current, parts[i]); - } - if(current == null && conf.getModuleType() != null) { - // Sheets are currently located in the model root. Try to find the sheet. - current = conf.getModuleType().getParent(); // Get module type parent (should be a model) - if(current instanceof Model) - current = getElement(((Model)current).getModelConfiguration(), parts[0]); // Try to get the sheet - } - - if(current != null && current instanceof Sheet) { - Sheet sheet = (Sheet) current; - String e = ef.getExpression(); - int start = 0, end = 0, call = 0; - String cellOrRange = null; - while((call = e.indexOf(key, end)) >= 0) { - start = e.indexOf("(", call) +1; - end = e.indexOf(")", start); - if(start < 0 || end < 0 || end < start) { - break; - } - Pattern p = Pattern.compile("[-\\+\\*\\/\\(\\)\\{\\}\\[\\],\\.\\t\\n\\r\\f]"); - cellOrRange = e.substring(start, end); - Matcher m = p.matcher(cellOrRange); - if (m.find() || cellOrRange.split(":").length > 2) { - ef.setSyntaxError(start, end - start, ExpressionField.SYNTAX_ERROR, "Not a valid cell or range"); - } - } - - List tokens = functionReferences.get(ef).get(key); - for(Token cell : tokens) { - List refs = references.get(ef).get(cell.image); - if(refs != null) - refs.remove(cell); - if(!sheet.getCells().containsKey(cell.image)) - ef.setSyntaxError(cell.image, "Invalid cell", cell.beginLine, cell.beginColumn, cell.endLine, cell.endColumn); - } - + List errors = examineSheetReferences(conf, key, functionReferences.get(ef).get(key), ef.getExpression(), references.get(ef)); + if(errors != null) { + for(SyntaxError error : errors) + ef.setSyntaxError(error); } } } + // Examine variable references for(String v : variables) { - - if(modelVariables.get(v) instanceof Enumeration || modelVariables.get(v) instanceof Sheet) { - ignoreVariables.add(v); - } - - // Reference to some other module, spreadsheet or enumeration - if(v.contains(".")) { - String[] parts = v.split("\\."); - Object parent = conf; - for(int i = 0; i < parts.length && parent != null; i++) { - parent = getElement(parent, parts[i]); - } - if(parent == null) { + ReferenceOption option = getReferenceOption(conf, v); + switch(option) { + case DOES_NOT_EXIST: noSuchVariables.add(v); - } else { + break; + case CANNOT_BE_CONNECTED: ignoreVariables.add(v); - } - } else if(!modelVariables.keySet().contains(v)) { - noSuchVariables.add(v); + break; + case CAN_BE_CONNECTED: } } @@ -289,119 +246,252 @@ public class ExpressionUtils { } + for(final ExpressionField ef : ranges.keySet()) { + List errors = new ArrayList(); + // RANGES + errors.addAll(examineArrayRanges(conf, ranges.get(ef), forIndices.get(ef))); + + // ENUMERATION REFERENCES IN FOR-LOOPS + errors.addAll(examineEnumerationReferences(conf, enumerationReferences.get(ef))); - HashMap> errors = new HashMap>(); - HashMap result = null; + for(SyntaxError error : errors) + ef.setSyntaxError(error); + } + } + + + static public List examineArrayRanges( + final Configuration configuration, + final HashMap>> ranges, + final HashMap> forIndices) { + + List result = Collections.emptyList(); + try { + result = SimanticsUI.getSession().syncRequest(new Read>() { - for(final ExpressionField ef : ranges.keySet()) { + @Override + public List perform(ReadGraph graph) throws DatabaseException { + return examineArrayRanges(graph, configuration, ranges, forIndices); + } + }); + } catch (DatabaseException e) { + e.printStackTrace(); + } + return result; + } - // RANGES - try { - result = SimanticsUI.getSession().syncRequest(new Read>() { - - @Override - public HashMap perform(ReadGraph graph) throws DatabaseException { - HashMap result = new HashMap(); - for(String s : ranges.get(ef).keySet()) { - if(ranges.get(ef).containsKey(s)) { - for(List l : ranges.get(ef).get(s)) { - String[] ss = new String[l.size()]; - for(int i = 0; i < l.size(); i++) { - ss[i] = l.get(i).image; - } - Map invalidRanges = ArrayVariableUtils.isRangeValid(graph, modelVariables.get(s), ss); - if(invalidRanges != null && !invalidRanges.isEmpty()) { - for(Integer i : invalidRanges.keySet()) { - result.put(l.get(i), invalidRanges.get(i)); - } - } - } + static public List examineEnumerationReferences(Configuration configuration, HashMap> enumRefList) { + ArrayList result = new ArrayList(); + for(String enumeration : enumRefList.keySet()) { + for(Token et : enumRefList.get(enumeration)) { + Object o = getElement(configuration, enumeration); + if(o != null && o instanceof Enumeration) { + boolean isFound = false; + Enumeration e = (Enumeration)o; + + if(enumeration.equals(et.image) || + "size".equals(et.image) || + "elements".equals(et.image)){ + // The full enumeration + isFound = true; + } else { + for(EnumerationIndex ei : e.getEnumerationIndexes()) { + if(ei.getName().equals(et.image)) { + isFound = true; + break; } - } - return result; + } } - }); - } catch (DatabaseException e) { - e.printStackTrace(); - } - // FOR-INDICES - - HashMap> indexList = forIndices.get(ef); - for(Token t : indexList.keySet()) { - boolean isFound = false; - if(indexList.get(t) != null) { - for(Token rt : indexList.get(t)) { - if(rt.image.equals(t.image)) { - isFound = true; - // remove range token from invalid ranges - result.remove(rt); - break; + if(!isFound) { + StringBuilder sb = new StringBuilder(); + sb.append("Enumeration "); + sb.append(enumeration); + sb.append(" has no such index.\nAvailable indexes are: "); + Iterator iterator = e.getEnumerationIndexes().iterator(); + while(iterator.hasNext()) { + sb.append(iterator.next().getName()); + if(iterator.hasNext()) + sb.append(", "); } + result.add(new SyntaxError(et, sb.toString())); } - } - if(!isFound) { - result.put(t, "Invalid index"); + + + } else { + result.add(new SyntaxError(et, "No such enumeration (" + enumeration + ")")); } } + } + return result; + } - // ENUMERATION REFERENCES IN FOR-LOOPS - HashMap> enumRefList = enumerationReferences.get(ef); - for(String enumeration : enumRefList.keySet()) { - for(Token et : enumRefList.get(enumeration)) { - Variable v = modelVariables.get(enumeration); - if(v != null && v instanceof Enumeration) { - boolean isFound = false; - Enumeration e = (Enumeration)v; - - if(enumeration.equals(et.image) || - "size".equals(et.image) || - "elements".equals(et.image)){ - // The full enumeration - isFound = true; - } else { - for(EnumerationIndex ei : e.getEnumerationIndexes()) { - if(ei.getName().equals(et.image)) { - isFound = true; - break; - } - } - } + /** + * + * @param graph + * @param configuration + * @param ranges + * @param forIndices + * @return + * @throws DatabaseException + */ + static public List examineArrayRanges( + ReadGraph graph, + Configuration configuration, + HashMap>> ranges, + HashMap> forIndices) throws DatabaseException { + HashMap errors = new HashMap(); + for(String name : ranges.keySet()) { + if(ranges.get(name) != null) { + for(List l : ranges.get(name)) { + String[] rangeReferences = new String[l.size()]; + for(int i = 0; i < l.size(); i++) { + rangeReferences[i] = l.get(i).image; + } - if(!isFound) { - StringBuilder sb = new StringBuilder(); - sb.append("Enumeration "); - sb.append(enumeration); - sb.append(" has no such index.\nAvailable indexes are: "); - Iterator iterator = e.getEnumerationIndexes().iterator(); - while(iterator.hasNext()) { - sb.append(iterator.next().getName()); - if(iterator.hasNext()) - sb.append(", "); + Object o = getElement(configuration, name); + if(o != null && o instanceof Variable) { + Map invalidRanges = ArrayVariableUtils.isRangeValid(graph, (Variable)o, rangeReferences); + if(invalidRanges != null && !invalidRanges.isEmpty()) { + for(Integer i : invalidRanges.keySet()) { + SyntaxError error = invalidRanges.get(i); + error.setToken(l.get(i)); + errors.put(l.get(i), error); } - result.put(et, sb.toString()); } - - - } else { - result.put(et, "No such enumeration (" + enumeration + ")"); } } } - - errors.put(ef, result); + } - } + // FOR-INDICES - for(ExpressionField ef : ranges.keySet()) { - HashMap tokens = errors.get(ef); - if(tokens == null || tokens.isEmpty()) continue; - for(Token t : tokens.keySet()) { - ef.setSyntaxError(t, tokens.get(t)); + HashSet removes = new HashSet(); + for(Token t : forIndices.keySet()) { + boolean isFound = false; + for(Token rt : errors.keySet()) { + if(rt.image.equals(t.image)) { + isFound = true; + // remove range token from invalid ranges + removes.add(rt); + } } + if(!isFound) { + SyntaxError error = new SyntaxError(t, "Invalid index"); + errors.put(t, error); + } + } + + for(Token t : removes) + errors.remove(t); + + return new ArrayList(errors.values()); + } + + + /** + * Examine if a given functionKey is a sheet reference and whether all the tokens in the function ( Sheet1(token1, token2) ) + * are valid. + * + * @param configuration Configuration where the function is called + * @param functionKey Function name + * @param functionTokens Function parameters (sheet reference, either a cell or cell range) + * @param expression The whole expression where the function reference is + * @param expressionReferences All variable references, including function parameters + * @return A list of possible errors + */ + static public List examineSheetReferences( + Configuration configuration, + String functionKey, + List functionTokens, + String expression, + HashMap> expressionReferences) { + + List result = new ArrayList(); + + String[] parts = functionKey.split("\\."); + Object current = configuration; + for(int i = 0; i < parts.length && current != null; i++) { + current = getElement(current, parts[i]); } + + if(current == null && configuration.getModuleType() != null) { + // Sheets are currently located in the model root. Try to find the sheet. + current = configuration.getModuleType().getParent(); // Get module type parent (should be a model) + if(current instanceof Model) + current = getElement(((Model)current).getModelConfiguration(), parts[0]); // Try to get the sheet + } + + if(current != null && current instanceof Sheet) { + Sheet sheet = (Sheet) current; + int start = 0, end = 0, call = 0; + String cellOrRange = null; + while((call = expression.indexOf(functionKey, end)) >= 0) { + start = expression.indexOf("(", call) +1; + end = expression.indexOf(")", start); + if(start < 0 || end < 0 || end < start) { + break; + } + Pattern p = Pattern.compile("[-\\+\\*\\/\\(\\)\\{\\}\\[\\],\\.\\t\\n\\r\\f]"); + cellOrRange = expression.substring(start, end); + Matcher m = p.matcher(cellOrRange); + if (m.find() || cellOrRange.split(":").length > 2) { + result.add(new SyntaxError(start, end - start, ExpressionField.SYNTAX_ERROR, "Not a valid cell or range", cellOrRange)); + } + } + + + for(Token cell : functionTokens) { + List refs = expressionReferences.get(cell.image); + if(refs != null) + refs.remove(cell); + if(!sheet.getCells().containsKey(cell.image)) + result.add(new SyntaxError(cell.image, "Invalid cell", cell.beginLine, cell.beginColumn, cell.endLine, cell.endColumn)); + } + } + + return result; + } + + + /** + * Option for a reference. Whether the reference does not exist, + * it can be connected (normal variable) or it cannot be + * connected even though it exists (e.g. enumeration index) + * + * @author Teemu Lempinen + * + */ + static public enum ReferenceOption {DOES_NOT_EXIST, CAN_BE_CONNECTED, CANNOT_BE_CONNECTED}; + + /** + * Get the reference option for a reference (name) in a configuration. + * + * @param conf Configuration + * @param name Referred variable + * @return The result tells does the referred name exist and can it be connected to + */ + static public ReferenceOption getReferenceOption(Configuration conf, String name) { + + String[] parts = name.split("\\."); + Object element = conf; + for(int i = 0; i < parts.length && element != null; i++) { + element = getElement(element, parts[i]); + } + if(element == null) + return ReferenceOption.DOES_NOT_EXIST; + else if(Boolean.TRUE.equals(element)) + return ReferenceOption.CANNOT_BE_CONNECTED; + else if(element instanceof Variable) { + if(element instanceof Enumeration || element instanceof Sheet) + return ReferenceOption.CANNOT_BE_CONNECTED; + else + return ReferenceOption.CAN_BE_CONNECTED; + } + else + return ReferenceOption.DOES_NOT_EXIST; } static private Object getElement(Object parent, String name) { diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/SyntaxError.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/SyntaxError.java new file mode 100644 index 00000000..a2f86e76 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/SyntaxError.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2012 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.sysdyn.ui.utils; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.simantics.sysdyn.expressionParser.Token; +import org.simantics.sysdyn.ui.properties.widgets.expressions.ExpressionField; + +/** + * Class for containing errors caught in expression validation + * @author Teemu Lempinen + * + */ +public class SyntaxError { + + private String type, message, image; + private int beginLine, beginColumn, endLine, endColumn; + private Integer start, offset; + + /** + * A syntax error without any info. Remember to assign location, + * type and message information. + */ + public SyntaxError() { + + } + + /** + * Creates an error from expression parser token + * @param token expressionParser token + * @param message Error message + */ + public SyntaxError(Token token, String message){ + this(token.image, message, token.beginLine, token.beginColumn, token.endLine, token.endColumn); + } + + /** + * Creates an error from table parser token + * @param token tableParser token + * @param message Error message + */ + public SyntaxError(org.simantics.sysdyn.tableParser.Token token, String message){ + this(token.image, message, token.beginLine, token.beginColumn, token.endLine, token.endColumn); + } + + /** + * Create syntax error with full data + * @param image + * @param message + * @param beginLine + * @param beginColumn + * @param endLine + * @param endColumn + */ + public SyntaxError(String image, String message, int beginLine, int beginColumn, int endLine, int endColumn) { + this.image = image; + this.message = message; + this.beginLine = beginLine; + this.beginColumn = beginColumn; + this.endLine = endLine; + this.endColumn = endColumn; + this.type = ExpressionField.SYNTAX_ERROR; + } + + /** + * Create syntax error with location, message and type data + * @param start + * @param offset + * @param type + * @param message + */ + public SyntaxError(int start, int offset, String type, String message) { + this(start, offset, type, message, null); + } + + /** + * Create syntax error with location, message and type data + * @param start + * @param offset + * @param type + * @param message + */ + public SyntaxError(int start, int offset, String type, String message, String image) { + this.image = image; + this.start = start; + this.offset = offset; + this.type = type; + this.message = message; + } + + /** + * Get start location of the issue. If start has not been set, + * document is used to calculate it. + * @param document + * @return + */ + public int getStart(IDocument document) { + if(this.start != null) + return this.start; + else if(document != null){ + int start = 0; + if(document.getLength() > 0) { + try { + start = document.getLineOffset(beginLine - 1) + beginColumn - 1; + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + return start; + } else { + return 0; + } + } + + /** + * Get offset data of the issue. If offset has not been set, + * document is used to calculate it. + * + * @param document + * @return + */ + public int getOffset(IDocument document) { + if(this.offset != null) + return this.offset; + else if(document != null){ + int start = getStart(document); + int offset = document.getLength(); + if(document.getLength() > 0) { + try { + offset = document.getLineOffset(endLine - 1) + endColumn - start; + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + return offset; + } else { + return 0; + } + } + + public void setToken(Token token){ + this.image = token.image; + this.beginLine = token.beginLine; + this.beginColumn = token.beginColumn; + this.endLine = token.endLine; + this.endColumn = token.endColumn; + } + + public void setToken(org.simantics.sysdyn.tableParser.Token token){ + this.image = token.image; + this.beginLine = token.beginLine; + this.beginColumn = token.beginColumn; + this.endLine = token.endLine; + this.endColumn = token.endColumn; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public int getBeginLine() { + return beginLine; + } + + public void setBeginLine(int beginLine) { + this.beginLine = beginLine; + } + + public int getBeginColumn() { + return beginColumn; + } + + public void setBeginColumn(int beginColumn) { + this.beginColumn = beginColumn; + } + + public int getEndLine() { + return endLine; + } + + public void setEndLine(int endLine) { + this.endLine = endLine; + } + + public int getEndColumn() { + return endColumn; + } + + public void setEndColumn(int endColumn) { + this.endColumn = endColumn; + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/DependencyFunction.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/DependencyFunction.java index 25867476..fce73fd7 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/DependencyFunction.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/DependencyFunction.java @@ -13,21 +13,24 @@ package org.simantics.sysdyn.ui.validation; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.Set; import org.simantics.db.Issue; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; -import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variable; -import org.simantics.issues.common.IssueUtils; -import org.simantics.issues.common.StandardIssue; import org.simantics.layer0.Layer0; import org.simantics.scl.reflection.annotations.SCLValue; import org.simantics.sysdyn.SysdynResource; +import org.simantics.sysdyn.manager.SysdynModel; +import org.simantics.sysdyn.manager.SysdynModelManager; +import org.simantics.sysdyn.representation.Configuration; +import org.simantics.sysdyn.ui.properties.widgets.expressions.ExpressionField; +import org.simantics.sysdyn.ui.utils.ExpressionUtils; +import org.simantics.sysdyn.ui.utils.ExpressionUtils.ReferenceOption; +import org.simantics.sysdyn.ui.utils.SyntaxError; import org.simantics.utils.datastructures.collections.CollectionUtils; /** @@ -67,7 +70,7 @@ public class DependencyFunction { // Find all references in equations of component try { - references = ValidationUtils.getReferences(graph, component); + references = ValidationUtils.getAllReferences(graph, component).getVariableReferences(); } catch (Exception e) { return result; } @@ -79,14 +82,28 @@ public class DependencyFunction { if (dependencies != null) { for (String dependency : dependencies) { if (references == null || !references.contains(dependency)) { - Resource variable = ValidationUtils.reach(graph, component, dependency); - result.add(new StandardIssue(sr.Validations_UnusedDependencyIssue, component, variable)); + result.add(new IssueWithStringContext(sr.Validations_UnusedDependencyIssue, component, dependency)); } } } return result; } + + + private static Configuration getConfiguration(ReadGraph graph, Resource component) throws DatabaseException { + Resource configuration = graph.getPossibleObject(component, Layer0.getInstance(graph).PartOf); + + if(configuration == null) + return null; + + SysdynModelManager smm = SysdynModelManager.getInstance(graph.getSession()); + SysdynModel sm = smm.getModel(graph, configuration); + if(sm == null) + return null; + + return sm.getConfiguration(); + } /** * Evaluates dependency-related issues for a component. @@ -109,44 +126,86 @@ public class DependencyFunction { if (!graph.hasStatement(component) || !graph.hasStatement(component, l0.PartOf)) return Collections.emptyList(); - // Find all variables that are linked to component with arrows - Set dependencies = ValidationUtils.getDependencies(graph, component); - Set references = null; - // Find all references in equations of component + References references = null; try { - references = ValidationUtils.getReferences(graph, component); - } catch (SyntaxErrorException e) { - } catch (UnsupportedCharactersException e) { - } catch (UndefinedExpressionException e) { + references = ValidationUtils.getAllReferences(graph, component); + } catch (Exception e) { + return Collections.emptyList(); } - + + Configuration configuration = getConfiguration(graph, component); ArrayList result = new ArrayList(); + + // Examine Sheet references + for(Resource expressionResource : references.functionReferences.keySet()) { + for(String functionKey : references.functionReferences.get(expressionResource).keySet()) { + List sheetErrors = ExpressionUtils.examineSheetReferences( + configuration, + functionKey, + references.functionReferences.get(expressionResource).get(functionKey), + references.expressions.get(expressionResource), + references.references.get(expressionResource)); + if(sheetErrors != null) { + for(SyntaxError error : sheetErrors) + result.add(new IssueWithStringContext(sr.Validations_InvalidSheetReferenceIssue, component, error.getMessage(), error.getImage())); + } + } + } + + + // Examine dependencies + Set variablesReferences = references.getVariableReferences(); + if(variablesReferences == null || variablesReferences.isEmpty()) + return result; + + // Find all variables that are linked to component with arrows + Set dependencies = ValidationUtils.getDependencies(graph, component); + dependencies.addAll(GLOBAL_VARIABLES); + + // Remove all dependency variables from reference maps + for(String dependency : dependencies) + variablesReferences.remove(dependency); boolean isStock = isStock(graph, component); - StandardIssue noSuchVariableIssue = null; - // Check that all references have corresponding arrows - if (references != null && dependencies != null) { - for (String reference : references) { - if (!dependencies.contains(reference) && !GLOBAL_VARIABLES.contains(reference)) { - Resource variable = null; - if ((variable = ValidationUtils.reach(graph, component, reference)) != null) { - if(isStock) { - /* Stocks do not get incoming dependencies. They are allowed - to have references without arrows */ - } else { - result.add(new StandardIssue(sr.Validations_MissingLinkIssue, component, variable)); - } + ReferenceOption option; + + for(String reference : variablesReferences) { + option = ExpressionUtils.getReferenceOption(configuration, reference); + switch(option) { + case DOES_NOT_EXIST: + result.add(new IssueWithStringContext(sr.Validations_NoSuchVariableIssue, component, reference)); + case CAN_BE_CONNECTED: + if(isStock) { + /* Stocks do not get incoming dependencies. They are allowed + to have references without arrows */ } else { - if (noSuchVariableIssue == null) { - noSuchVariableIssue = new StandardIssue(sr.Validations_NoSuchVariableIssue, component); - result.add(noSuchVariableIssue); - } + result.add(new IssueWithStringContext(sr.Validations_MissingLinkIssue, component, reference)); } - } + break; + case CANNOT_BE_CONNECTED: } } + + + for(Resource expression : references.ranges.keySet()) { + List errors = new ArrayList(); + // RANGES + errors.addAll(ExpressionUtils.examineArrayRanges(graph, configuration, references.ranges.get(expression), references.forIndices.get(expression))); + + // ENUMERATION REFERENCES IN FOR-LOOPS + errors.addAll(ExpressionUtils.examineEnumerationReferences(configuration, references.enumerationReferences.get(expression))); + + for(SyntaxError error : errors) { + Resource type = sr.Validations_RangeIssue; + if(ExpressionField.SYNTAX_WARNING.equals(error.getType())) { + type = sr.Validations_RangeWarning; + } + result.add(new IssueWithStringContext(type, component, error.getMessage())); + } + } + return result; } @@ -177,13 +236,12 @@ public class DependencyFunction { public static String missingLinkIssueDescription(ReadGraph graph, Resource converter, Variable property) throws DatabaseException { - List contexts = IssueUtils.getContextsForProperty(graph, property); + List contexts = IssueWithStringContext.getStringContexts(graph, property); String result = "Missing a link to "; if (contexts.size() > 0) { - Resource component = contexts.get(1); - String name = NameUtils.getSafeName(graph, component); - result = result + name; + result = result + contexts.get(0); } + return result; } @@ -200,14 +258,13 @@ public class DependencyFunction { @SCLValue(type = "ReadGraph -> Resource -> Variable -> String") public static String unusedDependencyIssueDescription(ReadGraph graph, Resource converter, Variable property) throws DatabaseException { - - List contexts = IssueUtils.getContextsForProperty(graph, property); + + List contexts = IssueWithStringContext.getStringContexts(graph, property); String result = "Unused dependency: "; if (contexts.size() > 0) { - Resource component = contexts.get(1); - String name = NameUtils.getSafeName(graph, component); - result = result + name; + result = result + contexts.get(0); } + return result; } @@ -224,49 +281,50 @@ public class DependencyFunction { @SCLValue(type = "ReadGraph -> Resource -> Variable -> String") public static String noSuchVariableIssueDescription(ReadGraph graph, Resource converter, Variable property) throws DatabaseException { - - List contexts = IssueUtils.getContextsForProperty(graph, property); - Resource component = contexts.get(0); - - // Find all variables that are linked to component with arrows - Set dependencies = ValidationUtils.getDependencies(graph, component); - Set references = null; - - // Find all references in equations of component - try { - references = ValidationUtils.getReferences(graph, component); - } catch (SyntaxErrorException e) { - } catch (UnsupportedCharactersException e) { - } catch (UndefinedExpressionException e) { + + List contexts = IssueWithStringContext.getStringContexts(graph, property); + String result = "Refers to unexisting variable "; + if (contexts.size() > 0) { + result = result + contexts.get(0); } + + return result; + } + + @SCLValue(type = "ReadGraph -> Resource -> Variable -> String") + public static String invalidSheetReferenceIssueDescription(ReadGraph graph, Resource converter, Variable property) + throws DatabaseException { + + List contexts = IssueWithStringContext.getStringContexts(graph, property); + String result = ""; + + if(contexts.size() == 2) + result = contexts.get(0) + ": " + contexts.get(1); + else + result = "Spreadsheet reference error"; - ArrayList result = new ArrayList(); - // Loop all references - if (references != null && dependencies != null) { - for (String reference : references) { - // If dependencies does not contain reference and the reference - // is not reachable from component, add the name - if (!dependencies.contains(reference) && ValidationUtils.reach(graph, component, reference) == null) { - result.add(reference); - } - } - } - if (result.size() == 0) { - return "Missing link"; - } else if (result.size() == 1) { - return "Refers to unexisting variable " + result.get(0); + return result; + } + + @SCLValue(type = "ReadGraph -> Resource -> Variable -> String") + public static String rangeIssueDescription(ReadGraph graph, Resource converter, Variable property) + throws DatabaseException { + + List contexts = IssueWithStringContext.getStringContexts(graph, property); + if (contexts.size() > 0) { + return contexts.get(0); } else { - StringBuilder sb = new StringBuilder(); - sb.append("Refers to unexisting variables "); - Iterator iterator = result.iterator(); - String reference; - while (iterator.hasNext()) { - reference = iterator.next(); - sb.append(reference); - if (iterator.hasNext()) - sb.append(", "); - } - return sb.toString(); + return "Range Issue"; } } + + @SCLValue(type = "ReadGraph -> Resource -> Variable -> String") + public static String rangeWarningDescription(ReadGraph graph, Resource converter, Variable property) + throws DatabaseException { + return rangeIssueDescription(graph, converter, property); + } + + + + } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ExpressionIssueFunction.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ExpressionIssueFunction.java index a027fce7..782fb3cf 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ExpressionIssueFunction.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ExpressionIssueFunction.java @@ -47,7 +47,7 @@ public class ExpressionIssueFunction { // Try if there are any errors while parsing the expressions try { - ValidationUtils.getReferences(graph, component); + ValidationUtils.getAllReferences(graph, component); } catch (Exception e) { return Collections.singletonList(new StandardIssue(sr.Validations_ExpressionIssue, component)); } @@ -62,7 +62,7 @@ public class ExpressionIssueFunction { // There should be an error try { - ValidationUtils.getReferences(graph, component); + ValidationUtils.getAllReferences(graph, component); } catch (SyntaxErrorException e) { return SYNTAX_ERROR; } catch (UnsupportedCharactersException e) { diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/Functions.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/Functions.java index d53a9128..eca08108 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/Functions.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/Functions.java @@ -22,8 +22,6 @@ import org.simantics.issues.common.IssueUtils; import org.simantics.layer0.Layer0; import org.simantics.project.ontology.ProjectResource; import org.simantics.scl.reflection.annotations.SCLValue; -import org.simantics.simulation.ontology.SimulationResource; -import org.simantics.structural.stubs.StructuralResource2; import org.simantics.sysdyn.SysdynResource; /** @@ -36,13 +34,7 @@ public class Functions { @SCLValue(type = "ReadGraph -> Resource -> Resource") public static Resource baseRealizationFunction(ReadGraph graph, Resource model) throws DatabaseException { - SysdynResource sr = SysdynResource.getInstance(graph); - if(graph.isInstanceOf(model, sr.SysdynModel)) - return graph.getSingleObject(model, SimulationResource.getInstance(graph).HasConfiguration); - else if (graph.isInheritedFrom(model, sr.Module)) - return graph.getSingleObject(model, StructuralResource2.getInstance(graph).IsDefinedBy); - else return null; - + return model; } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/IssueWithStringContext.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/IssueWithStringContext.java new file mode 100644 index 00000000..a491add4 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/IssueWithStringContext.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2012 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.sysdyn.ui.validation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.issues.common.StandardIssue; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.SysdynResource; + +/** + * Issue that can have string contexts. + * + * String contexts are written to a graph like resource contexts and can be accessed + * in issue description functions. This eliminates the need for making complex calculations + * for obtaining values that have already been calculated in the issue source function. + * + * @author Teemu Lempinen + * + */ +public class IssueWithStringContext extends StandardIssue { + + String[] stringContexts; + + /** + * Creates an issue with one resource context and an arbitrary number of string contexts + * @param type + * @param context + * @param stringContexts + */ + public IssueWithStringContext(Resource type, Resource context, String... stringContexts) { + super(type, context); + this.stringContexts = stringContexts; + } + + /** + * Get the string contexts of this issue + * @return string contexts + */ + public String[] getStringContexts() { + return stringContexts; + } + + /** + * Overridden function from StandardResource. This writes a list of string contexts to the database. + */ + public void writeAdditionalContext(WriteGraph graph, Resource issue) throws DatabaseException { + super.writeAdditionalContext(graph, issue); + + // Add possible string contexts to the contexts array + if(stringContexts != null && stringContexts.length > 0) { + SysdynResource SR = SysdynResource.getInstance(graph); + Layer0 L0 = Layer0.getInstance(graph); + List contexts = new ArrayList(); + for(String s : stringContexts) { + Resource r = graph.newResource(); + graph.claim(r, L0.InstanceOf, L0.String); + graph.claimValue(r, s, Bindings.STRING); + contexts.add(r); + } + graph.claim(issue, SR.Validations_Issue_stringContexts, ListUtils.create(graph, L0.List, contexts)); + } + + } + + /** + * Gets string contexts from IssueWithStringContexts + * @param graph ReadGraph + * @param property issue property + * @return String contexts of issue or empty list if none is found + * @throws DatabaseException + */ + public static List getStringContexts(ReadGraph graph, Variable property) throws DatabaseException { + SysdynResource SR = SysdynResource.getInstance(graph); + Variable issueVariable = property.getParent(graph); + Resource issueResource = issueVariable.getRepresents(graph); + Resource list = graph.getPossibleObject(issueResource, SR.Validations_Issue_stringContexts); + if(list == null) { + return Collections.emptyList(); + } else { + List stringResources = ListUtils.toList(graph, list); + ArrayList result = new ArrayList(stringResources.size()); + for(Resource r : stringResources) { + result.add((String)graph.getValue(r, Bindings.STRING)); + } + return result; + } + } +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/References.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/References.java new file mode 100644 index 00000000..0d9ed3d9 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/References.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2012 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.sysdyn.ui.validation; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.simantics.db.Resource; +import org.simantics.sysdyn.expressionParser.Token; + +/** + * Container for different types of references got from expression parser + * @author Teemu Lempinen + * + */ +public class References { + public HashMap expressions = new HashMap(); + public HashMap>> references = new HashMap>>(); + public HashMap>>> ranges = new HashMap>>>(); + public HashMap>> forIndices = new HashMap>>(); + public HashMap>> enumerationReferences = new HashMap>>(); + public HashMap>> functionReferences = new HashMap>>(); + + + /** + * Get all variable references from all expressions of the variable in a single set + * @return All variable references + */ + public Set getVariableReferences() { + HashSet result = new HashSet(); + for(HashMap> map : references.values()) { + for(String key : map.keySet()) { + if(!map.get(key).isEmpty()) + result.add(key); + } + } + + return result; + } +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ValidationUtils.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ValidationUtils.java index 79293b0b..e8f84068 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ValidationUtils.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ValidationUtils.java @@ -13,20 +13,20 @@ package org.simantics.sysdyn.ui.validation; import java.io.StringReader; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; -import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; -import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.layer0.Layer0; import org.simantics.sysdyn.SysdynResource; import org.simantics.sysdyn.expressionParser.ExpressionParser; import org.simantics.sysdyn.expressionParser.ParseException; +import org.simantics.sysdyn.expressionParser.Token; import org.simantics.sysdyn.expressionParser.TokenMgrError; /** @@ -35,7 +35,7 @@ import org.simantics.sysdyn.expressionParser.TokenMgrError; * */ public class ValidationUtils { - + /** * Find all variables that are referred to in the expressions of variable r * @param graph ReadGraph @@ -46,8 +46,9 @@ public class ValidationUtils { * @throws UnsupportedCharactersException * @throws UndefinedExpressionException */ - public static HashSet getReferences(ReadGraph graph, Resource r) throws DatabaseException, SyntaxErrorException, UnsupportedCharactersException, UndefinedExpressionException { - HashSet references = new HashSet(); + public static References getAllReferences(ReadGraph graph, Resource r) throws DatabaseException, SyntaxErrorException, UnsupportedCharactersException, UndefinedExpressionException { + References result = new References(); + ExpressionParser parser = new ExpressionParser(new StringReader("")); SysdynResource sr = SysdynResource.getInstance(graph); @@ -65,16 +66,22 @@ public class ValidationUtils { if(value.length() == 0) { // Empty might be allowed - if(graph.isSubrelationOf(statement.getPredicate(), sr.HasEquationOrEmpty)) - return references; - else + if(!graph.isSubrelationOf(statement.getPredicate(), sr.HasEquationOrEmpty)) throw new UndefinedExpressionException(); } parser.ReInit(new StringReader(value)); try { parser.expr(); - references.addAll(parser.getReferences().keySet()); + + HashMap> refs = parser.getReferences(); + result.references.put(expression, refs); + result.ranges.put(expression, parser.getRanges()); + result.forIndices.put(expression, parser.getForIndices()); + result.enumerationReferences.put(expression, parser.getEnumerationReferences()); + result.functionReferences.put(expression, parser.getFunctionCallReferences()); + result.expressions.put(expression, value); + } catch (ParseException e1) { throw new SyntaxErrorException(); } catch (TokenMgrError err) { @@ -82,9 +89,9 @@ public class ValidationUtils { } } } - return references; + return result; } - + /** * Get all expressions of a variable r * @param graph ReadGraph @@ -132,42 +139,4 @@ public class ValidationUtils { return variables; } - /** - * Is reference reachable from variable - * - * @param graph - * @param variable - * @param reference - * @return - * @throws DatabaseException - */ - public static boolean isReachable(ReadGraph graph, Resource variable, String reference) throws DatabaseException { - if(reach(graph, variable, reference) != null) - return true; - else - return false; - } - - /** - * Find a resource starting from variable and using reference path - * - * @param graph ReadGraph - * @param variable starting point - * @param reference path to another variable - * @return found variable or null - * @throws DatabaseException - */ - public static Resource reach(ReadGraph graph, Resource variable, String reference) throws DatabaseException { - Layer0 l0 = Layer0.getInstance(graph); - SysdynResource sr = SysdynResource.getInstance(graph); - Resource configuration = graph.getSingleObject(variable, l0.PartOf); - String varName; - for(Resource var : graph.syncRequest(new ObjectsWithType(configuration, l0.ConsistsOf, sr.Variable))) { - varName = graph.getRelatedValue(var, l0.HasName, Bindings.STRING); - if(varName != null && reference.equals(varName)) - return var; - } - return null; - } - }