]> gerrit.simantics Code Review - simantics/sysdyn.git/commitdiff
git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@13137 ac1ea38d-2e2b...
authorniemisto <niemisto@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Wed, 18 Nov 2009 13:42:06 +0000 (13:42 +0000)
committerniemisto <niemisto@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Wed, 18 Nov 2009 13:42:06 +0000 (13:42 +0000)
32 files changed:
org.simantics.sysdyn.ui/.classpath [new file with mode: 0644]
org.simantics.sysdyn.ui/.hgignore [new file with mode: 0644]
org.simantics.sysdyn.ui/.project [new file with mode: 0644]
org.simantics.sysdyn.ui/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.sysdyn.ui/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.sysdyn.ui/adapters.xml [new file with mode: 0644]
org.simantics.sysdyn.ui/build.properties [new file with mode: 0644]
org.simantics.sysdyn.ui/doc/manual.mediawiki [new file with mode: 0644]
org.simantics.sysdyn.ui/plugin.xml [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/Activator.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/TestDiagramEditor.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/Connect.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateAuxiliary.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateCloud.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateStock.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateValve.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/editor/SysdynDiagramEditor.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/editor/SysdynDiagramSchema.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/Arcs.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/AuxiliaryElement.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/CloudElement.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/DependencyElement.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/FlowElement.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/Flows.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/RectangularElement.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/StockElement.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/TextElement.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveElement.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/equation/EquationView.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/modelica/ModelicaView.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynPerspectiveFactory.java [new file with mode: 0644]
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java [new file with mode: 0644]

diff --git a/org.simantics.sysdyn.ui/.classpath b/org.simantics.sysdyn.ui/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.sysdyn.ui/.hgignore b/org.simantics.sysdyn.ui/.hgignore
new file mode 100644 (file)
index 0000000..73df90f
--- /dev/null
@@ -0,0 +1,5 @@
+syntax: regexp\r
+^bin/\r
+\r
+syntax: glob\r
+*.svn/*
\ No newline at end of file
diff --git a/org.simantics.sysdyn.ui/.project b/org.simantics.sysdyn.ui/.project
new file mode 100644 (file)
index 0000000..2ebd569
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.sysdyn.ui</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.sysdyn.ui/.settings/org.eclipse.jdt.core.prefs b/org.simantics.sysdyn.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..e9cf5f1
--- /dev/null
@@ -0,0 +1,8 @@
+#Tue Nov 10 13:35:16 EET 2009\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.sysdyn.ui/META-INF/MANIFEST.MF b/org.simantics.sysdyn.ui/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..6bd0fbf
--- /dev/null
@@ -0,0 +1,21 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Ui
+Bundle-SymbolicName: org.simantics.sysdyn.ui;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Require-Bundle: org.simantics.h2d;bundle-version="1.0.0",
+ org.simantics.db;bundle-version="0.6.2",
+ org.simantics.db.management;bundle-version="0.6.2",
+ org.simantics.layer0.utils;bundle-version="0.6.2",
+ org.simantics.scenegraph;bundle-version="1.0.0",
+ org.junit4;bundle-version="4.5.0",
+ org.simantics.ui;bundle-version="1.0.0",
+ org.eclipse.ui;bundle-version="3.5.0",
+ org.eclipse.core.runtime;bundle-version="3.5.0",
+ org.simantics.objmap;bundle-version="0.1.0",
+ org.simantics.sysdyn;bundle-version="1.0.0",
+ org.simantics.project;bundle-version="1.0.0",
+ org.apache.log4j;bundle-version="1.2.15"
+Bundle-Activator: org.simantics.sysdyn.ui.Activator
+Bundle-ActivationPolicy: lazy
diff --git a/org.simantics.sysdyn.ui/adapters.xml b/org.simantics.sysdyn.ui/adapters.xml
new file mode 100644 (file)
index 0000000..3af512f
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<adapters>\r
+       <target\r
+               interface="org.simantics.project.features.IProjectFeature">\r
+               <resource\r
+                       uri="http://www.simantics.org/Sysdyn#SysdynProject"\r
+                       class="org.simantics.sysdyn.ui.project.SysdynProject" />\r
+       </target>\r
+</adapters>
\ No newline at end of file
diff --git a/org.simantics.sysdyn.ui/build.properties b/org.simantics.sysdyn.ui/build.properties
new file mode 100644 (file)
index 0000000..6f20375
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               plugin.xml\r
diff --git a/org.simantics.sysdyn.ui/doc/manual.mediawiki b/org.simantics.sysdyn.ui/doc/manual.mediawiki
new file mode 100644 (file)
index 0000000..100ef97
--- /dev/null
@@ -0,0 +1,79 @@
+Possible connections between sysdyn elements:\r
+\r
+{| border="1"\r
+| &nbsp;\r
+| &nbsp;\r
+| colspan="4", align="center" | To\r
+|-\r
+| &nbsp;\r
+| &nbsp;\r
+| Auxiliary\r
+| Stock\r
+| Valve\r
+| Cloud\r
+|-\r
+| rowspan="4" | From\r
+| Auxiliary\r
+| dependency\r
+| -\r
+| dependency\r
+| -\r
+|-\r
+| Stock\r
+| dependency\r
+| -\r
+| flow / dependency\r
+| -\r
+|-\r
+| Valve\r
+| dependency\r
+| flow\r
+| dependency (?)\r
+| flow\r
+|-\r
+| Cloud\r
+| -\r
+| -\r
+| flow\r
+| -\r
+|}\r
+\r
+Connection actions between sysdyn elements:\r
+\r
+{| border="1"\r
+| &nbsp;\r
+| &nbsp;\r
+| colspan="4", align="center" | To\r
+|-\r
+| &nbsp;\r
+| &nbsp;\r
+| Auxiliary\r
+| Stock\r
+| Valve\r
+| Cloud\r
+|-\r
+| rowspan="4" | From\r
+| Auxiliary\r
+| dependency\r
+| -\r
+| dependency\r
+| -\r
+|-\r
+| Stock\r
+| dependency\r
+| valve + 2 x flow\r
+| flow / dependency\r
+| valve + 2 x flow\r
+|-\r
+| Valve\r
+| dependency\r
+| flow\r
+| dependency (?)\r
+| flow\r
+|-\r
+| Cloud\r
+| -\r
+| valve + 2 x flow\r
+| flow\r
+| -\r
+|}
\ No newline at end of file
diff --git a/org.simantics.sysdyn.ui/plugin.xml b/org.simantics.sysdyn.ui/plugin.xml
new file mode 100644 (file)
index 0000000..6092710
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<?eclipse version="3.4"?>\r
+<plugin>\r
+   <extension\r
+         point="org.eclipse.ui.editors">\r
+      <editor\r
+            class="org.simantics.sysdyn.ui.editor.SysdynDiagramEditor"\r
+            default="false"\r
+            id="org.simantics.sysdyn.ui.diagramEditor"\r
+            name="Sysdyn diagram editor">\r
+      </editor>\r
+   </extension>\r
+   <extension\r
+         point="org.simantics.ui.resourceEditorAdapter">\r
+      <adapter\r
+            editorId="org.simantics.sysdyn.ui.diagramEditor"\r
+            priority="3"\r
+            type_uris="http://www.simantics.org/Sysdyn#Configuration">\r
+      </adapter>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.views">\r
+      <category\r
+            id="org.simantics.sysdyn.ui.category"\r
+            name="System Dynamics">\r
+      </category>\r
+      <view\r
+            category="org.simantics.sysdyn.ui.category"\r
+            class="org.simantics.sysdyn.ui.modelica.ModelicaView"\r
+            id="org.simantics.sysdyn.ui.modelica.view"\r
+            name="Modelica View"\r
+            restorable="true">\r
+      </view>\r
+      <view\r
+            category="org.simantics.sysdyn.ui.category"\r
+            class="org.simantics.sysdyn.ui.equation.EquationView"\r
+            id="org.simantics.sysdyn.ui.equation.view"\r
+            name="Equation View"\r
+            restorable="true">\r
+      </view>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.perspectives">\r
+      <perspective\r
+            class="org.simantics.sysdyn.ui.project.SysdynPerspectiveFactory"\r
+            id="org.simantics.sysdyn.ui.perspective"\r
+            name="System dynamics">\r
+      </perspective>\r
+   </extension>\r
+\r
+</plugin>\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/Activator.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/Activator.java
new file mode 100644 (file)
index 0000000..15e8f4d
--- /dev/null
@@ -0,0 +1,19 @@
+package org.simantics.sysdyn.ui;\r
+\r
+import org.apache.log4j.BasicConfigurator;\r
+import org.apache.log4j.ConsoleAppender;\r
+import org.apache.log4j.SimpleLayout;\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+\r
+public class Activator extends AbstractUIPlugin {\r
+\r
+    @Override\r
+    public void start(BundleContext context) throws Exception {\r
+        super.start(context);\r
+        ConsoleAppender appender = \r
+            new ConsoleAppender(new SimpleLayout());\r
+        BasicConfigurator.configure(appender);\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/TestDiagramEditor.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/TestDiagramEditor.java
new file mode 100644 (file)
index 0000000..74e1bc9
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.sysdyn.ui;\r
+\r
+import javax.swing.JFrame;\r
+\r
+import org.simantics.h2d.canvas.EditorCanvas;\r
+import org.simantics.h2d.diagram.Diagram;\r
+import org.simantics.h2d.editor.impl.DiagramEditor;\r
+import org.simantics.h2d.event.handler.DefaultEventHandlers;\r
+import org.simantics.sysdyn.ui.actions.Connect;\r
+import org.simantics.sysdyn.ui.actions.CreateAuxiliary;\r
+import org.simantics.sysdyn.ui.actions.CreateCloud;\r
+import org.simantics.sysdyn.ui.actions.CreateStock;\r
+import org.simantics.sysdyn.ui.actions.CreateValve;\r
+\r
+public class TestDiagramEditor extends JFrame {\r
+\r
+       public TestDiagramEditor() {\r
+               super("Test Canvas");\r
+               setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\r
+               \r
+               Diagram diagram = new Diagram();\r
+               final DiagramEditor editor = new DiagramEditor(getRootPane(), diagram);\r
+               \r
+               DefaultEventHandlers.configure(editor);\r
+               editor.addEventHandler(1, "key(A)", new CreateAuxiliary());\r
+               editor.addEventHandler(1, "key(S)", new CreateStock());\r
+               editor.addEventHandler(1, "key(V)", new CreateValve());\r
+               editor.addEventHandler(1, "key(C)", new CreateCloud());\r
+               editor.addEventHandler(1, "drag(alt+left)", new Connect());\r
+               \r
+               getContentPane().add(new EditorCanvas(editor));\r
+\r
+        setSize(800, 600);\r
+       }\r
+       \r
+       public static void main(String[] args) {\r
+               javax.swing.SwingUtilities.invokeLater(new Runnable() {\r
+                       public void run() {\r
+                               new TestDiagramEditor().setVisible(true);\r
+                       }\r
+               });     \r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/Connect.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/Connect.java
new file mode 100644 (file)
index 0000000..6354acd
--- /dev/null
@@ -0,0 +1,122 @@
+package org.simantics.sysdyn.ui.actions;\r
+\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.simantics.h2d.editor.IDiagramEditor;\r
+import org.simantics.h2d.element.IElement;\r
+import org.simantics.h2d.element.handler.Connectable;\r
+import org.simantics.h2d.event.DragEvent;\r
+import org.simantics.h2d.event.handler.DragEventHandler;\r
+import org.simantics.h2d.node.RectangleNode;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+import org.simantics.sysdyn.ui.elements.AuxiliaryElement;\r
+import org.simantics.sysdyn.ui.elements.CloudElement;\r
+import org.simantics.sysdyn.ui.elements.DependencyElement;\r
+import org.simantics.sysdyn.ui.elements.FlowElement;\r
+import org.simantics.sysdyn.ui.elements.StockElement;\r
+import org.simantics.sysdyn.ui.elements.ValveElement;\r
+\r
+public class Connect extends DragEventHandler {\r
+\r
+       Connectable from;\r
+       Connectable to;\r
+       \r
+       RectangleNode fromNode = new RectangleNode();   \r
+       RectangleNode toNode = new RectangleNode();\r
+       \r
+       @Override\r
+       protected boolean begin(IDiagramEditor editor, DragEvent event) {\r
+               for(IElement element : event.pickedElements) {\r
+                       Connectable connectable = element.getInterface(Connectable.class);\r
+                       if(connectable != null) {\r
+                               this.from = connectable;\r
+                               return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       @Override\r
+       protected void update(IDiagramEditor editor, DragEvent event) {\r
+               for(IElement element : editor.pickElements(event.current)) {\r
+                       Connectable connectable = element.getInterface(Connectable.class);                      \r
+                       if(connectable != null && connectable != from) {\r
+                               if(connectable == to)\r
+                                       return;\r
+                               to = connectable;\r
+                               \r
+                               Rectangle2D bounds = new Rectangle2D.Double();          \r
+                               to.getBounds(bounds);\r
+                               bounds.setFrame(\r
+                                               bounds.getX()-2.0, \r
+                                               bounds.getY()-2.0, \r
+                                               bounds.getWidth()+4.0, \r
+                                               bounds.getHeight()+4.0);                                \r
+                               toNode.init(bounds);\r
+                               \r
+                               editor.requestRepaint();                                \r
+                               return;\r
+                       }\r
+               }\r
+               to = null;\r
+               toNode.init(fromNode.getBounds());\r
+               editor.requestRepaint();\r
+       }\r
+       \r
+       @Override\r
+       protected void end(IDiagramEditor editor, DragEvent event) {\r
+               if(to != null) {\r
+                       IElement newElement;\r
+                       if(from instanceof ValveElement && to instanceof StockElement)\r
+                               newElement = new FlowElement(from, to);\r
+                       else if(from instanceof StockElement && to instanceof ValveElement)\r
+                               newElement = new FlowElement(from, to);\r
+                       else if( (from instanceof StockElement || from instanceof CloudElement) \r
+                                 && (to instanceof StockElement || to instanceof CloudElement)) {\r
+                               Point2D fromOrigo = from.getOrigo();\r
+                               Point2D toOrigo = to.getOrigo();\r
+                               newElement = new ValveElement(\r
+                                               0.5 * (fromOrigo.getX() + toOrigo.getX()),\r
+                                               0.5 * (fromOrigo.getY() + toOrigo.getY())\r
+                                               );\r
+                               editor.getDiagram().addElement(new FlowElement(from, (ValveElement)newElement));\r
+                               editor.getDiagram().addElement(new FlowElement(to, (ValveElement)newElement));\r
+                       }\r
+                       else if(from instanceof ValveElement && to instanceof AuxiliaryElement)\r
+                               newElement = new DependencyElement(to, from);\r
+                       else if(from instanceof AuxiliaryElement && to instanceof StockElement)\r
+                               newElement = new DependencyElement(to, from);\r
+                       else \r
+                               newElement = new DependencyElement(from, to);\r
+                       editor.getDiagram().addElement(newElement);\r
+               }\r
+               \r
+               from = null;\r
+               to = null;\r
+       }\r
+       \r
+       @Override\r
+       public void init(G2DParentNode parent) {\r
+               fromNode = parent.addNode(RectangleNode.class);\r
+               toNode = parent.addNode(RectangleNode.class);\r
+               \r
+               Rectangle2D bounds = new Rectangle2D.Double();          \r
+               from.getBounds(bounds);\r
+               bounds.setFrame(\r
+                               bounds.getX()-2.0, \r
+                               bounds.getY()-2.0, \r
+                               bounds.getWidth()+4.0, \r
+                               bounds.getHeight()+4.0);\r
+               \r
+               fromNode.init(bounds);\r
+               toNode.init(bounds);\r
+       }\r
+       \r
+       @Override\r
+       public void remove() {\r
+               fromNode.remove();\r
+               toNode.remove();\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateAuxiliary.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateAuxiliary.java
new file mode 100644 (file)
index 0000000..3e6977e
--- /dev/null
@@ -0,0 +1,24 @@
+package org.simantics.sysdyn.ui.actions;\r
+\r
+import org.simantics.h2d.editor.IDiagramEditor;\r
+import org.simantics.h2d.event.IEvent;\r
+import org.simantics.h2d.event.ILocatableEvent;\r
+import org.simantics.h2d.event.handler.IEventHandler;\r
+import org.simantics.sysdyn.ui.elements.AuxiliaryElement;\r
+import org.simantics.sysdyn.ui.elements.StockElement;\r
+\r
+public class CreateAuxiliary implements IEventHandler {\r
+\r
+       @Override\r
+       public boolean handle(IDiagramEditor editor, IEvent _event) {\r
+               ILocatableEvent event = (ILocatableEvent)_event;\r
+               AuxiliaryElement element = new AuxiliaryElement("Auxiliary", \r
+                               event.getLocation().getX(),\r
+                               event.getLocation().getY());\r
+               editor.getDiagram().addElement(element);\r
+               element.beginRenameAction(editor);\r
+               editor.requestRepaint();\r
+               return true;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateCloud.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateCloud.java
new file mode 100644 (file)
index 0000000..b201f37
--- /dev/null
@@ -0,0 +1,22 @@
+package org.simantics.sysdyn.ui.actions;\r
+\r
+import org.simantics.h2d.editor.IDiagramEditor;\r
+import org.simantics.h2d.event.IEvent;\r
+import org.simantics.h2d.event.ILocatableEvent;\r
+import org.simantics.h2d.event.handler.IEventHandler;\r
+import org.simantics.sysdyn.ui.elements.CloudElement;\r
+\r
+public class CreateCloud implements IEventHandler {\r
+\r
+       @Override\r
+       public boolean handle(IDiagramEditor editor, IEvent _event) {\r
+               ILocatableEvent event = (ILocatableEvent)_event;\r
+               CloudElement element = new CloudElement( \r
+                               event.getLocation().getX(),\r
+                               event.getLocation().getY());\r
+               editor.getDiagram().addElement(element);        \r
+               editor.requestRepaint();\r
+               return true;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateStock.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateStock.java
new file mode 100644 (file)
index 0000000..99238f1
--- /dev/null
@@ -0,0 +1,23 @@
+package org.simantics.sysdyn.ui.actions;\r
+\r
+import org.simantics.h2d.editor.IDiagramEditor;\r
+import org.simantics.h2d.event.IEvent;\r
+import org.simantics.h2d.event.ILocatableEvent;\r
+import org.simantics.h2d.event.handler.IEventHandler;\r
+import org.simantics.sysdyn.ui.elements.StockElement;\r
+\r
+public class CreateStock implements IEventHandler {\r
+\r
+       @Override\r
+       public boolean handle(IDiagramEditor editor, IEvent _event) {\r
+               ILocatableEvent event = (ILocatableEvent)_event;\r
+               StockElement element = new StockElement("Stock", \r
+                               event.getLocation().getX(),\r
+                               event.getLocation().getY());\r
+               editor.getDiagram().addElement(element);\r
+               element.beginRenameAction(editor);\r
+               editor.requestRepaint();\r
+               return true;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateValve.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/CreateValve.java
new file mode 100644 (file)
index 0000000..8805053
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.sysdyn.ui.actions;\r
+\r
+import org.simantics.h2d.editor.IDiagramEditor;\r
+import org.simantics.h2d.event.IEvent;\r
+import org.simantics.h2d.event.ILocatableEvent;\r
+import org.simantics.h2d.event.handler.IEventHandler;\r
+import org.simantics.sysdyn.ui.elements.ValveElement;\r
+\r
+public class CreateValve implements IEventHandler {\r
+\r
+       @Override\r
+       public boolean handle(IDiagramEditor editor, IEvent _event) {\r
+               ILocatableEvent event = (ILocatableEvent)_event;\r
+               editor.getDiagram().addElement(new ValveElement( \r
+                               event.getLocation().getX(),\r
+                               event.getLocation().getY()));\r
+               editor.requestRepaint();\r
+               return true;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/editor/SysdynDiagramEditor.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/editor/SysdynDiagramEditor.java
new file mode 100644 (file)
index 0000000..006093c
--- /dev/null
@@ -0,0 +1,210 @@
+package org.simantics.sysdyn.ui.editor;\r
+\r
+import java.awt.Frame;\r
+import java.util.ArrayList;\r
+\r
+import javax.swing.SwingUtilities;\r
+\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.awt.SWT_AWT;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.ui.IEditorInput;\r
+import org.eclipse.ui.IEditorSite;\r
+import org.eclipse.ui.PartInitException;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.h2d.canvas.EditorCanvas;\r
+import org.simantics.h2d.diagram.IDiagram;\r
+import org.simantics.h2d.diagram.IDiagramListener;\r
+import org.simantics.h2d.editor.ISelection;\r
+import org.simantics.h2d.editor.ISelectionListener;\r
+import org.simantics.h2d.editor.impl.DiagramEditor;\r
+import org.simantics.h2d.element.IElement;\r
+import org.simantics.h2d.element.IElementListener;\r
+import org.simantics.h2d.event.handler.DefaultEventHandlers;\r
+import org.simantics.objmap.IMapping;\r
+import org.simantics.objmap.IMappingListener;\r
+import org.simantics.objmap.MappingException;\r
+import org.simantics.objmap.Mappings;\r
+import org.simantics.sysdyn.ui.actions.Connect;\r
+import org.simantics.sysdyn.ui.actions.CreateAuxiliary;\r
+import org.simantics.sysdyn.ui.actions.CreateCloud;\r
+import org.simantics.sysdyn.ui.actions.CreateStock;\r
+import org.simantics.sysdyn.ui.actions.CreateValve;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.ui.workbench.ResourceEditorPart;\r
+import org.simantics.utils.ui.jface.ActiveSelectionProvider;\r
+\r
+public class SysdynDiagramEditor extends ResourceEditorPart {\r
+\r
+       EditorCanvas canvas;\r
+       IDiagram diagram;\r
+       IMapping mapping;\r
+       Frame frame;\r
+               \r
+       IElementListener elementUpdateListener = new IElementListener() {\r
+        \r
+        @Override\r
+        public void elementUpdated(IElement element) {\r
+            mapping.rangeModified(element);\r
+        }\r
+        \r
+        @Override\r
+        public void elementRemoved(IElement element) {\r
+        }\r
+    };\r
+       \r
+       protected void readDiagram(ReadGraph g) throws DatabaseException {\r
+               SysdynDiagramSchema schema = new SysdynDiagramSchema(g);\r
+               mapping = Mappings.createWithListening(schema);\r
+                               \r
+               try {\r
+                       diagram = (IDiagram)mapping.map(g, getInputResource());\r
+               } catch (MappingException e) {\r
+                       // TODO Auto-generated catch block\r
+                       e.printStackTrace();\r
+               }\r
+               \r
+               final Session session = g.getSession();\r
+               mapping.addMappingListener(new IMappingListener() {\r
+                       \r
+                       @Override\r
+                       public void rangeModified() {\r
+                               session.asyncRequest(new WriteRequest() {\r
+                                       \r
+                                       @Override\r
+                                       public void perform(WriteGraph graph)\r
+                                                       throws DatabaseException {\r
+                                           try {\r
+                                               mapping.updateDomain(graph);\r
+                                           } catch(Exception e) {\r
+                                               e.printStackTrace();\r
+                                           }\r
+                                       }\r
+                                       \r
+                               });\r
+                       }\r
+                       \r
+                       @Override\r
+                       public void domainModified() {\r
+                           session.asyncRequest(new ReadRequest() {\r
+                    \r
+                    @Override\r
+                    public void run(ReadGraph graph) throws DatabaseException {\r
+                        try {\r
+                            mapping.updateRange(graph);\r
+                        } catch(Exception e) {\r
+                            e.printStackTrace();\r
+                        }\r
+                    }\r
+                });                        \r
+                       }\r
+                                               \r
+               });\r
+               \r
+               diagram.addDiagramListener(new IDiagramListener() {\r
+                       \r
+                       @Override\r
+                       public void elementAdded(IElement element) {\r
+                               mapping.rangeModified(diagram);                 \r
+                               element.addListener(elementUpdateListener);\r
+                       }\r
+                       \r
+                       @Override\r
+                       public void elementRemoved(IElement element) {\r
+                               mapping.rangeModified(diagram);                 \r
+                       }\r
+                       \r
+               });\r
+       }\r
+       \r
+       @Override\r
+       public void init(IEditorSite site, IEditorInput input)\r
+                       throws PartInitException {\r
+               super.init(site, input);\r
+               \r
+               try {\r
+                       SimanticsUI.getSession().syncRequest(new ReadRequest() {\r
+                               \r
+                               @Override\r
+                               public void run(ReadGraph g) throws DatabaseException {\r
+                                       readDiagram(g);                 \r
+                               }\r
+                               \r
+                       });\r
+               } catch (DatabaseException e) {\r
+                       // TODO Auto-generated catch block\r
+                       e.printStackTrace();\r
+               }               \r
+       }\r
+       \r
+       @Override\r
+       public void createPartControl(Composite parent) {\r
+        final Composite composite = new Composite(parent, \r
+                       SWT.NO_BACKGROUND | SWT.EMBEDDED);\r
+        frame = SWT_AWT.new_Frame(composite);\r
+        \r
+        final ActiveSelectionProvider selectionProvider = new ActiveSelectionProvider();\r
+        getSite().setSelectionProvider(selectionProvider);\r
+        \r
+        SwingUtilities.invokeLater(new Runnable() {\r
+\r
+            @Override\r
+            public void run() {                \r
+                       DiagramEditor editor = new DiagramEditor(null, diagram);                \r
+                       \r
+                       DefaultEventHandlers.configure(editor);\r
+                       editor.addEventHandler(1, "key(A)", new CreateAuxiliary());\r
+                       editor.addEventHandler(1, "key(S)", new CreateStock());\r
+                       editor.addEventHandler(1, "key(V)", new CreateValve());\r
+                       editor.addEventHandler(1, "key(C)", new CreateCloud());\r
+                       editor.addEventHandler(1, "drag(alt+left)", new Connect());\r
+                       \r
+               canvas = new EditorCanvas(editor);\r
+                frame.add(canvas);\r
+                \r
+                canvas.requestFocus();           \r
+                \r
+                editor.getSelection().addSelectionListener(new ISelectionListener() {\r
+                    \r
+                    @Override\r
+                    public void selectionChanged(ISelection selection) {\r
+                        final ArrayList<Resource> resources = new ArrayList<Resource>(selection.size());\r
+                        for(IElement element : selection)\r
+                            resources.add(mapping.inverseGet(element));\r
+                        composite.getDisplay().asyncExec(new Runnable() {\r
+\r
+                            @Override\r
+                            public void run() {\r
+                                selectionProvider.setSelection(new StructuredSelection(resources));\r
+                            }\r
+                            \r
+                        });\r
+                    }\r
+                    \r
+                });\r
+            }\r
+            \r
+        });\r
+       }\r
+\r
+       @Override\r
+       public void setFocus() {\r
+               if(canvas != null)\r
+            canvas.requestFocus();             \r
+       }\r
+       \r
+       @Override\r
+       public void dispose() {\r
+           mapping.dispose();\r
+           frame.dispose();\r
+           \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/editor/SysdynDiagramSchema.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/editor/SysdynDiagramSchema.java
new file mode 100644 (file)
index 0000000..bdcf568
--- /dev/null
@@ -0,0 +1,54 @@
+package org.simantics.sysdyn.ui.editor;\r
+\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.Builtins;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.h2d.diagram.Diagram;\r
+import org.simantics.objmap.rules.MappedElementsRule;\r
+import org.simantics.objmap.rules.domain.RelatedObjectsAccessor;\r
+import org.simantics.objmap.rules.range.FieldAccessor;\r
+import org.simantics.objmap.schema.MappingSchemas;\r
+import org.simantics.objmap.schema.SimpleLinkType;\r
+import org.simantics.objmap.schema.SimpleSchema;\r
+import org.simantics.sysdyn.SysdynResource;\r
+import org.simantics.sysdyn.ui.elements.AuxiliaryElement;\r
+import org.simantics.sysdyn.ui.elements.CloudElement;\r
+import org.simantics.sysdyn.ui.elements.DependencyElement;\r
+import org.simantics.sysdyn.ui.elements.FlowElement;\r
+import org.simantics.sysdyn.ui.elements.StockElement;\r
+import org.simantics.sysdyn.ui.elements.ValveElement;\r
+\r
+public class SysdynDiagramSchema extends SimpleSchema {\r
+\r
+       public SysdynDiagramSchema(ReadGraph g) throws DatabaseException {\r
+               Builtins b = g.getBuiltins();\r
+               SysdynResource sr = SysdynResource.getInstance(g);\r
+               try {\r
+                       {\r
+                               SimpleLinkType linkType = \r
+                                       new SimpleLinkType(sr.Configuration, Diagram.class);\r
+                               linkType.addRule(new MappedElementsRule(\r
+                                               new RelatedObjectsAccessor(b.ConsistsOf),\r
+                                               new FieldAccessor<Collection<Object>>(Diagram.class.getField("elements"))\r
+                                               ));\r
+                               addLinkType(linkType);\r
+                       }                       \r
+               \r
+                       addLinkType(MappingSchemas.fromAnnotations(g, AuxiliaryElement.class));                         \r
+                       addLinkType(MappingSchemas.fromAnnotations(g, StockElement.class));\r
+                       addLinkType(MappingSchemas.fromAnnotations(g, CloudElement.class));\r
+                       addLinkType(MappingSchemas.fromAnnotations(g, ValveElement.class));\r
+                       addLinkType(MappingSchemas.fromAnnotations(g, DependencyElement.class));\r
+                       addLinkType(MappingSchemas.fromAnnotations(g, FlowElement.class));\r
+               } catch(NoSuchFieldException e) {\r
+                       e.printStackTrace();\r
+               } catch (InstantiationException e) {\r
+            e.printStackTrace();\r
+        } catch (IllegalAccessException e) {\r
+            e.printStackTrace();\r
+        }\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/Arcs.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/Arcs.java
new file mode 100644 (file)
index 0000000..89d1dc0
--- /dev/null
@@ -0,0 +1,154 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import java.awt.geom.Rectangle2D;\r
+\r
+public class Arcs {\r
+\r
+    public static final double PI2 = Math.PI*2.0;\r
+    \r
+    /**\r
+     * Returns angle + 2PI * n such that the\r
+     * result is between -PI and PI.\r
+     */\r
+    public static double normalizeAngle(double angle) {\r
+        return Math.IEEEremainder(angle, PI2);\r
+    }\r
+    \r
+    /**\r
+     * Returns true, if three normalized angles are clockwise oriented.\r
+     */\r
+    public static boolean areClockwiseOrdered(double angle1, double angle2, double angle3) {\r
+        //System.out.println(angle1 + " " + angle2 + " " + angle3);\r
+        return angle1 < angle2 \r
+            ? (angle2 < angle3 || angle3 < angle1)\r
+            : (angle2 < angle3 && angle3 < angle1)\r
+            ;\r
+    }\r
+    \r
+    /**\r
+     * Returns an angle in radians between straight line from (x0,y0) to (x2,y2)\r
+     * and an arc from (x0,y0) to (x2,y2) thru (x1,y1). The angle\r
+     * is measured at (x0,y0) and is between -PI and PI.\r
+     */\r
+    public static double angleOfArc(\r
+        double x0, double y0, \r
+        double x1, double y1,\r
+        double x2, double y2) {\r
+        double dx0 = x1-x0;\r
+        double dy0 = y1-y0;\r
+        double dx1 = x1-x2;\r
+        double dy1 = y1-y2;\r
+        double dx = x2-x0;\r
+        double dy = y2-y0;\r
+        // Length of cross product (p1-p0)x(p2-p0)\r
+        double dd = dx0*dy - dy0*dx; \r
+        \r
+        if(Math.abs(dd) < 1e-6) // Points are (almost) collinear\r
+            return 0.0;\r
+        else {            \r
+            // (p1-p0)*(p1-p2) / dd\r
+            double offset = (dx0*dx1 + dy0*dy1) / dd;\r
+            double angle = Math.PI*0.5 - Math.atan(offset);\r
+            if(dd > 0.0)\r
+                angle = angle-Math.PI;\r
+            return angle;\r
+            \r
+        }\r
+    }\r
+    \r
+    private static double updateBestNextAngle(double curAngle, double bestAngle, double newAngle) {\r
+        if(newAngle < curAngle)\r
+            newAngle += PI2;\r
+        if(newAngle < bestAngle)\r
+            return newAngle;\r
+        return bestAngle;        \r
+    }   \r
+    \r
+    private static double updateBestPrevAngle(double curAngle, double bestAngle, double newAngle) {\r
+        if(newAngle > curAngle)\r
+            newAngle -= PI2;\r
+        if(newAngle > bestAngle)\r
+            return newAngle;\r
+        return bestAngle;        \r
+    }   \r
+    \r
+    public static double nextIntersectingAngle(double cx, double cy, double r,\r
+        double curAngle, Rectangle2D rect, boolean dir) {\r
+        if(!dir) {\r
+            double bestAngle = curAngle + PI2;\r
+            {\r
+                double dx = rect.getMinX() - cx;\r
+                if(Math.abs(dx) < r) {\r
+                    double angle = normalizeAngle(Math.acos(dx / r));\r
+                    bestAngle = updateBestNextAngle(curAngle, bestAngle, angle);\r
+                    bestAngle = updateBestNextAngle(curAngle, bestAngle, -angle);\r
+                }\r
+            }\r
+            {\r
+                double dx = rect.getMaxX() - cx;\r
+                if(Math.abs(dx) < r) {\r
+                    double angle = normalizeAngle(Math.acos(dx / r));\r
+                    bestAngle = updateBestNextAngle(curAngle, bestAngle, angle);\r
+                    bestAngle = updateBestNextAngle(curAngle, bestAngle, -angle);\r
+                }\r
+            }\r
+            {\r
+                double dy = cy - rect.getMinY();\r
+                if(Math.abs(dy) < r) {\r
+                    double angle = Math.asin(dy / r);\r
+                    bestAngle = updateBestNextAngle(curAngle, bestAngle, angle);\r
+                    bestAngle = updateBestNextAngle(curAngle, bestAngle, \r
+                        normalizeAngle(Math.PI-angle));\r
+                }\r
+            }\r
+            {\r
+                double dy = cy - rect.getMaxY();\r
+                if(Math.abs(dy) < r) {\r
+                    double angle = Math.asin(dy / r);\r
+                    bestAngle = updateBestNextAngle(curAngle, bestAngle, angle);\r
+                    bestAngle = updateBestNextAngle(curAngle, bestAngle, \r
+                        normalizeAngle(Math.PI-angle));\r
+                }\r
+            }\r
+            return normalizeAngle(bestAngle);\r
+        }   \r
+        else {\r
+            double bestAngle = curAngle - PI2;\r
+            {\r
+                double dx = rect.getMinX() - cx;\r
+                if(Math.abs(dx) < r) {\r
+                    double angle = normalizeAngle(Math.acos(dx / r));\r
+                    bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle);\r
+                    bestAngle = updateBestPrevAngle(curAngle, bestAngle, -angle);\r
+                }\r
+            }\r
+            {\r
+                double dx = rect.getMaxX() - cx;\r
+                if(Math.abs(dx) < r) {\r
+                    double angle = normalizeAngle(Math.acos(dx / r));\r
+                    bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle);\r
+                    bestAngle = updateBestPrevAngle(curAngle, bestAngle, -angle);\r
+                }\r
+            }\r
+            {\r
+                double dy = cy - rect.getMinY();\r
+                if(Math.abs(dy) < r) {\r
+                    double angle = Math.asin(dy / r);\r
+                    bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle);\r
+                    bestAngle = updateBestPrevAngle(curAngle, bestAngle, \r
+                        normalizeAngle(Math.PI-angle));\r
+                }\r
+            }\r
+            {\r
+                double dy = cy - rect.getMaxY();\r
+                if(Math.abs(dy) < r) {\r
+                    double angle = Math.asin(dy / r);\r
+                    bestAngle = updateBestPrevAngle(curAngle, bestAngle, angle);\r
+                    bestAngle = updateBestPrevAngle(curAngle, bestAngle, \r
+                        normalizeAngle(Math.PI-angle));\r
+                }\r
+            }\r
+            return normalizeAngle(bestAngle);\r
+        }\r
+    }\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/AuxiliaryElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/AuxiliaryElement.java
new file mode 100644 (file)
index 0000000..e10f97f
--- /dev/null
@@ -0,0 +1,15 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import org.simantics.objmap.annotations.GraphType;\r
+\r
+@GraphType("http://www.simantics.org/Sysdyn#Auxiliary")\r
+public class AuxiliaryElement extends TextElement {\r
+       \r
+       public AuxiliaryElement() {     \r
+       }\r
+       \r
+       public AuxiliaryElement(String label, double x, double y) {\r
+           super(label, x, y);\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/CloudElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/CloudElement.java
new file mode 100644 (file)
index 0000000..97c974d
--- /dev/null
@@ -0,0 +1,71 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.geom.Path2D;\r
+\r
+import org.simantics.h2d.element.handler.Connectable;\r
+import org.simantics.h2d.node.ShapeNode;\r
+import org.simantics.objmap.annotations.GraphType;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+\r
+@GraphType("http://www.simantics.org/Sysdyn#Cloud")\r
+public class CloudElement extends RectangularElement implements Connectable {\r
+        \r
+       public static final double CLOUD_SIZE_X = 5.0;\r
+       public static final double CLOUD_SIZE_Y = 3.0;\r
+       \r
+       public static final double CLOUD_CURVES = 7;\r
+       \r
+    ShapeNode cloudNode;\r
+    boolean rotated = false;\r
+    \r
+       public CloudElement() { \r
+       }\r
+       \r
+       public CloudElement(double x, double y) {\r
+           this.posX = x;\r
+           this.posY = y; \r
+       }\r
+\r
+       @Override\r
+       public void init(G2DParentNode parent) {\r
+               cloudNode = parent.addNode(ShapeNode.class);\r
+               cloudNode.setColor(Color.BLACK);\r
+               cloudNode.setScaleStroke(true);\r
+               cloudNode.setStroke(new BasicStroke(1));\r
+               update();\r
+       }\r
+\r
+       @Override\r
+       public void remove() {\r
+               cloudNode.remove();\r
+       }\r
+       \r
+       @Override\r
+       protected void update() {\r
+               //bounds.setFrame(posX-CLOUD_SIZE_X, posY-CLOUD_SIZE_Y, 2.0*CLOUD_SIZE_X, 2.0*CLOUD_SIZE_Y);\r
+               Path2D path = new Path2D.Double();      \r
+               double ox = CLOUD_SIZE_X;\r
+               double oy = 0.0;\r
+               path.moveTo(posX+ox, posY+oy);          \r
+               for(int i=1;i<CLOUD_CURVES+1;++i) {\r
+                       double angle = (Math.PI * 2.0 / CLOUD_CURVES) * i;\r
+                       double x = Math.cos(angle) * CLOUD_SIZE_X;\r
+                       double y = Math.sin(angle) * CLOUD_SIZE_Y;\r
+                       path.curveTo(\r
+                                       posX+(2*ox + x)*0.5, posY+(2*oy + y)*0.5,\r
+                                       posX+(ox + 2*x)*0.5, posY+(oy + 2*y)*0.5,\r
+                                       posX + x, posY + y);\r
+                       ox = x;\r
+                       oy = y;\r
+               }\r
+               cloudNode.setShape(path);\r
+               bounds = path.getBounds2D();\r
+           super.update();\r
+       }\r
+\r
+       public boolean isRotated() {\r
+               return rotated;\r
+       }\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/DependencyElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/DependencyElement.java
new file mode 100644 (file)
index 0000000..67026e5
--- /dev/null
@@ -0,0 +1,203 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Shape;\r
+import java.awt.geom.Arc2D;\r
+import java.awt.geom.Path2D;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.simantics.h2d.editor.IDiagramEditor;\r
+import org.simantics.h2d.element.Element;\r
+import org.simantics.h2d.element.IElement;\r
+import org.simantics.h2d.element.IElementListener;\r
+import org.simantics.h2d.element.handler.Connectable;\r
+import org.simantics.h2d.event.DragEvent;\r
+import org.simantics.h2d.event.handler.DragEventHandler;\r
+import org.simantics.h2d.event.handler.IEventHandler;\r
+import org.simantics.h2d.node.FilledShapeNode;\r
+import org.simantics.h2d.node.ShapeNode;\r
+import org.simantics.objmap.annotations.GraphType;\r
+import org.simantics.objmap.annotations.RelatedElement;\r
+import org.simantics.objmap.annotations.RelatedValue;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+\r
+@GraphType("http://www.simantics.org/Sysdyn#Dependency")\r
+public class DependencyElement extends Element implements IElementListener {\r
+       \r
+       /*\r
+        * Total length of the arrow is ARROW_LENGTH1 + ARROW_LENGTH2\r
+        */\r
+    public static double ARROW_LENGTH1 = 0.2;\r
+    public static double ARROW_LENGTH2 = 3.0;\r
+    public static double ARROW_WIDTH = 1.8;\r
+    \r
+    @RelatedElement("http://www.simantics.org/Sysdyn#HasTail")\r
+       Connectable tail;\r
+    @RelatedElement("http://www.simantics.org/Sysdyn#HasHead")\r
+       Connectable head;\r
+    @RelatedValue("http://www.simantics.org/Sysdyn#HasAngle")\r
+       double angle = 0.1;\r
+\r
+       // Auxiliary    \r
+       double angle0;\r
+       double angle1;\r
+       double cx;\r
+       double cy;\r
+       double r;\r
+       \r
+       // Scene graph\r
+       ShapeNode arcNode;\r
+       FilledShapeNode arrowNode;\r
+       \r
+       public DependencyElement() {        \r
+       }\r
+       \r
+       public DependencyElement(Connectable tail, Connectable head) {\r
+               super();\r
+               this.tail = tail;\r
+               this.head = head;\r
+       }\r
+       \r
+       @Override\r
+       public void elementUpdated(IElement element) {\r
+               update();               \r
+       }       \r
+\r
+       @Override\r
+       public void remove() {\r
+               arcNode.remove();\r
+               arrowNode.remove();\r
+               tail.removeListener(this);\r
+               head.removeListener(this);\r
+               super.remove();\r
+       }\r
+\r
+       @Override\r
+       public void init(G2DParentNode parent) {\r
+               tail.addListener(this);\r
+               head.addListener(this);\r
+               \r
+               arcNode = parent.addNode(ShapeNode.class);\r
+               arcNode.setScaleStroke(true);\r
+               arcNode.setStroke(new BasicStroke(1));\r
+               arrowNode = parent.addNode(FilledShapeNode.class);\r
+               update();\r
+       }\r
+       \r
+       protected Shape createArrow(double x, double y, double dx, double dy) {\r
+        Path2D path = new Path2D.Double();\r
+        path.moveTo(x+ARROW_LENGTH1*dx, y+ARROW_LENGTH1*dy);\r
+        x -= ARROW_LENGTH2*dx;\r
+        y -= ARROW_LENGTH2*dy;\r
+        path.lineTo(x-ARROW_WIDTH*dy, y+ARROW_WIDTH*dx);\r
+        path.lineTo(x+ARROW_WIDTH*dy, y-ARROW_WIDTH*dx);\r
+        path.closePath();\r
+        return path;\r
+    }\r
+       \r
+       protected void updateSceneGraph() {\r
+               double x0 = tail.getOrigo().getX();\r
+        double y0 = tail.getOrigo().getY();\r
+        double x1 = head.getOrigo().getX();\r
+        double y1 = head.getOrigo().getY();\r
+        \r
+        double offset = \r
+            Math.abs(angle) < 1.0e-6\r
+            ? 1e3 * Math.signum(angle)\r
+            : Math.tan(Math.PI*0.5-angle)*0.5;\r
+        cx = 0.5*(x0+x1) + offset * (y1-y0);\r
+        cy = 0.5*(y0+y1) + offset * (x0-x1);\r
+        double dx0 = x0 - cx;\r
+        double dy0 = y0 - cy;\r
+        double dx1 = x1 - cx;\r
+        double dy1 = y1 - cy;\r
+        r = Math.sqrt(dx0*dx0 + dy0*dy0);\r
+        Rectangle2D bounds = new Rectangle2D.Double();\r
+        tail.getBounds(bounds);\r
+        angle0 = Arcs.nextIntersectingAngle(cx, cy, r, \r
+            Math.atan2(-dy0, dx0), bounds, angle < 0.0);\r
+        head.getBounds(bounds);\r
+        angle1 = Arcs.nextIntersectingAngle(cx, cy, r, \r
+            Math.atan2(-dy1, dx1), bounds, angle > 0.0);\r
+        double extent = angle1-angle0;\r
+        //double arcAngle = angle0;\r
+        if(angle < 0.0) {\r
+            double temp = angle0;            \r
+            angle0 = angle1;\r
+            angle1 = temp;\r
+            extent = -extent;\r
+        }                \r
+        if(extent < 0)\r
+            extent += Math.PI*2.0;\r
+        else if(extent >= 360.0)\r
+            extent -= Math.PI*2.0;\r
+        Shape shape = new Arc2D.Double(cx-r, cy-r, 2*r, 2*r, \r
+            Math.toDegrees(angle0), \r
+            Math.toDegrees(extent), \r
+            Arc2D.OPEN);                \r
+        arcNode.setShape(shape);\r
+        \r
+        double xx = Math.cos(angle > 0.0 ? angle1 : angle0);\r
+        double yy = -Math.sin(angle > 0.0 ? angle1 : angle0);\r
+        Shape arrowShape = createArrow(cx + r*xx, cy + r*yy, \r
+            angle < 0.0 ? -yy : yy, \r
+            angle > 0.0 ? -xx : xx);\r
+        arrowNode.setShape(arrowShape);\r
+       }\r
+       \r
+       public void update() {\r
+               if(arcNode != null)\r
+                       updateSceneGraph();\r
+               super.update();\r
+       }\r
+               \r
+       @Override\r
+       public void getBounds(Rectangle2D bounds) {\r
+               bounds.setFrame(arcNode.getBounds());\r
+       }\r
+\r
+       @Override\r
+       public boolean hitTest(double x, double y, double tolerance) {\r
+        double dx = x-cx;\r
+        double dy = y-cy;\r
+        double dist = dx*dx + dy*dy;\r
+        if(dist < (r+tolerance)*(r+tolerance) &&\r
+            dist > (r-tolerance)*(r-tolerance)) {\r
+            double angle = Arcs.normalizeAngle(Math.atan2(-dy, dx));\r
+            if(Arcs.areClockwiseOrdered(angle0, angle, angle1))\r
+                return true;\r
+        }\r
+        return false;\r
+       }\r
+       \r
+       class EventHandler extends DragEventHandler {\r
+               @Override\r
+               protected boolean begin(IDiagramEditor editor, DragEvent event) {\r
+                       return event.startModifiers.equals("left");\r
+               }\r
+               \r
+               @Override\r
+               protected void update(IDiagramEditor editor, DragEvent event) {\r
+                       angle = Arcs.angleOfArc(\r
+                                       tail.getOrigo().getX(), tail.getOrigo().getY(), \r
+                                       event.current.getX(), event.current.getY(), \r
+                                       head.getOrigo().getX(), head.getOrigo().getY()\r
+                                       );\r
+                       DependencyElement.this.update();\r
+                       editor.requestRepaint();\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public <T> T getInterface(Class<T> clazz) {\r
+               if(clazz == IEventHandler.class) \r
+                       return (T)new EventHandler();\r
+               return super.getInterface(clazz);\r
+       }\r
+\r
+       @Override\r
+       public void elementRemoved(IElement element) {\r
+               remove();               \r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/FlowElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/FlowElement.java
new file mode 100644 (file)
index 0000000..2642aa5
--- /dev/null
@@ -0,0 +1,183 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import java.awt.Shape;\r
+import java.awt.geom.Path2D;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.simantics.h2d.element.Element;\r
+import org.simantics.h2d.element.IElement;\r
+import org.simantics.h2d.element.IElementListener;\r
+import org.simantics.h2d.element.handler.Connectable;\r
+import org.simantics.h2d.node.FilledShapeNode;\r
+import org.simantics.h2d.node.ShapeNode;\r
+import org.simantics.objmap.annotations.GraphType;\r
+import org.simantics.objmap.annotations.RelatedElement;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+\r
+@GraphType("http://www.simantics.org/Sysdyn#Flow")\r
+public class FlowElement extends Element implements IElementListener {\r
+\r
+       public static double ARROW_LENGTH1 = 0.2;\r
+    public static double ARROW_LENGTH2 = 3.0;\r
+    public static double ARROW_WIDTH = 1.8;\r
+    \r
+    static final double OFFSET = 1.5;\r
+    \r
+       /*\r
+        * Total length of the arrow is ARROW_LENGTH1 + ARROW_LENGTH2\r
+        */    \r
+    @RelatedElement("http://www.simantics.org/Sysdyn#HasTail")\r
+       Connectable tail;\r
+    @RelatedElement("http://www.simantics.org/Sysdyn#HasHead")\r
+       Connectable head;\r
+       double angle = 0.1;\r
+\r
+       // Auxiliary    \r
+       double angle0;\r
+       double angle1;\r
+       double cx;\r
+       double cy;\r
+       double r;\r
+       \r
+       // Scene graph\r
+       ShapeNode lineNode1;\r
+       ShapeNode lineNode2;\r
+       FilledShapeNode arrowNode;\r
+       \r
+       public FlowElement() {      \r
+       }\r
+       \r
+       public FlowElement(Connectable tail, Connectable head) {\r
+               super();\r
+               this.tail = tail;\r
+               this.head = head;\r
+       }\r
+       \r
+       @Override\r
+       public void elementUpdated(IElement element) {\r
+               update();               \r
+       }       \r
+\r
+       @Override\r
+       public void remove() {\r
+               lineNode1.remove();\r
+               lineNode2.remove();\r
+               tail.removeListener(this);\r
+               head.removeListener(this);\r
+       }\r
+\r
+       @Override\r
+       public void init(G2DParentNode parent) {\r
+               tail.addListener(this);\r
+               head.addListener(this);\r
+               \r
+               lineNode1 = parent.addNode(ShapeNode.class);\r
+               lineNode1.setScaleStroke(true);\r
+               lineNode2 = parent.addNode(ShapeNode.class);\r
+               lineNode2.setScaleStroke(true);\r
+               \r
+               //arrowNode = parent.addNode(FilledShapeNode.class);\r
+               update();\r
+       }\r
+       \r
+       protected Shape createArrow(double x, double y, double dx, double dy) {\r
+        Path2D path = new Path2D.Double();\r
+        path.moveTo(x+ARROW_LENGTH1*dx, y+ARROW_LENGTH1*dy);\r
+        x -= ARROW_LENGTH2*dx;\r
+        y -= ARROW_LENGTH2*dy;\r
+        path.lineTo(x-ARROW_WIDTH*dy, y+ARROW_WIDTH*dx);\r
+        path.lineTo(x+ARROW_WIDTH*dy, y-ARROW_WIDTH*dx);\r
+        path.closePath();\r
+        return path;\r
+    }\r
+       \r
+       // TODO\r
+       \r
+       private void draw(boolean vertical, double ... coordinates) {\r
+               lineNode1.setShape(Flows.createOffsetLine(vertical, OFFSET, coordinates));\r
+               lineNode2.setShape(Flows.createOffsetLine(vertical, -OFFSET, coordinates));\r
+       }\r
+\r
+       private void draw(Connectable valve, Connectable node) {\r
+               double x0 = valve.getOrigo().getX();\r
+               double y0 = valve.getOrigo().getY();        \r
+               double x1 = node.getOrigo().getX();\r
+               double y1 = node.getOrigo().getY();\r
+\r
+               Rectangle2D rect = new Rectangle2D.Double();\r
+               node.getBounds(rect);\r
+               if( ((ValveElement)valve).rotated ) {\r
+                       if(y1 > y0)\r
+                               y0 += OFFSET;\r
+                       else\r
+                               y0 -= OFFSET;\r
+                       if(rect.getMinX() <= x0 && rect.getMaxX() >= x0) {\r
+                               if(y1 > y0)\r
+                                       draw(true, y0, x0, rect.getMinY());\r
+                               else\r
+                                       draw(true, y0, x0, rect.getMaxY());\r
+                       }\r
+                       else {\r
+                               if(x1 > x0)\r
+                                       draw(true, y0, x0, y1, rect.getMinX());\r
+                               else\r
+                                       draw(true, y0, x0, y1, rect.getMaxX());\r
+                       }\r
+               }\r
+               else {\r
+                       if(x1 > x0)\r
+                               x0 += OFFSET;\r
+                       else\r
+                               x0 -= OFFSET;\r
+                       if(rect.getMinY() <= y0 && rect.getMaxY() >= y0) {\r
+                               if(x1 > x0)\r
+                                       draw(false, x0, y0, rect.getMinX());\r
+                               else\r
+                                       draw(false, x0, y0, rect.getMaxX());\r
+                       }\r
+                       else {\r
+                               if(y1 > y0)\r
+                                       draw(false, x0, y0, x1, rect.getMinY());\r
+                               else\r
+                                       draw(false, x0, y0, x1, rect.getMaxY());\r
+                       }\r
+               }\r
+       }\r
+\r
+       protected void updateSceneGraph() {\r
+               if(tail instanceof ValveElement)\r
+                       draw(tail, head);\r
+               else if(head instanceof ValveElement)\r
+                       draw(head, tail);\r
+       }\r
+       \r
+       // TODO\r
+       \r
+       public void update() {\r
+               if(lineNode1 != null)\r
+                       updateSceneGraph();\r
+               super.update();\r
+       }\r
+               \r
+       @Override\r
+       public void getBounds(Rectangle2D bounds) {\r
+               bounds.setFrame(lineNode1.getBounds());\r
+       }\r
+\r
+       @Override\r
+       public boolean hitTest(double x, double y, double tolerance) {\r
+        // TODO\r
+        return false;\r
+       }\r
+\r
+       @Override\r
+       public <T> T getInterface(Class<T> clazz) {             \r
+               return super.getInterface(clazz);\r
+       }\r
+\r
+       @Override\r
+       public void elementRemoved(IElement element) {\r
+               remove();               \r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/Flows.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/Flows.java
new file mode 100644 (file)
index 0000000..2c9c23e
--- /dev/null
@@ -0,0 +1,33 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import java.awt.geom.Path2D;\r
+\r
+public class Flows {\r
+    public static Path2D createLine(boolean vertical, double ... coordinates) {\r
+        Path2D path = new Path2D.Double();\r
+        if(vertical)\r
+            path.moveTo(coordinates[1], coordinates[0]);\r
+        else\r
+            path.moveTo(coordinates[0], coordinates[1]);\r
+        for(int i=2;i<coordinates.length;++i, vertical = !vertical) {\r
+            if(vertical)\r
+                path.lineTo(coordinates[i-1], coordinates[i]);\r
+            else\r
+                path.lineTo(coordinates[i], coordinates[i-1]);\r
+        }\r
+        return path;\r
+    }\r
+    \r
+    public static Path2D createOffsetLine(boolean vertical, double offset, double ... coordinates) {\r
+        double[] newCoordinats = new double[coordinates.length];\r
+        newCoordinats[0] = coordinates[0];\r
+        newCoordinats[coordinates.length-1] = coordinates[coordinates.length-1];\r
+        for(int i=1;i<coordinates.length-1;++i) {\r
+            if(coordinates[i-1] < coordinates[i+1] ^ (i&1)==1)\r
+                newCoordinats[i] = coordinates[i]+offset;\r
+            else\r
+                newCoordinats[i] = coordinates[i]-offset;\r
+        }\r
+        return createLine(vertical, newCoordinats);\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/RectangularElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/RectangularElement.java
new file mode 100644 (file)
index 0000000..c2d4a2a
--- /dev/null
@@ -0,0 +1,48 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.simantics.h2d.element.Element;\r
+import org.simantics.h2d.element.handler.Movable;\r
+import org.simantics.objmap.annotations.RelatedValue;\r
+\r
+/**\r
+ * Base class of elements that have rectangular shape (for hit testing)\r
+ * and which can be moved.\r
+ * @author Hannu Niemistö\r
+ */\r
+public abstract class RectangularElement extends Element implements Movable {\r
+       \r
+       protected Rectangle2D bounds = new Rectangle2D.Double();\r
+       \r
+    @RelatedValue("http://www.simantics.org/Sysdyn#HasX")\r
+    protected double posX;\r
+    @RelatedValue("http://www.simantics.org/Sysdyn#HasY")\r
+    protected double posY;     \r
+    \r
+       public RectangularElement() {   \r
+       }\r
+       \r
+       @Override\r
+       public void getBounds(Rectangle2D bounds) {\r
+               bounds.setFrame(this.bounds);\r
+       }\r
+\r
+       @Override\r
+       public boolean hitTest(double x, double y, double tolerance) {\r
+               return bounds.intersects(x-tolerance, y-tolerance, 2.0*tolerance, 2.0*tolerance);\r
+       }       \r
+       \r
+       @Override\r
+       public void move(double deltaX, double deltaY) {\r
+               posX += deltaX;\r
+               posY += deltaY;\r
+               update();\r
+       }\r
+               \r
+       public Point2D getOrigo() {\r
+               return new Point2D.Double(posX, posY);\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/StockElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/StockElement.java
new file mode 100644 (file)
index 0000000..01c6692
--- /dev/null
@@ -0,0 +1,38 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import org.simantics.h2d.node.RectangleNode;\r
+import org.simantics.objmap.annotations.GraphType;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+\r
+@GraphType("http://www.simantics.org/Sysdyn#Stock")\r
+public class StockElement extends TextElement {\r
+       \r
+    RectangleNode rectangleNode;\r
+    \r
+       public StockElement() { \r
+       }\r
+       \r
+       public StockElement(String label, double x, double y) {\r
+           super(label, x, y);\r
+       }\r
+\r
+       @Override\r
+       public void init(G2DParentNode parent) {\r
+           rectangleNode = parent.addNode(RectangleNode.class);\r
+           super.init(parent);\r
+       }\r
+       \r
+       @Override\r
+       public void remove() {\r
+               rectangleNode.remove();\r
+               super.remove();\r
+       }\r
+\r
+       @Override\r
+       protected void update() {\r
+           super.update();\r
+           if(rectangleNode != null)\r
+               rectangleNode.init(bounds);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/TextElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/TextElement.java
new file mode 100644 (file)
index 0000000..59725bd
--- /dev/null
@@ -0,0 +1,160 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import java.awt.Color;\r
+import java.awt.Font;\r
+import java.awt.font.FontRenderContext;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.simantics.h2d.action.IAction;\r
+import org.simantics.h2d.editor.IDiagramEditor;\r
+import org.simantics.h2d.element.handler.Connectable;\r
+import org.simantics.h2d.element.handler.Movable;\r
+import org.simantics.h2d.event.ClickEvent;\r
+import org.simantics.h2d.event.IEvent;\r
+import org.simantics.h2d.event.KeyboardEvent;\r
+import org.simantics.h2d.event.handler.IEventHandler;\r
+import org.simantics.h2d.node.ITextListener;\r
+import org.simantics.h2d.node.TextNode;\r
+import org.simantics.objmap.annotations.GraphType;\r
+import org.simantics.objmap.annotations.RelatedValue;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+\r
+@GraphType("http://www.simantics.org/Sysdyn#Auxiliary")\r
+public class TextElement extends RectangularElement implements Movable, Connectable, IEventHandler {\r
+       \r
+       static final Font FONT = new Font("sans-serif", Font.PLAIN, 12);\r
+       static final double FONT_SCALE = 0.3;\r
+       static final AffineTransform FONT_TRANSFORM = new AffineTransform(FONT_SCALE, 0.0, 0.0, FONT_SCALE, 0.0, 0.0);\r
+       \r
+    static final double XPADDING = 4.0;\r
+    static final double YPADDING = 2.0;\r
+    static final FontRenderContext FRC = new FontRenderContext(FONT_TRANSFORM, true, true);\r
+\r
+    // Properties\r
+    @RelatedValue("http://www.vtt.fi/Simantics/Layer0/1.0/Relations#HasName")\r
+    public String label = "Unnamed";\r
+       \r
+       // Auxiliary fields\r
+       double textX;\r
+       double textY;\r
+       \r
+       TextNode textNode;\r
+       \r
+       public TextElement() {  \r
+       }\r
+       \r
+       public TextElement(String label, double x, double y) {\r
+               this.label = label;\r
+               this.posX = x;\r
+               this.posY = y;\r
+       }\r
+\r
+       @Override\r
+       public void remove() {\r
+               textNode.remove();\r
+       }\r
+\r
+       @Override\r
+       public void init(G2DParentNode parent) {\r
+               textNode = parent.addNode(TextNode.class);\r
+               update();\r
+       }\r
+       \r
+       @Override\r
+       protected void update() {\r
+               Rectangle2D textBounds = FONT.getStringBounds(label, FRC);\r
+               textBounds.setFrame(\r
+                               textBounds.getX()*FONT_SCALE,\r
+                               textBounds.getY()*FONT_SCALE,\r
+                               textBounds.getWidth()*FONT_SCALE,\r
+                               textBounds.getHeight()*FONT_SCALE\r
+                               );\r
+               \r
+               textX = posX-textBounds.getCenterX();\r
+               textY = posY-textBounds.getCenterY();\r
+               bounds.setFrame(\r
+                               posX-textBounds.getWidth()*0.5-XPADDING,\r
+                               posY-textBounds.getHeight()*0.5-YPADDING,\r
+                               textBounds.getWidth()+XPADDING*2,\r
+                               textBounds.getHeight()+YPADDING*2\r
+                               );              \r
+       \r
+               if(textNode != null)\r
+                       textNode.init(label, FONT, Color.BLACK, textX, textY, FONT_SCALE);\r
+               \r
+               super.update();\r
+       }\r
+\r
+       class TextEditingAction implements IAction, ITextListener {\r
+               \r
+               String oldText;\r
+               IDiagramEditor editor;\r
+\r
+        public TextEditingAction(IDiagramEditor editor) {\r
+                       super();\r
+                       this.editor = editor;\r
+               }\r
+\r
+               @Override\r
+        public void init(G2DParentNode parent) {\r
+               oldText = textNode.getText();\r
+               textNode.setEditMode(true);      \r
+               textNode.setTextListener(this);\r
+            /*textFieldNode = parent.addNode(TextFieldNode.class);\r
+            textFieldNode.init(10.0, 10.0);*/\r
+        }\r
+\r
+        @Override\r
+        public void remove() {\r
+               textNode.setEditMode(false);\r
+               textNode.setTextListener(null);\r
+            //textFieldNode.remove();            \r
+        }\r
+\r
+        @Override\r
+        public boolean handle(IDiagramEditor editor, IEvent _event) {\r
+               if(_event instanceof KeyboardEvent) {\r
+                KeyboardEvent event = (KeyboardEvent)_event;\r
+                if(event.key.equals("Escape")) {\r
+                       label = oldText;\r
+                       update();\r
+                       editor.removeAction(this);  \r
+                    editor.requestRepaint();                   \r
+                }\r
+                else if(event.key.equals("Enter"))\r
+                       editor.removeAction(this);\r
+                return true;\r
+            }\r
+               else if(_event instanceof ClickEvent) {\r
+                       editor.removeAction(this);\r
+               }\r
+               return false;\r
+        }\r
+\r
+               @Override\r
+               public void textChanged() {\r
+                       label = textNode.getText();\r
+            update();\r
+            editor.requestRepaint();\r
+               }\r
+           \r
+       }\r
+       \r
+       public void beginRenameAction(IDiagramEditor editor) {\r
+               editor.addAction(new TextEditingAction(editor));\r
+       }\r
+\r
+       @Override\r
+    public boolean handle(IDiagramEditor editor, IEvent _event) {\r
+        if(_event instanceof KeyboardEvent) {\r
+            KeyboardEvent event = (KeyboardEvent)_event;\r
+            if(event.key.equals("F3")) {\r
+                beginRenameAction(editor);\r
+                return true;\r
+            }            \r
+        }\r
+        return false;\r
+    }  \r
+       \r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveElement.java
new file mode 100644 (file)
index 0000000..d2fb9a6
--- /dev/null
@@ -0,0 +1,73 @@
+package org.simantics.sysdyn.ui.elements;\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.geom.Path2D;\r
+\r
+import org.simantics.h2d.element.handler.Connectable;\r
+import org.simantics.h2d.element.handler.Rotatable;\r
+import org.simantics.h2d.node.ShapeNode;\r
+import org.simantics.objmap.annotations.GraphType;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+\r
+@GraphType("http://www.simantics.org/Sysdyn#Valve")\r
+public class ValveElement extends RectangularElement implements Connectable, Rotatable {\r
+        \r
+       public static final double VALVE_SIZE = 5.0;\r
+       \r
+    ShapeNode valveNode;\r
+    boolean rotated = false;\r
+    \r
+       public ValveElement() { \r
+       }\r
+       \r
+       public ValveElement(double x, double y) {\r
+           this.posX = x;\r
+           this.posY = y; \r
+       }\r
+\r
+       @Override\r
+       public void init(G2DParentNode parent) {\r
+               valveNode = parent.addNode(ShapeNode.class);\r
+               valveNode.setColor(Color.BLACK);\r
+               valveNode.setScaleStroke(true);\r
+               valveNode.setStroke(new BasicStroke(1));\r
+               update();\r
+       }\r
+\r
+       @Override\r
+       public void remove() {\r
+               valveNode.remove();\r
+       }\r
+       \r
+       @Override\r
+       protected void update() {\r
+               bounds.setFrame(posX-VALVE_SIZE, posY-VALVE_SIZE, 2.0*VALVE_SIZE, 2.0*VALVE_SIZE);\r
+               Path2D path = new Path2D.Double();\r
+               path.moveTo(posX-VALVE_SIZE, posY-VALVE_SIZE);\r
+               if(rotated) {\r
+                       path.lineTo(posX-VALVE_SIZE, posY+VALVE_SIZE);\r
+                       path.lineTo(posX+VALVE_SIZE, posY-VALVE_SIZE);\r
+               }\r
+               else {                  \r
+                       path.lineTo(posX+VALVE_SIZE, posY-VALVE_SIZE);\r
+                       path.lineTo(posX-VALVE_SIZE, posY+VALVE_SIZE);                  \r
+               }\r
+               path.lineTo(posX+VALVE_SIZE, posY+VALVE_SIZE);\r
+               path.closePath();\r
+               valveNode.setShape(path);\r
+           super.update();\r
+       }\r
+\r
+       @Override\r
+       public void rotate(int amount) {\r
+               if((amount & 1) == 1) {\r
+                       rotated = !rotated;\r
+                       update();\r
+               }\r
+       }\r
+\r
+       public boolean isRotated() {\r
+               return rotated;\r
+       }\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/equation/EquationView.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/equation/EquationView.java
new file mode 100644 (file)
index 0000000..9a513a8
--- /dev/null
@@ -0,0 +1,141 @@
+package org.simantics.sysdyn.ui.equation;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.FocusAdapter;\r
+import org.eclipse.swt.events.FocusEvent;\r
+import org.eclipse.swt.events.KeyAdapter;\r
+import org.eclipse.swt.events.KeyEvent;\r
+import org.eclipse.swt.graphics.Font;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.ISelectionListener;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.db.Builtins;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.sysdyn.SysdynResource;\r
+import org.simantics.ui.SimanticsUI;\r
+\r
+public class EquationView extends ViewPart implements ISelectionListener {\r
+    \r
+    static final Font FONT = new Font(null, "Courier New", 12, SWT.NORMAL);\r
+    \r
+    Text text;\r
+    Resource auxiliary;\r
+    String originalText;\r
+    \r
+    @Override    \r
+    public void createPartControl(Composite parent) {\r
+        getSite().getPage().addPostSelectionListener(this);\r
+        text = new Text(parent, SWT.MULTI);\r
+        text.setFont(FONT);\r
+        text.addFocusListener(new FocusAdapter() {\r
+            \r
+            @Override\r
+            public void focusLost(FocusEvent e) {\r
+                final String currentText = text.getText();\r
+                if(originalText != null && !originalText.equals(currentText)) {\r
+                    SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
+\r
+                        @Override\r
+                        public void perform(WriteGraph g)\r
+                                throws DatabaseException {\r
+                            SysdynResource sr = SysdynResource.getInstance(g);\r
+                            g.claimValue(auxiliary, sr.HasValue, currentText);\r
+                        }\r
+                        \r
+                    });\r
+                }\r
+            }            \r
+            \r
+        });\r
+        text.addKeyListener(new KeyAdapter() {          \r
+                        \r
+            @Override\r
+            public void keyPressed(KeyEvent e) {\r
+                if(e.keyCode == SWT.ESC) {\r
+                    text.setText(originalText);\r
+                }                \r
+            }\r
+            \r
+        });\r
+    }   \r
+\r
+    class UpdateViewRequest extends ReadRequest {\r
+\r
+        Resource resource;\r
+        \r
+        public UpdateViewRequest(Resource resource) {\r
+            this.resource = resource;\r
+        }\r
+        \r
+        @Override\r
+        public void run(ReadGraph g) throws DatabaseException {\r
+            SysdynResource sr = SysdynResource.getInstance(g);\r
+            Builtins b = g.getBuiltins();\r
+            if(g.isInstanceOf(resource, sr.Auxiliary) || g.isInstanceOf(resource, sr.Valve)) {\r
+                auxiliary = resource;\r
+                final String name = g.getRelatedValue(resource, b.HasName);\r
+                final String value = g.getPossibleRelatedValue(resource, sr.HasValue);\r
+                text.getDisplay().asyncExec(new Runnable() {\r
+\r
+                    @Override\r
+                    public void run() {\r
+                        if(value == null)\r
+                            originalText = "";\r
+                        else\r
+                            originalText = value;\r
+                        text.setText(originalText);\r
+                        setPartName("Value of " + name);\r
+                    }\r
+                    \r
+                });\r
+            }\r
+            else if(g.isInstanceOf(resource, sr.Stock)) {\r
+                auxiliary = resource;\r
+                final String name = g.getRelatedValue(resource, b.HasName);\r
+                final String value = g.getPossibleRelatedValue(resource, sr.HasValue);\r
+                text.getDisplay().asyncExec(new Runnable() {\r
+\r
+                    @Override\r
+                    public void run() {\r
+                        if(value == null)\r
+                            originalText = "";\r
+                        else\r
+                            originalText = value;\r
+                        text.setText(originalText);\r
+                        setPartName("Initial value of " + name);\r
+                    }\r
+                    \r
+                });\r
+            }\r
+        }\r
+        \r
+    }\r
+    \r
+    @Override\r
+    public void selectionChanged(IWorkbenchPart part, ISelection selection) {\r
+        if(selection instanceof IStructuredSelection) {\r
+            IStructuredSelection structuredSelection = \r
+                (IStructuredSelection)selection;\r
+            if(structuredSelection.size() == 1) {\r
+                Object element = structuredSelection.getFirstElement();\r
+                if(element instanceof Resource)\r
+                    SimanticsUI.getSession().asyncRequest(new UpdateViewRequest((Resource)element));\r
+            }\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void setFocus() {\r
+        text.setFocus();\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/modelica/ModelicaView.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/modelica/ModelicaView.java
new file mode 100644 (file)
index 0000000..fb88416
--- /dev/null
@@ -0,0 +1,30 @@
+package org.simantics.sysdyn.ui.modelica;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.ui.ISelectionListener;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.part.ViewPart;\r
+\r
+public class ModelicaView extends ViewPart implements ISelectionListener {\r
+    \r
+    @Override    \r
+    public void createPartControl(Composite parent) {\r
+        getSite().getPage().addPostSelectionListener(this);\r
+        new Label(parent, SWT.NONE).setText("Hello World!");\r
+    }   \r
+\r
+    @Override\r
+    public void setFocus() {\r
+        // TODO Auto-generated method stub\r
+\r
+    }\r
+\r
+    @Override\r
+    public void selectionChanged(IWorkbenchPart part, ISelection selection) {\r
+        System.out.println("selection changed");\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynPerspectiveFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynPerspectiveFactory.java
new file mode 100644 (file)
index 0000000..9f6b257
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.sysdyn.ui.project;\r
+\r
+import org.eclipse.ui.IFolderLayout;\r
+import org.eclipse.ui.IPageLayout;\r
+import org.eclipse.ui.IPerspectiveFactory;\r
+\r
+public class SysdynPerspectiveFactory implements IPerspectiveFactory {\r
+\r
+    @Override\r
+    public void createInitialLayout(IPageLayout layout) {\r
+        layout.setEditorAreaVisible(true);\r
+        String editorArea = layout.getEditorArea();\r
+\r
+        IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, 0.25f, editorArea);\r
+        left.addView("org.simantics.ode.views.ontologyBrowser");\r
+        \r
+        IFolderLayout bottom = layout.createFolder("bottom", IPageLayout.BOTTOM, 0.75f, editorArea);\r
+        bottom.addView("org.simantics.sysdyn.ui.equation.view");\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java
new file mode 100644 (file)
index 0000000..7324bc4
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.sysdyn.ui.project;\r
+\r
+import org.simantics.project.ProjectKeys;\r
+import org.simantics.project.exception.ProjectException;\r
+import org.simantics.project.features.AbstractProjectFeature;\r
+\r
+public class SysdynProject extends AbstractProjectFeature {\r
+    private static final String DEFAULT_PERSPECTIVE = "org.simantics.sysdyn.ui.perspective";\r
+    \r
+    @Override\r
+    public void configure() throws ProjectException {\r
+        addToCollectionHint(ProjectKeys.PERSPECTIVES, DEFAULT_PERSPECTIVE);\r
+        addToCollectionHint(ProjectKeys.OPEN_PERSPECTIVES, DEFAULT_PERSPECTIVE);\r
+        getProjectElement().setHint(ProjectKeys.DEFAULT_PERSPECTIVE, DEFAULT_PERSPECTIVE);\r
+    }\r
+\r
+    @Override\r
+    public void deconfigure() throws ProjectException {\r
+    }\r
+\r
+}\r