Skip to content

Commit

Permalink
Merge pull request #1339 from lf-lang/master
Browse files Browse the repository at this point in the history
Merge from Master
  • Loading branch information
arengarajan99 authored Aug 30, 2022
2 parents d1bc156 + 71d832a commit 0ab9cb3
Show file tree
Hide file tree
Showing 13 changed files with 225 additions and 165 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ buildNumber.properties
.flattened-pom.xml

### VisualStudioCode ###
.vscode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,27 @@
***************/
package org.lflang.diagram.synthesis.util;

import com.google.inject.Inject;
import de.cau.cs.kieler.klighd.krendering.KContainerRendering;
import de.cau.cs.kieler.klighd.krendering.KGridPlacementData;
import de.cau.cs.kieler.klighd.krendering.KRectangle;
import de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared;
import de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions;
import de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;

import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.xtext.xbase.lib.Exceptions;
import org.eclipse.xtext.xbase.lib.Extension;
import org.eclipse.xtext.xbase.lib.StringExtensions;
import org.lflang.ASTUtils;
import org.lflang.AttributeUtils;
import org.lflang.diagram.synthesis.AbstractSynthesisExtensions;
import org.lflang.lf.ReactorDecl;
import org.lflang.util.FileUtil;

import com.google.inject.Inject;

import de.cau.cs.kieler.klighd.krendering.Colors;
import de.cau.cs.kieler.klighd.krendering.KContainerRendering;
import de.cau.cs.kieler.klighd.krendering.KGridPlacementData;
import de.cau.cs.kieler.klighd.krendering.KRectangle;
import de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared;
import de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions;
import de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions;

/**
* Utility class to handle icons for reactors in Lingua Franca diagrams.
Expand All @@ -63,127 +59,91 @@ public class ReactorIcons extends AbstractSynthesisExtensions {

private static final ImageLoader LOADER = new ImageLoader();

// memory-sensitive cache
private static final HashMap<URL, SoftReference<ImageData>> CACHE = new HashMap<>();
// Image cache during synthesis
private final HashMap<java.net.URI, ImageData> cache = new HashMap<>();

// Error message
private String error = null;

public void handleIcon(KContainerRendering rendering, ReactorDecl reactor, boolean collapsed) {
if (!collapsed) {
return;
}
URL iconLocation = locateIcon(reactor);
if (iconLocation != null) {
ImageData data = loadImage(iconLocation);
if (data != null) {
KRectangle figure = _kContainerRenderingExtensions.addRectangle(rendering);
_kRenderingExtensions.setInvisible(figure, true);
KGridPlacementData figurePlacement = _kRenderingExtensions.setGridPlacementData(figure, data.width, data.height);
_kRenderingExtensions.to(
_kRenderingExtensions.from(
figurePlacement,
_kRenderingExtensions.LEFT, 3, 0,
_kRenderingExtensions.TOP, 0, 0),
_kRenderingExtensions.RIGHT, 3, 0,
_kRenderingExtensions.BOTTOM, 3, 0);

KRectangle icon = _kContainerRenderingExtensions.addRectangle(figure);
_kRenderingExtensions.setInvisible(icon, true);
_kContainerRenderingExtensions.addImage(icon, data);
_kRenderingExtensions.setPointPlacementData(icon,
_kRenderingExtensions.createKPosition(
_kRenderingExtensions.LEFT, 0, 0.5f,
_kRenderingExtensions.TOP, 0, 0.5f),
_kRenderingExtensions.H_CENTRAL, _kRenderingExtensions.V_CENTRAL, 0,
0, data.width, data.height);
}

// Reset error
error = null;

// Get annotation
String iconPath = AttributeUtils.findAttributeByName(reactor, "icon");
if (iconPath == null) { // Fallback to old syntax (in comment)
iconPath = ASTUtils.findAnnotationInComments(reactor, "@icon");
}
}

private URL locateIcon(EObject eobj) {
URL location = null;
String iconPath = ASTUtils.findAnnotationInComments(eobj, "@icon");
if (!StringExtensions.isNullOrEmpty(iconPath)) {
// Check if path is URL
try {
return new URL(iconPath);
} catch (Exception e) {
// nothing
}
// Check if path exists as is
File path = new File(iconPath);
if (path.exists()) {
try {
return path.toURI().toURL();
} catch (Exception e) {
// nothing
}
}
// Check if path is relative to LF file
URI eURI = eobj.eResource() != null ? eobj.eResource().getURI() : null;
if (eURI != null) {
java.net.URI sourceURI = null;
try {
if (eURI.isFile()) {
sourceURI = new java.net.URI(eURI.toString());
sourceURI = new java.net.URI(sourceURI.getScheme(), null,
sourceURI.getPath().substring(0, sourceURI.getPath().lastIndexOf("/")), null);
} else if (eURI.isPlatformResource()) {
IResource iFile = ResourcesPlugin.getWorkspace().getRoot().findMember(eURI.toPlatformString(true));
sourceURI = iFile != null ? iFile.getRawLocation().toFile().getParentFile().toURI() : null;
} else if (eURI.isPlatformPlugin()) {
// TODO support loading from plugin bundles?
}
} catch (Exception e) {
// nothing
}
if (sourceURI != null) {
try {
location = sourceURI.resolve(path.toString()).toURL();
} catch (Exception e) {
// nothing
}
if (iconPath != null && !iconPath.isEmpty()) {
var iconLocation = FileUtil.locateFile(iconPath, reactor.eResource());
if (iconLocation == null) {
error = "Cannot find given icon file.";
} else {
ImageData data = loadImage(iconLocation);
if (data != null) {
KRectangle figure = _kContainerRenderingExtensions.addRectangle(rendering);
_kRenderingExtensions.setInvisible(figure, true);
KGridPlacementData figurePlacement = _kRenderingExtensions.setGridPlacementData(figure, data.width, data.height);
_kRenderingExtensions.to(
_kRenderingExtensions.from(
figurePlacement,
_kRenderingExtensions.LEFT, 3, 0,
_kRenderingExtensions.TOP, 0, 0),
_kRenderingExtensions.RIGHT, 3, 0,
_kRenderingExtensions.BOTTOM, 3, 0);

KRectangle icon = _kContainerRenderingExtensions.addRectangle(figure);
_kRenderingExtensions.setInvisible(icon, true);
_kContainerRenderingExtensions.addImage(icon, data);
_kRenderingExtensions.setPointPlacementData(icon,
_kRenderingExtensions.createKPosition(
_kRenderingExtensions.LEFT, 0, 0.5f,
_kRenderingExtensions.TOP, 0, 0.5f),
_kRenderingExtensions.H_CENTRAL, _kRenderingExtensions.V_CENTRAL, 0,
0, data.width, data.height);
}
if (error != null) {
var errorText = _kContainerRenderingExtensions.addText(rendering, "Icon not found!\n"+error);
_kRenderingExtensions.setForeground(errorText, Colors.RED);
_kRenderingExtensions.setFontBold(errorText, true);
_kRenderingExtensions.setSurroundingSpaceGrid(errorText, 8, 0);
}
}
// TODO more variants based on package and library system in LF
}
return location;
}

private ImageData loadImage(final URL url) {
private ImageData loadImage(final java.net.URI uri) {
try {
synchronized (CACHE) {
if (CACHE.containsKey(url)) {
ImageData img = CACHE.get(url).get();
if (img != null) {
return img;
} else {
CACHE.remove(url);
}
}
if (cache.containsKey(uri)) {
return cache.get(uri);
}
synchronized (LOADER) {
InputStream inStream = null;
try {
inStream = url.openStream();
// TODO check for memory leak !!!
inStream = uri.toURL().openStream();
ImageData[] data = LOADER.load(inStream);
if (data != null && data.length > 0) {
ImageData img = data[0];
synchronized (CACHE) {
CACHE.put(url, new SoftReference<ImageData>(img));
}
cache.put(uri, img);
return img;
} else {
error = "Could not load icon image.";
return null;
}
return null;
} finally {
if (inStream != null) {
inStream.close();
}
}
}
} catch (IOException ex) {
throw Exceptions.sneakyThrow(ex);
} catch (Exception ex) {
ex.printStackTrace();
error = "Could not load icon image.";
return null;
}
}

Expand Down
23 changes: 11 additions & 12 deletions org.lflang/src/lib/ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@
"name": "LinguaFrancaDefault",
"version": "0.0.1",
"description": "A default Lingua Franca project for the TypeScript target",
"type": "commonjs",
"repository": {
"type": "git",
"url": "https://github.com/icyphy/lingua-franca"
},
"license": "BSD-2-Clause",
"dependencies": {
"command-line-args": "^5.1.1",
"command-line-usage": "^6.1.0",
"microtime": "^3.0.0",
"ulog": "^2.0.0-beta.7",
"google-protobuf": "^3.7.4",
"uuid": "^8.3.2"
},
"devDependencies": {
"reactor-ts": "file:./reactor-ts",
"@types/reactor-ts": "file:./reactor-ts",
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.7",
"@babel/node": "^7.8.7",
Expand All @@ -25,18 +20,22 @@
"@babel/plugin-transform-modules-commonjs": "^7.8.3",
"@babel/preset-env": "^7.8.7",
"@babel/preset-typescript": "^7.8.3",
"command-line-usage": "^6.1.0",
"command-line-args": "^5.1.1",
"rimraf": "^3.0.2"
},
"devDependencies": {
"@types/google-protobuf": "^3.7.4",
"@types/node": "^13.9.2",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.8.1",
"@typescript-eslint/eslint-plugin": "5.33.0",
"@typescript-eslint/parser": "^5.8.1",
"eslint": "^8.5.0",
"rimraf": "^3.0.2",
"typescript": "^3.8.3",
"typescript": "~4.8.2",
"ts-protoc-gen": "^0.12.0"
},
"scripts": {
"check-types": "tsc",
"build": "rimraf dist && babel src --out-dir dist --extensions .ts,.js"
"build": "npx rimraf dist && npx babel src --out-dir dist --extensions .ts,.js"
}
}
4 changes: 3 additions & 1 deletion org.lflang/src/lib/ts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"allowJs": true,
"noEmit": true,
"target": "esnext",
"types": ["node", "reactor-ts", "ulog", "microtime", "command-line-args", "command-line-usage"],
"esModuleInterop": true,
"isolatedModules": true,
"lib": ["esnext", "dom"],
Expand All @@ -12,8 +13,9 @@
"strictBindCallApply": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"typeRoots": ["./node_modules/@types/", "./node_modules/reactor-ts/src/core/@types/"]
},
"include": [
"src/**/*",
"src/**/*"
]
}
20 changes: 16 additions & 4 deletions org.lflang/src/org/lflang/AttributeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@

/**
* A helper class for processing attributes in the AST.
*
* @author{Shaokai Lin <[email protected]>}
* @author{Clément Fournier, TU Dresden, INSA Rennes}
* @author{Alexander Schulz-Rosengarten <[email protected]>}
*/
public class AttributeUtils {

Expand Down Expand Up @@ -74,20 +76,30 @@ public static List<Attribute> getAttributes(EObject node) {
}

/**
* Return the value of the {@code @label} attribute if
* present, otherwise return null.
* Return the value of the attribute with the given name
* if present, otherwise return null.
*
* @throws IllegalArgumentException If the node cannot have attributes
*/
public static String findLabelAttribute(EObject node) {
public static String findAttributeByName(EObject node, String name) {
List<Attribute> attrs = getAttributes(node);
return attrs.stream()
.filter(it -> it.getAttrName().equals("label"))
.filter(it -> it.getAttrName().equalsIgnoreCase(name)) // case-insensitive search (more user-friendly)
.map(it -> it.getAttrParms().get(0).getValue().getStr())
.findFirst()
.orElse(null);
}

/**
* Return the value of the {@code @label} attribute if
* present, otherwise return null.
*
* @throws IllegalArgumentException If the node cannot have attributes
*/
public static String findLabelAttribute(EObject node) {
return findAttributeByName(node, "label");
}

/**
* Return true if the specified node is an Input and has an {@code @sparse}
* attribute.
Expand Down
8 changes: 4 additions & 4 deletions org.lflang/src/org/lflang/generator/ts/TSFileConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,19 @@ class TSFileConfig(
/**
* Path to TypeScript core source code.
*/
fun tsCoreGenPath(): Path = tsSrcGenPath().resolve("core")
fun reactorTsPath(): Path = srcGenPath.resolve("reactor-ts")

/**
* Path to the generated docker file
*/
fun tsDockerFilePath(tsFileName: String): Path {
return srcGenPath.resolve(tsFileName + ".Dockerfile")
return srcGenPath.resolve("$tsFileName.Dockerfile")
}

/**
* Path to the generated docker compose file
*/
fun tsDockerComposeFilePath(): Path {
return srcGenPath.resolve("docker-compose.yml")
}
}
}
Loading

0 comments on commit 0ab9cb3

Please sign in to comment.