From: Marko Luukkainen Date: Fri, 21 Sep 2018 09:22:43 +0000 (+0000) Subject: Merge "Reading background color of a ICanvasContext with SCL" X-Git-Tag: v1.43.0~136^2~364 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=ec70c03d4ce3f68b71de5eeadce3d008620c5521;hp=6223edf13f7d35e18c45e35343c0347fb0159b2b Merge "Reading background color of a ICanvasContext with SCL" --- diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StructuredProperty.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StructuredProperty.java new file mode 100644 index 000000000..fa6469c3f --- /dev/null +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StructuredProperty.java @@ -0,0 +1,10 @@ +package org.simantics.db.layer0.variable; + +/** + * Java interface for StructuredProperty SCL value type. + * + * @author Tuukka Lehtonen + * @since 1.36.0 + */ +public interface StructuredProperty { +} \ No newline at end of file diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/TranslateElement.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/TranslateElement.java index 215b77f3f..f7a1ad185 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/TranslateElement.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/TranslateElement.java @@ -97,7 +97,7 @@ public class TranslateElement extends ModificationAdapter { if (!changed) return; - at.setTransform(at.getScaleX(), at.getShearX(), at.getShearY(), at.getScaleY(), x, y); + at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), x, y); DiagramGraphUtil.setTransform(graph, element, at); CommentMetadata cm = graph.getMetadata(CommentMetadata.class); diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/SWTPopupMenuParticipant.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/SWTPopupMenuParticipant.java index 588692b91..c489373b6 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/SWTPopupMenuParticipant.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/SWTPopupMenuParticipant.java @@ -27,7 +27,6 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPartSite; import org.simantics.g2d.canvas.ICanvasContext; @@ -42,6 +41,7 @@ import org.simantics.utils.datastructures.hints.HintListenerAdapter; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintListener; import org.simantics.utils.datastructures.hints.IHintObservable; +import org.simantics.utils.ui.SWTDPIUtil; /** * A participant that initializes an SWT pop-up menu and registers it with the @@ -221,20 +221,15 @@ public class SWTPopupMenuParticipant extends AbstractCanvasParticipant { * @param newValue * @thread canvas-thread (AWT) */ - protected void showPopup(Point2D newValue) { - final Point2D cp = (Point2D) newValue; + protected void showPopup(Point2D cp) { setHint(DiagramHints.POPUP_MENU_CONTROL_POSITION, cp); setHint(DiagramHints.POPUP_MENU_CANVAS_POSITION, trUtil.controlToCanvas(cp, null)); - display.asyncExec(new Runnable() { - @Override - public void run() { - if (control == null || control.isDisposed()) - return; - - Point p = control.toDisplay((int) cp.getX(), (int) cp.getY()); - menuManager.getMenu().setLocation(p); - menuManager.getMenu().setVisible(true); - } + display.asyncExec(() -> { + if (control == null || control.isDisposed()) + return; + Point p = control.toDisplay( SWTDPIUtil.downscaleSwtToInteger(cp) ); + menuManager.getMenu().setLocation(p); + menuManager.getMenu().setVisible(true); }); } diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/e4/SWTPopupMenuParticipant.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/e4/SWTPopupMenuParticipant.java index eb7fd9928..e6e4d33ee 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/e4/SWTPopupMenuParticipant.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/ui/e4/SWTPopupMenuParticipant.java @@ -14,9 +14,6 @@ package org.simantics.diagram.ui.e4; import java.awt.geom.Point2D; import org.eclipse.e4.ui.model.application.ui.basic.MPart; -import org.eclipse.e4.ui.model.application.ui.menu.MMenu; -import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory; -import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IMenuListener2; import org.eclipse.jface.action.IMenuManager; @@ -46,6 +43,7 @@ import org.simantics.utils.datastructures.hints.HintListenerAdapter; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintListener; import org.simantics.utils.datastructures.hints.IHintObservable; +import org.simantics.utils.ui.SWTDPIUtil; /** * A participant that initializes an SWT pop-up menu and registers it with the @@ -215,19 +213,15 @@ public class SWTPopupMenuParticipant extends AbstractCanvasParticipant { * @param newValue * @thread canvas-thread (AWT) */ - protected void showPopup(Point2D newValue) { - final Point2D cp = (Point2D) newValue; + protected void showPopup(Point2D cp) { setHint(DiagramHints.POPUP_MENU_CONTROL_POSITION, cp); setHint(DiagramHints.POPUP_MENU_CANVAS_POSITION, trUtil.controlToCanvas(cp, null)); - display.asyncExec(new Runnable() { - @Override - public void run() { - if (control == null || control.isDisposed()) - return; - Point p = control.toDisplay((int) cp.getX(), (int) cp.getY()); - menuManager.getMenu().setLocation(p); - menuManager.getMenu().setVisible(true); - } + display.asyncExec(() -> { + if (control == null || control.isDisposed()) + return; + Point p = control.toDisplay( SWTDPIUtil.downscaleSwtToInteger(cp) ); + menuManager.getMenu().setLocation(p); + menuManager.getMenu().setVisible(true); }); } diff --git a/bundles/org.simantics.g2d/plugin.xml b/bundles/org.simantics.g2d/plugin.xml index 10cb3b73f..85dfc192c 100644 --- a/bundles/org.simantics.g2d/plugin.xml +++ b/bundles/org.simantics.g2d/plugin.xml @@ -34,7 +34,7 @@ categoryId="org.simantics.g2d" id="org.simantics.gallery.itemfont" label="Symbol Font" - value="Tahoma-regular-8"> + value="Tahoma-regular-12"> The symbol font is used for labels of symbols in the symbol library view. diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/DiagramHints.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/DiagramHints.java index aded9d170..0c11d348a 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/DiagramHints.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/DiagramHints.java @@ -155,7 +155,7 @@ public class DiagramHints { /** * A Hint for other participants to use for showing the context menu at the - * contol position specified by the Point2D argument. + * control position specified by the Point2D argument. */ public static final Key SHOW_POPUP_MENU = new KeyOf(Point2D.class, "SHOW_POPUP_MENU_CMD"); diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/event/adapter/SWTMouseEventAdapter.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/event/adapter/SWTMouseEventAdapter.java index bb8560c30..924c7c252 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/event/adapter/SWTMouseEventAdapter.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/event/adapter/SWTMouseEventAdapter.java @@ -34,6 +34,7 @@ import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent; import org.simantics.scenegraph.g2d.events.adapter.AbstractEventAdapter; +import org.simantics.utils.ui.SWTDPIUtil; public class SWTMouseEventAdapter extends AbstractEventAdapter implements MouseListener, MouseMoveListener, MouseTrackListener, MouseWheelListener { @@ -64,12 +65,12 @@ public class SWTMouseEventAdapter extends AbstractEventAdapter implements MouseL private Point2D getControlPosition(MouseEvent e) { - return new Point2D.Double(e.x, e.y); + return new Point2D.Double(SWTDPIUtil.upscaleSwt(e.x), SWTDPIUtil.upscaleSwt(e.y)); } private Point2D getScreenPosition(MouseEvent e) { - Point p = e.display.getCursorLocation(); + Point p = SWTDPIUtil.upscaleSwt(e.display.getCursorLocation()); return new Point2D.Double(p.x, p.y); } diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/gallery/GalleryViewer.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/gallery/GalleryViewer.java index 2e8ad5b66..ce5687e84 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/gallery/GalleryViewer.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/gallery/GalleryViewer.java @@ -105,6 +105,7 @@ import org.simantics.utils.threads.logger.ITask; import org.simantics.utils.threads.logger.ThreadLogger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.simantics.utils.ui.SWTDPIUtil; /** * @author Toni Kalajainen @@ -165,22 +166,24 @@ public class GalleryViewer extends ContentViewer { chassis = new SWTChassis(composite, style) { @Override public Point computeSize(int wHint, int hHint, boolean changed) { -// System.out.println("chassis compute size: " + wHint + ", " + hHint + ", " + changed); - if (diagram == null) return super.computeSize(wHint, hHint, changed); + // Note: This code must take into account that FlowLayout expects to + // receive pixel coordinates, not SWT API coordinates. + Rectangle2D rect; // if (!changed) { // rect = ElementUtils.getSurroundingElementBoundsOnDiagram(diagram.getSnapshot()); // } // else { - Double wH = wHint==SWT.DEFAULT ? null : (double) wHint-vMargin-vMargin; - Double hH = hHint==SWT.DEFAULT ? null : (double) hHint-hMargin-hMargin; + Double wH = wHint==SWT.DEFAULT ? null : (double) SWTDPIUtil.upscaleSwt(wHint)-hMargin*2; + Double hH = hHint==SWT.DEFAULT ? null : (double) SWTDPIUtil.upscaleSwt(hHint)-vMargin*2; rect = fl.computeSize(diagram, wH, hH); + SWTDPIUtil.downscaleSwt(rect, rect); } - return new Point((int)rect.getMaxX()+hMargin*2, (int)rect.getMaxY()+vMargin*2); + return new Point((int)rect.getWidth()+hMargin*2, (int)rect.getHeight()+vMargin*2); } }; @@ -210,12 +213,7 @@ public class GalleryViewer extends ContentViewer { hintCtx.setHint(DiagramHints.KEY_DIAGRAM, diagram); // Force layout - ThreadUtils.asyncExec(swtThread, new Runnable() { - @Override - public void run() { - resized(false); - } - }); + ThreadUtils.asyncExec(swtThread, () -> resized(false)); }); chassis.addControlListener(new ControlListener() { @@ -255,12 +253,9 @@ public class GalleryViewer extends ContentViewer { fontRegistry.removeListener(fontRegistryListener); // Prevent memory leaks. - ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() { - @Override - public void run() { - chassis.getAWTComponent().setCanvasContext(null); - ctx.dispose(); - } + ThreadUtils.asyncExec(ctx.getThreadAccess(), () -> { + chassis.getAWTComponent().setCanvasContext(null); + ctx.dispose(); }); } }); @@ -274,12 +269,7 @@ public class GalleryViewer extends ContentViewer { currentItemFont = FontHelper.toAwt(fdn); itemClass.getSingleItem(GalleryItemSGNode.class).setFont(currentItemFont); // FIXME: a bug exists in this case. The group size will not be refreshed even though the sizes of the gallery items are recalculated and changed. - ThreadUtils.asyncExec(swtThread, new Runnable() { - @Override - public void run() { - resized(true); - } - }); + ThreadUtils.asyncExec(swtThread, () -> resized(true)); } }; @@ -324,26 +314,25 @@ public class GalleryViewer extends ContentViewer { //System.out.println(this + ".resized(" + refreshElementSizes + ")"); if (chassis.isDisposed()) return; - org.eclipse.swt.graphics.Rectangle b = chassis.getBounds(); + org.eclipse.swt.graphics.Rectangle b = SWTDPIUtil.upscaleSwt(chassis.getBounds()); + //System.out.println("chassis bounds: " + b); final Rectangle2D bounds = new Rectangle2D.Double(hMargin, vMargin, b.width-hMargin*2, b.height-vMargin*2); - ctx.getThreadAccess().asyncExec(new Runnable() { - @Override - public void run() { - if (ctx.isDisposed()) - return; - if (diagram == null) - return; - //System.out.println(this + ".resized(" + refreshElementSizes + ") AWT update"); - if (refreshElementSizes) - refreshElementSizes(); - fl.layout(diagram, bounds); - - // Makes sure RTreeNode is marked dirty and everything is - // properly repainted. - if (itemPainter != null) - itemPainter.updateAll(); - ctx.getContentContext().setDirty(); - }}); + ctx.getThreadAccess().asyncExec(() -> { + if (ctx.isDisposed()) + return; + if (diagram == null) + return; + //System.out.println(this + ".resized(" + refreshElementSizes + ") AWT update"); + if (refreshElementSizes) + refreshElementSizes(); + fl.layout(diagram, bounds); + + // Makes sure RTreeNode is marked dirty and everything is + // properly repainted. + if (itemPainter != null) + itemPainter.updateAll(); + ctx.getContentContext().setDirty(); + }); } /** @@ -392,12 +381,9 @@ public class GalleryViewer extends ContentViewer { // wrong thread (SWT) for AWTChassis. chassis.getAWTComponent().setCanvasContext(canvasContext); - swtThread.asyncExec(new Runnable() { - @Override - public void run() { - if (!chassis.isDisposed()) - chassis.setCanvasContext(canvasContext); - } + swtThread.asyncExec(() -> { + if (!chassis.isDisposed()) + chassis.setCanvasContext(canvasContext); }); canvasContext.assertParticipantDependencies(); @@ -573,12 +559,7 @@ public class GalleryViewer extends ContentViewer { // 3. Calculate maximum vertical space needed by current diagram element texts refreshElementSizes(); - ThreadUtils.asyncExec(swtThread, new Runnable() { - @Override - public void run() { - resized(false); - } - }); + ThreadUtils.asyncExec(swtThread, () -> resized(false)); // $AWT-Thread-End$ } }); @@ -609,9 +590,9 @@ public class GalleryViewer extends ContentViewer { // Calculate maximum vertical space needed by current diagram element texts FontMetrics metrics = awtComponent.getFontMetrics(currentItemFont); int fontHeight = metrics.getHeight(); - int maxWidth = (int) itemSize.getWidth(); - Rectangle2D size = itemSize; - java.awt.Point targetSize = new java.awt.Point((int) itemSize.getWidth(), (int) itemSize.getHeight()); + Rectangle2D size = SWTDPIUtil.upscaleSwt(itemSize); + int maxWidth = (int) size.getWidth(); + java.awt.Point targetSize = new java.awt.Point((int) size.getWidth(), (int) size.getHeight()); diagram.setHint(DiagramHints.KEY_ELEMENT_RASTER_TARGET_SIZE, targetSize); int maxLinesNeeded = 0; for (IElement el : diagram.getElements()) { @@ -619,7 +600,7 @@ public class GalleryViewer extends ContentViewer { // for caching rendered images in the correct size only. // NOTE: currently this is not used in GalleryItemPainter since the // target size is now propagated through the element class loading - // process through the diagram hint KEY_ELEMENT_RASTER_REFERENCE_SIZE. + // process through the diagram hint KEY_ELEMENT_RASTER_TARGET_SIZE. el.setHint(GalleryItemSGNode.KEY_TARGET_IMAGE_SIZE, targetSize); String text = ElementUtils.getText(el); @@ -647,14 +628,11 @@ public class GalleryViewer extends ContentViewer { if (image != i) continue; - ctx.getThreadAccess().asyncExec(new Runnable() { - @Override - public void run() { - //System.out.println(Thread.currentThread() + ": update scene graph(" + el + ")"); - // Update scene graph and repaint. - el.getElementClass().getSingleItem(GalleryItemSGNode.class).update(el); - ctx.getContentContext().setDirty(); - } + ctx.getThreadAccess().asyncExec(() -> { + //System.out.println(Thread.currentThread() + ": update scene graph(" + el + ")"); + // Update scene graph and repaint. + el.getElementClass().getSingleItem(GalleryItemSGNode.class).update(el); + ctx.getContentContext().setDirty(); }); break; } @@ -665,12 +643,9 @@ public class GalleryViewer extends ContentViewer { if (ctx.getThreadAccess().currentThreadAccess()) { ctx.add(p); } else { - ctx.getThreadAccess().asyncExec(new Runnable() { - @Override - public void run() { - if (!ctx.isDisposed()) - ctx.add(p); - } + ctx.getThreadAccess().asyncExec(() -> { + if (!ctx.isDisposed()) + ctx.add(p); }); } } @@ -679,12 +654,9 @@ public class GalleryViewer extends ContentViewer { if (ctx.getThreadAccess().currentThreadAccess()) { ctx.add(p); } else { - ctx.getThreadAccess().asyncExec(new Runnable() { - @Override - public void run() { - if (!ctx.isDisposed()) - ctx.add(p); - } + ctx.getThreadAccess().asyncExec(() -> { + if (!ctx.isDisposed()) + ctx.add(p); }); } } diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/FontHelper.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/FontHelper.java index 06bd80aa8..98d5c78f6 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/FontHelper.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/FontHelper.java @@ -12,11 +12,11 @@ package org.simantics.g2d.utils; import java.awt.Font; -import java.awt.Toolkit; import org.eclipse.jface.resource.FontRegistry; import org.eclipse.swt.graphics.FontData; import org.eclipse.ui.PlatformUI; +import org.simantics.utils.ui.SWTDPIUtil; public final class FontHelper { @@ -35,8 +35,7 @@ public final class FontHelper { } public static java.awt.Font toAwt(FontData fd) { - int resolution = Toolkit.getDefaultToolkit().getScreenResolution(); - int awtFontSize = (int) Math.round((double) fd.getHeight() * resolution / 72.0); + int awtFontSize = SWTDPIUtil.upscaleSwt(fd.getHeight()); // The style constants for SWT and AWT map exactly, and since they are int constants, they should // never change. So, the SWT style is passed through as the AWT style. Font font = new java.awt.Font(fd.getName(), fd.getStyle(), awtFontSize); diff --git a/bundles/org.simantics.jdbc.ontology/.classpath b/bundles/org.simantics.jdbc.ontology/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/bundles/org.simantics.jdbc.ontology/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.simantics.jdbc.ontology/.project b/bundles/org.simantics.jdbc.ontology/.project new file mode 100644 index 000000000..6668cd10e --- /dev/null +++ b/bundles/org.simantics.jdbc.ontology/.project @@ -0,0 +1,34 @@ + + + org.simantics.jdbc.ontology + + + + + + org.simantics.graph.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.simantics.graph.nature + + diff --git a/bundles/org.simantics.jdbc.ontology/.settings/org.eclipse.jdt.core.prefs b/bundles/org.simantics.jdbc.ontology/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/bundles/org.simantics.jdbc.ontology/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.simantics.jdbc.ontology/META-INF/MANIFEST.MF b/bundles/org.simantics.jdbc.ontology/META-INF/MANIFEST.MF new file mode 100644 index 000000000..69dae10ab --- /dev/null +++ b/bundles/org.simantics.jdbc.ontology/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: http://www.simantics.org/JDBC-1.0 +Bundle-SymbolicName: org.simantics.jdbc.ontology +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.simantics.jdbc.ontology.Activator +Require-Bundle: org.eclipse.core.runtime, + org.simantics.layer0, + org.simantics.selectionview.ontology;bundle-version="1.2.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ActivationPolicy: lazy +Export-Package: org.simantics.jdbc diff --git a/bundles/org.simantics.jdbc.ontology/build.properties b/bundles/org.simantics.jdbc.ontology/build.properties new file mode 100644 index 000000000..e85b630a0 --- /dev/null +++ b/bundles/org.simantics.jdbc.ontology/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + graph.tg diff --git a/bundles/org.simantics.jdbc.ontology/graph/JDBC.pgraph b/bundles/org.simantics.jdbc.ontology/graph/JDBC.pgraph new file mode 100644 index 000000000..432e10c88 --- /dev/null +++ b/bundles/org.simantics.jdbc.ontology/graph/JDBC.pgraph @@ -0,0 +1,10 @@ +L0 = +SEL = + +JDBC = : L0.Ontology + @L0.new + L0.HasResourceClass "org.simantics.jdbc.JDBCResource" + +JDBC.Session -- JDBC.Session.hasValue --> L0.Value + + + + + + diff --git a/bundles/org.simantics.jdbc/.project b/bundles/org.simantics.jdbc/.project new file mode 100644 index 000000000..3af9a2f8f --- /dev/null +++ b/bundles/org.simantics.jdbc/.project @@ -0,0 +1,34 @@ + + + org.simantics.jdbc + + + + + + org.simantics.graph.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.simantics.graph.nature + + diff --git a/bundles/org.simantics.jdbc/.settings/org.eclipse.jdt.core.prefs b/bundles/org.simantics.jdbc/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/bundles/org.simantics.jdbc/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.simantics.jdbc/META-INF/MANIFEST.MF b/bundles/org.simantics.jdbc/META-INF/MANIFEST.MF new file mode 100644 index 000000000..9aff2f490 --- /dev/null +++ b/bundles/org.simantics.jdbc/META-INF/MANIFEST.MF @@ -0,0 +1,24 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Simantics JDBC support +Bundle-SymbolicName: org.simantics.jdbc +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ClassPath: . +Require-Bundle: org.eclipse.osgi, + org.simantics.simulator.toolkit, + org.simantics.databoard, + gnu.trove3;bundle-version="3.0.3", + org.slf4j.api;bundle-version="1.7.25", + org.simantics.db.layer0, + org.simantics.simulator.toolkit.db, + org.simantics, + org.simantics.jdbc.ontology, + io.netty.buffer;bundle-version="4.1.27", + io.netty.codec;bundle-version="4.1.27", + io.netty.common;bundle-version="4.1.27", + io.netty.handler;bundle-version="4.1.27", + io.netty.transport;bundle-version="4.1.27", + pgjdbc-ng;bundle-version="0.7.1" +Export-Package: org.simantics.jdbc, + org.simantics.jdbc.variable diff --git a/bundles/org.simantics.jdbc/adapters.xml b/bundles/org.simantics.jdbc/adapters.xml new file mode 100644 index 000000000..800ee1461 --- /dev/null +++ b/bundles/org.simantics.jdbc/adapters.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/bundles/org.simantics.jdbc/build.properties b/bundles/org.simantics.jdbc/build.properties new file mode 100644 index 000000000..0dc8dce86 --- /dev/null +++ b/bundles/org.simantics.jdbc/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + adapters.xml,\ + jdbc.properties diff --git a/bundles/org.simantics.jdbc/jdbc.properties b/bundles/org.simantics.jdbc/jdbc.properties new file mode 100644 index 000000000..7f23859a1 --- /dev/null +++ b/bundles/org.simantics.jdbc/jdbc.properties @@ -0,0 +1,5 @@ +simantics.jdbc.host=127.0.0.1 +simantics.jdbc.port=5432 +simantics.jdbc.user=simantics +simantics.jdbc.password=simantics +simantics.jdbc.database=simantics \ No newline at end of file diff --git a/bundles/org.simantics.jdbc/src/org/simantics/jdbc/SimanticsJDBC.java b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/SimanticsJDBC.java new file mode 100644 index 000000000..ac287e6e4 --- /dev/null +++ b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/SimanticsJDBC.java @@ -0,0 +1,45 @@ +package org.simantics.jdbc; + +import org.simantics.databoard.Bindings; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.Layer0Utils; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.layer0.variable.Variables; +import org.simantics.layer0.Layer0; + +/** + * Simantics JDBC facade. + * + * @author Jani Simomaa + */ +public class SimanticsJDBC { + + public static final String PROP_SIMANTICS_JDBC_PROPERTYFILE = "simantics.jdbc.propertyfile"; + public static final String PROP_SIMANTICS_JDBC_HOST = "simantics.jdbc.host"; + public static final String PROP_SIMANTICS_JDBC_PORT = "simantics.jdbc.port"; + public static final String PROP_SIMANTICS_JDBC_USER = "simantics.jdbc.user"; + public static final String PROP_SIMANTICS_JDBC_PASSWORD = "simantics.jdbc.password"; + public static final String PROP_SIMANTICS_JDBC_DATABASE = "simantics.jdbc.database"; + + public static String createJDBCSession(WriteGraph graph, String sessionGUID) throws DatabaseException { + Resource projects = graph.getResource("http://Projects"); + Resource documentSessions = Layer0Utils.getPossibleChild(graph, projects, "DocumentSessions"); + Layer0 L0 = Layer0.getInstance(graph); + Resource documentSession = Layer0Utils.getPossibleChild(graph, documentSessions, sessionGUID); + + String sessionId = "http://Projects/DocumentSessions/" + sessionGUID + "/__jdbc__"; + + JDBCResource JDBC = JDBCResource.getInstance(graph); + Resource jdbcSession = graph.newResource(); + graph.claim(jdbcSession, L0.InstanceOf, JDBC.Session); + graph.claimLiteral(jdbcSession, L0.HasName, L0.NameOf, L0.String, "__jdbc__", Bindings.STRING); + graph.claim(documentSession, L0.ConsistsOf, jdbcSession); + + @SuppressWarnings("unused") + Variable jdbcState = Variables.getVariable(graph, jdbcSession); + + return sessionId; + } +} diff --git a/bundles/org.simantics.jdbc/src/org/simantics/jdbc/internal/Activator.java b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/internal/Activator.java new file mode 100644 index 000000000..0f9da36d7 --- /dev/null +++ b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/internal/Activator.java @@ -0,0 +1,18 @@ +package org.simantics.jdbc.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + @Override + public void start(BundleContext context) throws Exception { + + } + + @Override + public void stop(BundleContext context) throws Exception { + + } + +} diff --git a/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNode.java b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNode.java new file mode 100644 index 000000000..54f5d3947 --- /dev/null +++ b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNode.java @@ -0,0 +1,41 @@ +package org.simantics.jdbc.variable; + +import org.simantics.simulator.toolkit.StandardNode; + +public class JDBCNode implements StandardNode { + + public String name; + + public JDBCNode(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + JDBCNode other = (JDBCNode) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } +} diff --git a/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNodeManager.java b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNodeManager.java new file mode 100644 index 000000000..fd2585211 --- /dev/null +++ b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNodeManager.java @@ -0,0 +1,21 @@ +package org.simantics.jdbc.variable; + +import java.util.Collections; +import java.util.Set; + +import org.simantics.simulator.toolkit.StandardNodeManager; +import org.simantics.simulator.toolkit.StandardRealm; +import org.simantics.simulator.variable.exceptions.NodeManagerException; + +public class JDBCNodeManager extends StandardNodeManager { + + public JDBCNodeManager(StandardRealm realm, JDBCNode root) { + super(realm, root); + } + + @Override + public Set getClassifications(JDBCNode node) throws NodeManagerException { + return Collections.emptySet(); + } + +} diff --git a/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNodeManagerSupport.java b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNodeManagerSupport.java new file mode 100644 index 000000000..b1c16a6df --- /dev/null +++ b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCNodeManagerSupport.java @@ -0,0 +1,123 @@ +package org.simantics.jdbc.variable; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.simantics.databoard.Bindings; +import org.simantics.databoard.binding.Binding; +import org.simantics.simulator.toolkit.StandardNodeManagerSupport; +import org.simantics.simulator.variable.exceptions.NodeManagerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.impossibl.postgres.api.jdbc.PGConnection; +import com.impossibl.postgres.jdbc.PGDataSource; + +public class JDBCNodeManagerSupport implements StandardNodeManagerSupport { + + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCNodeManagerSupport.class); + @SuppressWarnings("unused") + private String id; // this might have some use later in the future? + private PGDataSource dataSource; + private String channelName; + + public JDBCNodeManagerSupport(String id, PGDataSource dataSource, String channelName) { + this.id = id; + this.dataSource = dataSource; + this.channelName = channelName; + } + + @Override + public Object getEngineValue(JDBCNode node) throws NodeManagerException { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Getting value for {}", node.getName()); + + try (PGConnection connection = (PGConnection) dataSource.getConnection()) { + // do get value + PreparedStatement ps = connection.prepareStatement("SELECT value->'value' FROM simantics_table WHERE key IN ('" + node.getName() + "');"); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("no value for query {}", ps.toString()); + } + return null; + } + return rs.getObject(1); + } catch (Exception e) { + LOGGER.error("Failed to get value for {}", node.getName(), e); + throw new NodeManagerException("Failed to get value for " + node.getName(), e); + } + } + + @Override + public Binding getEngineBinding(JDBCNode node) throws NodeManagerException { + return Bindings.OBJECT; + } + + @Override + public void setEngineValue(JDBCNode node, Object value) throws NodeManagerException { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Setting value for {} to {}", node.getName(), value); + + setValueImpl(node.getName(), value); + } + + private void setValueImpl(String name, Object value) throws NodeManagerException { + try (PGConnection connection = (PGConnection) dataSource.getConnection()) { + // do set value + PreparedStatement statement = connection.prepareStatement("INSERT INTO simantics_table VALUES (?, ?::JSON) ON CONFLICT (key) DO UPDATE SET value= ?::JSON"); + statement.setString(1, name); + statement.setObject(2, "{\"value\": " + value.toString() + "}"); + statement.setObject(3, "{\"value\": " + value.toString() + "}"); + statement.executeUpdate(); + + // notify others (including ourselves) + doNotify(connection, name); + } catch (Exception e) { + LOGGER.error("Failed to set value for {} to {}", name, value, e); + throw new NodeManagerException("Failed to set value for " + name + " to " + String.valueOf(value), e); + } + } + + private void doNotify(PGConnection connection, String name) throws SQLException { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Notifying change {} to channel {}", name, this.channelName); + Statement statement = connection.createStatement(); + String sql = "NOTIFY " + this.channelName + ", '" + name + "'"; + statement.execute(sql); + statement.close(); + } + + @Override + public String getName(JDBCNode node) { + return node.getName(); + } + + @Override + public Map getChildren(JDBCNode node) { + return Collections.emptyMap(); + } + + @Override + public Map getProperties(JDBCNode node) { + HashMap properties = new HashMap<>(); + try (PGConnection connection = (PGConnection) dataSource.getConnection()) { + Statement st = connection.createStatement(); + ResultSet executeQuery = st.executeQuery("SELECT key FROM simantics_table"); + while (executeQuery.next()) { + String key = executeQuery.getString(1); + properties.put(key, new JDBCNode(key)); + } + } catch (Exception e) { + LOGGER.error("Could not read properties", e); + } + + return properties; + } + +} diff --git a/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCRealm.java b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCRealm.java new file mode 100644 index 000000000..9a6f4ab15 --- /dev/null +++ b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCRealm.java @@ -0,0 +1,28 @@ +package org.simantics.jdbc.variable; + +import org.simantics.simulator.toolkit.StandardNodeManager; +import org.simantics.simulator.toolkit.StandardRealm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JDBCRealm extends StandardRealm { + + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCRealm.class); + + protected JDBCRealm(JDBCNodeManagerSupport engine, String id) { + super(engine, id); + } + + @Override + protected StandardNodeManager createManager() { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Creating {} for realm with id {}", JDBCNodeManager.class.getSimpleName(), getId()); + return new JDBCNodeManager(this, new JDBCNode("ROOT")); + } + + @Override + public Logger getLogger() { + return LOGGER; + } + +} diff --git a/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCSessionManager.java b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCSessionManager.java new file mode 100644 index 000000000..f6a6077e4 --- /dev/null +++ b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCSessionManager.java @@ -0,0 +1,208 @@ +package org.simantics.jdbc.variable; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; +import java.util.function.Function; + +import org.simantics.Simantics; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.binding.error.BindingException; +import org.simantics.db.ReadGraph; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.NodeSupport; +import org.simantics.jdbc.SimanticsJDBC; +import org.simantics.simulator.toolkit.StandardRealm; +import org.simantics.simulator.toolkit.db.StandardSessionManager; +import org.simantics.simulator.variable.exceptions.NodeManagerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.impossibl.postgres.api.jdbc.PGConnection; +import com.impossibl.postgres.api.jdbc.PGNotificationListener; +import com.impossibl.postgres.jdbc.PGDataSource; + +public class JDBCSessionManager extends StandardSessionManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCSessionManager.class); + private static JDBCSessionManager INSTANCE = new JDBCSessionManager(); + + private static final String VALUE_SIMANTICS_JDBC_HOST = "localhost"; + private static final int VALUE_SIMANTICS_JDBC_PORT = 5432; + private static final String VALUE_SIMANTICS_JDBC_USER = "simantics"; + private static final String VALUE_SIMANTICS_JDBC_PASSWORD = "simantics"; + private static final String VALUE_SIMANTICS_JDBC_DATABASE = "simantics"; + + private String channelName; + private PGNotificationListener listener; + + private PGDataSource dataSource; + private Connection connection; + + private static Properties readProperties(InputStream s) throws IOException { + try (InputStream is = s) { + Properties props = new Properties(); + props.load(is); + return props; + } + } + + private static Properties safeReadProperties(URL url) { + try { + return readProperties(url.openStream()); + } catch (IOException e) { + LOGGER.error("Could not read props from " + url, e); + return null; + } + } + + private static Properties safeReadProperties(URI uri) { + try { + return safeReadProperties(uri.toURL()); + } catch (MalformedURLException e) { + LOGGER.error("Could not read props from " + uri, e); + return null; + } + } + + private static Properties safeReadProperties(String path) { + return safeReadProperties(Paths.get(path).toUri()); + } + + private static Properties readProperties() { + String propFile = System.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_PROPERTYFILE, null); + if (propFile != null) { + Properties p = safeReadProperties(propFile); + if (p != null) + return p; + } + // Read default settings from built-in file and override them with values in System properties + Properties p = safeReadProperties(JDBCSessionManager.class.getClassLoader().getResource("jdbc.properties")); + if (p != null) { + p.putAll(System.getProperties()); + } else { + p = System.getProperties(); + } + return p; + } + + public JDBCSessionManager() { + this.channelName = "test"; + + Properties props = readProperties(); + String host = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_HOST, VALUE_SIMANTICS_JDBC_HOST); + String port = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_PORT, "" + VALUE_SIMANTICS_JDBC_PORT); + String database = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_DATABASE, VALUE_SIMANTICS_JDBC_DATABASE); + String user = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_USER, VALUE_SIMANTICS_JDBC_USER); + String password = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_PASSWORD, VALUE_SIMANTICS_JDBC_PASSWORD); + + try { + int portNumber = Integer.valueOf(port); + + dataSource = new PGDataSource(); + dataSource.setHost(host); + dataSource.setPort(portNumber); + dataSource.setDatabase(database); + dataSource.setUser(user); + dataSource.setPassword(password); + + this.connection = dataSource.getConnection(); + this.listener = new PGNotificationListener() { + @Override + public void notification(int processId, String channelName, String payload) { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Received notification from processId={} channelName={} and payload={}", processId, channelName, payload); + Simantics.getSession().asyncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + for (String realmId : INSTANCE.getRealms()) { + try { + JDBCRealm jdbcRealm = (JDBCRealm) INSTANCE.getOrCreateRealm(graph, realmId); + jdbcRealm.getNodeManager().refreshVariable(new JDBCNode(payload)); + } catch (DatabaseException e) { + LOGGER.error("Could not refresh variable in realm {} with payload {}", realmId, payload, e); + } + } + } + }); + } + }; + createTable(); + init(); + } catch (SQLException e) { + LOGGER.error("Could not initialize JDBCSessionManager!", e); + } + } + + private void createTable() throws SQLException { + Statement statement = connection.createStatement(); + statement.execute("CREATE TABLE IF NOT EXISTS simantics_table (key VARCHAR UNIQUE, value JSON)"); + statement.close(); + } + + protected void init() throws SQLException { + Statement statement = connection.createStatement(); + statement.execute("LISTEN " + this.channelName); + statement.close(); + ((PGConnection) connection).addNotificationListener(this.listener); + } + + protected void destroy() throws SQLException { + try (PGConnection connection = (PGConnection) dataSource.getConnection()) { + Statement statement = connection.createStatement(); + statement.execute("UNLISTEN " + this.channelName); + statement.close(); + } + } + + + @Override + protected JDBCNodeManagerSupport createEngine(ReadGraph graph, String id) throws DatabaseException { + return new JDBCNodeManagerSupport(id, this.dataSource, this.channelName); + } + + @Override + protected StandardRealm createRealm(JDBCNodeManagerSupport engine, String id) { + return new JDBCRealm(engine, id); + } + + public static void setValue(ReadGraph graph, String id, String key, Object value) throws DatabaseException, NodeManagerException, BindingException, InterruptedException { + JDBCRealm realm = (JDBCRealm) INSTANCE.getOrCreateRealm(graph, id); + realm.asyncExec(() -> { + try { + realm.getNodeManager().setValue(new JDBCNode(key), key, value, Bindings.OBJECT); + } catch (NodeManagerException | BindingException e) { + LOGGER.error("Could not set value {} for {}", value, key, e); + } + }); + } + + public static NodeSupport nodeSupport(ReadGraph graph, String sessionName) throws DatabaseException { + return INSTANCE.getOrCreateNodeSupport(graph, sessionName); + } + + public static Object getValue(ReadGraph graph, String uri, String key) throws InterruptedException, DatabaseException { + JDBCRealm realm = (JDBCRealm) INSTANCE.getOrCreateRealm(graph, uri); + return realm.syncExec(new Function() { + + @Override + public Object apply(Object t) { + try { + return realm.getNodeManager().getValue(new JDBCNode(key), key).getValue(); + } catch (NodeManagerException e) { + LOGGER.error("Could not get value for {}", key, e); + return null; + } + } + }); + } + +} diff --git a/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCVariableBuilder.java b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCVariableBuilder.java new file mode 100644 index 000000000..c633fd71e --- /dev/null +++ b/bundles/org.simantics.jdbc/src/org/simantics/jdbc/variable/JDBCVariableBuilder.java @@ -0,0 +1,21 @@ +package org.simantics.jdbc.variable; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.NodeManagerVariableBuilder; +import org.simantics.db.layer0.variable.NodeSupport; + +public class JDBCVariableBuilder extends NodeManagerVariableBuilder { + + @Override + protected NodeSupport getNodeSupport(ReadGraph graph, String sessionName) throws DatabaseException { + return JDBCSessionManager.nodeSupport(graph, sessionName); + } + + @Override + protected Object getRoot(ReadGraph graph, NodeSupport support, String sessionName) throws DatabaseException { + JDBCNodeManager manager = (JDBCNodeManager) support.manager; + return manager.getRoot(); + } + +} diff --git a/bundles/org.simantics.layer0/graph/Layer0.pgraph b/bundles/org.simantics.layer0/graph/Layer0.pgraph index 5fe74ec01..225a4f17e 100644 --- a/bundles/org.simantics.layer0/graph/Layer0.pgraph +++ b/bundles/org.simantics.layer0/graph/Layer0.pgraph @@ -22,6 +22,7 @@ L0.Entity : L0.Type >-- L0.identifier L0.GUID + ==> "GUID" >-- L0.typeURI L0.String @@ -42,7 +43,7 @@ L0.Entity : L0.Type @L0.assert L0.Entity.methods _ : L0.Value -L0.Entity.methods --> L0.Value "StructuredProperty" selectedObjects) throws DatabaseException { - - final Resource diagram = getDiagram(g, r, selectedObjects); - if (diagram == null) - return false; - - final Resource configurationComposite = ComponentUtils.getPossibleDiagramComposite(g, diagram); - if (configurationComposite == null) - return false; - - Pair modelAndRVI = getModelAndRVI(g, configurationComposite); + public static boolean openEditor(ReadGraph g, Resource r, String editorId, Collection selectedObjects) throws DatabaseException { + Resource diagram = getDiagram(g, r, selectedObjects); + Resource configurationComposite = diagram != null ? ComponentUtils.getPossibleDiagramComposite(g, diagram) : null; + Pair modelAndRVI = configurationComposite != null ? getModelAndRVI(g, configurationComposite) : null; //System.out.println("modelAndRVI: " + modelAndRVI); if (modelAndRVI == null) return false; + scheduleOpenEditor(editorId, diagram, modelAndRVI.first, modelAndRVI.second, selectedObjects); + return true; + } + + /** + * @param g + * @param configurationComposite + * @param editorId + * @param selectedObjects + * @throws DatabaseException + */ + public static boolean openEditor(ReadGraph g, Resource r, String editorId, Collection selectedObjects, Resource model, RVI rvi) throws DatabaseException { + Resource diagram = getDiagram(g, r, selectedObjects); + if (diagram == null) + return false; + scheduleOpenEditor(editorId, diagram, model, rvi, selectedObjects); + return true; + } - final Runnable editorActivator = NavigateToTarget.editorActivator(editorId, diagram, modelAndRVI.first, modelAndRVI.second, part -> { + /** + * @param g + * @param configurationComposite + * @param editorId + * @param selectedObjects + * @throws DatabaseException + */ + private static void scheduleOpenEditor(String editorId, Resource diagram, Resource model, RVI rvi, Collection selectedObjects) throws DatabaseException { + Runnable editorActivator = NavigateToTarget.editorActivator(editorId, diagram, model, rvi, part -> { if (selectedObjects.isEmpty()) return; - - final ICanvasContext openedCanvas = (ICanvasContext) part.getAdapter(ICanvasContext.class); + ICanvasContext openedCanvas = (ICanvasContext) part.getAdapter(ICanvasContext.class); assert openedCanvas != null; // CanvasContext-wide denial of initial zoom-to-fit on diagram open. openedCanvas.getDefaultHintContext().setHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT, Boolean.FALSE); - //System.out.println("ASDF: " + element); ThreadUtils.asyncExec(openedCanvas.getThreadAccess(), NavigateToTarget.elementSelectorZoomer(openedCanvas, selectedObjects, false)); }); - - PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - editorActivator.run(); - } - }); - - return true; + PlatformUI.getWorkbench().getDisplay().asyncExec(editorActivator); } } diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLTypeUtils.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLTypeUtils.java index 9632090e3..d0a777caa 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLTypeUtils.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLTypeUtils.java @@ -60,6 +60,9 @@ public class SCLTypeUtils { TYPE_MAP.put("ByteArray", Types.BYTE_ARRAY); add((TCon)Types.RESOURCE); + add(Types.con("Simantics/GUID", "GUID")); // L0.GUID + add(Types.con("Simantics/Variables", "StructuredProperty")); // L0.methods + add(Types.con("Simantics/Variables", "ValueAccessor")); // L0.ValueAccessor add(Types.con("Simantics/Variables", "VariableMap")); } diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java index 7c1fe461a..8a0b1ddbc 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java @@ -459,6 +459,8 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { private boolean isSynchronizedConnector(ReadGraph graph, Resource templateConnection, Resource instanceConnector) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); Resource instanceConnection = graph.getPossibleObject(instanceConnector, DIA.IsConnectorOf); + if (instanceConnection == null) + return false; return graph.hasStatement(instanceConnection, MOD.HasElementSource, templateConnection) // If the master connection has been removed, this is all that's left // to identify a connection that at least was originally synchronized diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/names/SCLReservedWords.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/names/SCLReservedWords.java new file mode 100644 index 000000000..7f6f80b15 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/names/SCLReservedWords.java @@ -0,0 +1,65 @@ +package org.simantics.scl.compiler.common.names; + +import java.io.StringReader; + +import org.simantics.scl.compiler.internal.parsing.Token; +import org.simantics.scl.compiler.internal.parsing.parser.SCLLexer; +import org.simantics.scl.compiler.internal.parsing.parser.SCLTerminals; + +import gnu.trove.set.hash.THashSet; + +public class SCLReservedWords { + public static final String[] RESERVED_WORDS_ARRAY = { + "as", + "by", + "do", + "if", + "in", + "edo", + "let", + "mdo", + "data", + "else", + "rule", + "then", + "type", + "when", + "with", + "class", + "infix", + "match", + "where", + "effect", + "forall", + "hiding", + "import", + "infixl", + "infixr", + "select", + "enforce", + "include", + "ruleset", + "deriving", + "instance", + "constraint", + "importJava", + "transformation", + }; + + public static final THashSet RESERVED_WORDS_SET = new THashSet<>(); + + static { + for(String word : RESERVED_WORDS_ARRAY) + RESERVED_WORDS_SET.add(word); + } + + public static boolean isReserved(String str) { + try { + SCLLexer lexer = new SCLLexer(new StringReader(str)); + Token token = lexer.nextToken(); + return token.id != SCLTerminals.ID; + } catch(Exception e) { + return true; + } + } +} diff --git a/bundles/org.simantics.scl.db/scl/Simantics/Variables.scl b/bundles/org.simantics.scl.db/scl/Simantics/Variables.scl index 12d06b76b..43be6defb 100644 --- a/bundles/org.simantics.scl.db/scl/Simantics/Variables.scl +++ b/bundles/org.simantics.scl.db/scl/Simantics/Variables.scl @@ -96,6 +96,9 @@ importJava "org.simantics.db.layer0.function.All" where importJava "org.simantics.db.layer0.variable.VariableMap" where data VariableMap +importJava "org.simantics.db.layer0.variable.StructuredProperty" where + data StructuredProperty + importJava "org.simantics.db.layer0.variable.ResourceCollectionVariableMap" where @JavaName "" createVariableMap :: [Resource] -> VariableMap diff --git a/bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentRuns.java b/bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentRuns.java index 21fcf2c26..5edf6c856 100644 --- a/bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentRuns.java +++ b/bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentRuns.java @@ -82,6 +82,37 @@ public class ExperimentRuns { final IExperimentActivationListener listener, final Function2 externalWrite, final Consumer successCallback) + { + createRun(session, vg, + experimentResource, experiment, experimentRunTypeURI, + listener, externalWrite, successCallback, true); + } + + /** + * Create new experiment run in a selected virtual graph. + * + * @param session + * @param vg + * @param experimentResource + * @param experiment + * @param experimentRunTypeURI + * @param listener + * @param successCallback if non-null invoked with the created run resource + * as an argument, just before invoking + * listener.onExperimentActivated(experiment) + * @param attachDeactivationListener true to run for the created run-resource + * {@link #attachStateListener(Session, IExperiment, Resource)} + */ + public static void createRun( + Session session, + VirtualGraph vg, + Resource experimentResource, + IExperiment experiment, + String experimentRunTypeURI, + IExperimentActivationListener listener, + Function2 externalWrite, + Consumer successCallback, + boolean attachDeactivationListener) { final AtomicReference run = new AtomicReference<>(); session.asyncRequest(new WriteRequest(vg) { @@ -97,7 +128,8 @@ public class ExperimentRuns { else ErrorLogger.defaultLogError(e); } else { - attachStateListener(session, experiment, run.get()); + if (attachDeactivationListener) + attachStateListener(session, experiment, run.get()); if (successCallback != null) successCallback.accept(run.get()); if (listener != null) diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ActualConnectionDescriptor.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ActualConnectionDescriptor.java index 716d4a001..f79bdb0b5 100644 --- a/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ActualConnectionDescriptor.java +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ActualConnectionDescriptor.java @@ -94,7 +94,7 @@ class ActualConnectionDescriptor extends AbstractVariableConnectionPointDescript StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource type = graph.getPossibleType(component, STR.Component); - return graph.syncRequest(new IsLeafType(type)); + return type != null ? graph.syncRequest(new IsLeafType(type)) : false; } diff --git a/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorPart.java b/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorPart.java index 1cd72de63..ca06a5d7b 100644 --- a/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorPart.java +++ b/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorPart.java @@ -20,7 +20,10 @@ import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PartInitException; +import org.eclipse.ui.internal.PartSite; +import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor; import org.eclipse.ui.part.EditorPart; import org.simantics.Simantics; import org.simantics.db.Resource; @@ -98,11 +101,25 @@ public abstract class ResourceEditorPart extends EditorPart implements IResource * @param partName */ protected void safeSetPartName(String partName) { - if (!disposed) { + if (!disposed && checkCompatibilityPartNotBeingDisposed()) { // this is to fix bug https://gitlab.simantics.org/simantics/platform/issues/117 setPartName(partName); } } + @SuppressWarnings("restriction") + private boolean checkCompatibilityPartNotBeingDisposed() { + IWorkbenchPartSite site = getSite(); + if (site instanceof PartSite) { + PartSite partSite = (PartSite) getSite(); + Object object = partSite.getModel().getObject(); + if (object instanceof CompatibilityEditor) { + CompatibilityEditor editor = (CompatibilityEditor) object; + return !editor.isBeingDisposed(); + } + } + return true; + } + /** * Safely sets title tooltip for parts whose IEditorInput is not yet disposed (e.g. * removed from database) diff --git a/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTDPIUtil.java b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTDPIUtil.java new file mode 100644 index 000000000..0fe51a9f2 --- /dev/null +++ b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTDPIUtil.java @@ -0,0 +1,261 @@ +package org.simantics.utils.ui; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.DPIUtil; + +/** + * This class is needed to support {@link SWTAWTComponent} and HiDPI screens + * with different display zoom settings. + * + *

+ * See {@link DPIUtil} for explanations on what downscaling and upscaling are in + * this context. If user has zoom > 100% in use in the system display settings, + * SWT's API coordinates will be "downscaled" from actual internal HiDPI + * coordinates (pixels). + * + *

+ * This class contains methods to work around problems with e.g. opening context + * menu's in the correct location when using {@link SWTAWTComponent}. AWT always + * returns HiDPI pixel coordinates which need to be converted to SWT API + * coordinates before giving them to any SWT APIs. + * + * @author Tuukka Lehtonen + * @since 1.36.0 + */ +@SuppressWarnings("restriction") +public class SWTDPIUtil { + + private static boolean initialized = false; + private static int swtZoom; + private static boolean hasSwtScale; + + private static float fromSwtInternalScalingFactorF; + private static double fromSwtInternalScalingFactorD; + private static float toSwtInternalScalingFactorF; + private static double toSwtInternalScalingFactorD; + + private static void initialize() { + if (initialized) + return; + + swtZoom = DPIUtil.autoScaleUp(100); + hasSwtScale = swtZoom != 100; + + fromSwtInternalScalingFactorD = 100.0 / (double) swtZoom; + toSwtInternalScalingFactorD = (double) swtZoom / 100.0; + fromSwtInternalScalingFactorF = (float) fromSwtInternalScalingFactorD; + toSwtInternalScalingFactorF = (float) toSwtInternalScalingFactorD; + +// System.out.format("SWTDPIUtil:%n\tswt zoom = %d%n\tfrom swt internal scaling factor = %f%n\tto swt internal scaling factor = %f%n", +// swtZoom, +// fromSwtInternalScalingFactorD, +// toSwtInternalScalingFactorD, +// ); + + initialized = true; + } + + // Internals + + private static Rectangle scale(float s, Rectangle r, Rectangle target) { + if (s == 1.0f) { + if (r == target) + return r; + if (target == null) { + return new Rectangle(r.x, r.y, r.width, r.height); + } else { + target.x = r.x; + target.y = r.y; + target.width = r.width; + target.height = r.height; + return target; + } + } + if (target == null) { + return new Rectangle( + Math.round(r.x*s), + Math.round(r.y*s), + Math.round(r.width*s), + Math.round(r.height*s)); + } else { + target.x = Math.round(r.x*s); + target.y = Math.round(r.y*s); + target.width = Math.round(r.width*s); + target.height = Math.round(r.height*s); + return target; + } + } + + private static Rectangle2D scale(double s, Rectangle2D r, Rectangle2D target) { + if (s == 1.0) { + if (r == target) + return r; + if (target == null) + return (Rectangle2D) r.clone(); + target.setFrame(r); + return target; + } + if (target == null) + target = (Rectangle2D) r.clone(); + target.setFrame(r.getX()*s, r.getY()*s, r.getWidth()*s, r.getHeight()*s); + return target; + } + + private static double downscaleSwt0(double x) { + return hasSwtScale ? x * fromSwtInternalScalingFactorD : x; + } + + private static int downscaleToIntegerSwt0(double x) { + return (int)(hasSwtScale ? Math.round((double) x * fromSwtInternalScalingFactorD) : x); + } + + private static int downscaleSwt0(int x) { + return hasSwtScale ? (int) Math.round((double) x * fromSwtInternalScalingFactorD) : x; + } + + private static double upscaleSwt0(double x) { + return hasSwtScale ? x * toSwtInternalScalingFactorD : x; + } + + private static int upscaleToIntegerSwt0(double x) { + return (int)(hasSwtScale ? Math.round((double) x * toSwtInternalScalingFactorD) : x); + } + + private static int upscaleSwt0(int x) { + return hasSwtScale ? (int) Math.round((double) x * toSwtInternalScalingFactorD) : x; + } + + // SWT API Coordinates <-> pixels + + // Downscaling + + public static double downscaleSwt(double x) { + initialize(); + return downscaleSwt0(x); + } + + public static int downscaleSwt(int x) { + initialize(); + return downscaleSwt0(x); + } + + public static Point2D downscaleSwt(double x, double y) { + initialize(); + if (!hasSwtScale) + return new Point2D.Double(x, y); + double s = fromSwtInternalScalingFactorD; + return new Point2D.Double(x * s, y * s); + } + + public static Point downscaleSwt(int x, int y) { + initialize(); + return new Point(downscaleSwt0(x), downscaleSwt0(y)); + } + + public static Point2D downscaleSwt(Point2D p) { + return downscaleSwt(p.getX(), p.getY()); + } + + public static Point downscaleSwtToInteger(Point2D p) { + initialize(); + return new Point(downscaleToIntegerSwt0(p.getX()), downscaleToIntegerSwt0(p.getY())); + } + + public static Rectangle2D downscaleSwt(Rectangle2D r, Rectangle2D target) { + initialize(); + return scale(fromSwtInternalScalingFactorD, r, target); + } + + public static Rectangle2D downscaleSwt(Rectangle2D r) { + return downscaleSwt(r, null); + } + + public static Rectangle downscaleSwt(Rectangle r, Rectangle target) { + initialize(); + return scale(fromSwtInternalScalingFactorF, r, target); + } + + public static Rectangle downscaleSwt(Rectangle r) { + return downscaleSwt(r, null); + } + + public static Rectangle downscaleSwtToInteger(Rectangle2D r) { + initialize(); + return new Rectangle( + downscaleToIntegerSwt0(r.getMinX()), + downscaleToIntegerSwt0(r.getMinY()), + downscaleToIntegerSwt0(r.getWidth()), + downscaleToIntegerSwt0(r.getHeight())); + } + + // Upscaling + + public static double upscaleSwt(double x) { + initialize(); + return upscaleSwt0(x); + } + + public static int upscaleSwt(int x) { + initialize(); + return upscaleSwt0(x); + } + + public static Point2D upscaleSwt(double x, double y) { + initialize(); + if (!hasSwtScale) + return new Point2D.Double(x, y); + double s = toSwtInternalScalingFactorD; + return new Point2D.Double(x * s, y * s); + } + + public static Point upscaleSwt(int x, int y) { + initialize(); + return new Point(upscaleSwt0(x), upscaleSwt0(y)); + } + + public static Point2D upscaleSwt(Point2D p) { + initialize(); + return (hasSwtScale && p != null) ? upscaleSwt(p.getX(), p.getY()) : p; + } + + public static Point upscaleSwtToInteger(Point2D p) { + initialize(); + return new Point(upscaleToIntegerSwt0(p.getX()), upscaleToIntegerSwt0(p.getY())); + } + + public static Point upscaleSwt(Point p) { + initialize(); + return (hasSwtScale && p != null) ? upscaleSwt(p.x, p.y) : p; + } + + public static Rectangle2D upscaleSwt(Rectangle2D r, Rectangle2D target) { + initialize(); + return scale(toSwtInternalScalingFactorD, r, target); + } + + public static Rectangle upscaleSwt(Rectangle r, Rectangle target) { + initialize(); + return scale(toSwtInternalScalingFactorF, r, target); + } + + public static Rectangle2D upscaleSwt(Rectangle2D r) { + return upscaleSwt(r, null); + } + + public static Rectangle upscaleSwt(Rectangle r) { + return upscaleSwt(r, null); + } + + public static Rectangle upscaleSwtToInteger(Rectangle2D r) { + return new Rectangle( + upscaleToIntegerSwt0(r.getMinX()), + upscaleToIntegerSwt0(r.getMinY()), + upscaleToIntegerSwt0(r.getWidth()), + upscaleToIntegerSwt0(r.getHeight())); + } + +} diff --git a/features/org.simantics.jdbc.feature/.project b/features/org.simantics.jdbc.feature/.project new file mode 100644 index 000000000..0d1872076 --- /dev/null +++ b/features/org.simantics.jdbc.feature/.project @@ -0,0 +1,17 @@ + + + org.simantics.jdbc.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/features/org.simantics.jdbc.feature/build.properties b/features/org.simantics.jdbc.feature/build.properties new file mode 100644 index 000000000..64f93a9f0 --- /dev/null +++ b/features/org.simantics.jdbc.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/features/org.simantics.jdbc.feature/feature.xml b/features/org.simantics.jdbc.feature/feature.xml new file mode 100644 index 000000000..66b53fac8 --- /dev/null +++ b/features/org.simantics.jdbc.feature/feature.xml @@ -0,0 +1,61 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + + + + + diff --git a/releng/org.simantics.sdk.build.p2.site/pom.xml b/releng/org.simantics.sdk.build.p2.site/pom.xml index 87df82cfe..1001743be 100644 --- a/releng/org.simantics.sdk.build.p2.site/pom.xml +++ b/releng/org.simantics.sdk.build.p2.site/pom.xml @@ -514,6 +514,11 @@ !sun.misc.*,*;resolution:=optional + + com.impossibl.pgjdbc-ng:pgjdbc-ng:0.7.1 + true + false + diff --git a/releng/org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.target b/releng/org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.target index 7306e4e4a..aa58f2419 100644 --- a/releng/org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.target +++ b/releng/org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.target @@ -1,7 +1,7 @@ - + @@ -355,6 +355,8 @@ + + diff --git a/releng/org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.tpd b/releng/org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.tpd index 50ce5ca5b..2875cbbd2 100644 --- a/releng/org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.tpd +++ b/releng/org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.tpd @@ -354,6 +354,8 @@ location "http://www.simantics.org/download/master/external-components/maven" { org.slf4j.api.source org.supercsv org.supercsv.source + pgjdbc-ng + pgjdbc-ng.source stax2-api stax2-api.source } diff --git a/releng/org.simantics.sdk.build.targetdefinition/simantics.target b/releng/org.simantics.sdk.build.targetdefinition/simantics.target index eb9605a93..4853e0c44 100644 --- a/releng/org.simantics.sdk.build.targetdefinition/simantics.target +++ b/releng/org.simantics.sdk.build.targetdefinition/simantics.target @@ -1,7 +1,7 @@ - + @@ -364,6 +364,8 @@ + +