Merge "InputStream returns -1 on EOF instead of throwing IOException"
authorJani Simomaa <jani.simomaa@vtt.fi>
Mon, 17 Oct 2016 07:41:11 +0000 (10:41 +0300)
committerGerrit Code Review <gerrit2@www.simantics.org>
Mon, 17 Oct 2016 07:41:11 +0000 (10:41 +0300)
59 files changed:
bundles/org.simantics.browsing.ui.nattable/images/transparent.png [new file with mode: 0644]
bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GENatTableThemeConfiguration.java
bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeLayer.java
bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeRowModel.java
bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/KeyToSelectionAdapter.java [new file with mode: 0644]
bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableGraphExplorer.java
bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableSelectionAdaptor.java
bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/TreeNode.java
bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/DefaultBindingFactory.java
bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/JavaUtilBindingsProvider.java
bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/TroveBindingsProvider.java
bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/DefaultMapBinding.java [new file with mode: 0644]
bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/DefaultSetBinding.java [new file with mode: 0644]
bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashMapBinding.java
bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashSetBinding.java
bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/TreeSetBinding.java
bundles/org.simantics.diagram.ontology/graph.tg
bundles/org.simantics.diagram.ontology/graph/DiagramProfiles.pgraph
bundles/org.simantics.diagram.ontology/src/org/simantics/diagram/stubs/DiagramResource.java
bundles/org.simantics.diagram/src/org/simantics/diagram/connection/ModelledConnectionAdvisor.java
bundles/org.simantics.diagram/src/org/simantics/diagram/flag/AbstractFlagType.java
bundles/org.simantics.diagram/src/org/simantics/diagram/flag/FlagUtil.java
bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectTool2.java
bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionBuilder.java
bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/Profiles.java
bundles/org.simantics.document.server.io/src/org/simantics/document/server/io/Content.java
bundles/org.simantics.event/src/org/simantics/event/util/EventUtils.java
bundles/org.simantics.event/src/org/simantics/event/view/contribution/ProjectEventsRule.java
bundles/org.simantics.event/src/org/simantics/event/view/handler/Hide.java [deleted file]
bundles/org.simantics.event/src/org/simantics/event/view/handler/MenuActions.java
bundles/org.simantics.event/src/org/simantics/event/view/handler/TagAction.java
bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/pointertool/TerminalUtil.java
bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/BranchPointTerminal.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncActiveModelTypicals.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncActiveModelTypicals.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalInstanceWithTemplate.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalTemplateToInstances.java
bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java
bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java
bundles/org.simantics.scenegraph/.classpath
bundles/org.simantics.scenegraph/META-INF/MANIFEST.MF
bundles/org.simantics.scenegraph/build.properties
bundles/org.simantics.scenegraph/lib/batik-awt-util-1.8.jar [new file with mode: 0644]
bundles/org.simantics.scenegraph/lib/batik-parser-1.8.jar [new file with mode: 0644]
bundles/org.simantics.scenegraph/lib/batik-util-1.8.jar [new file with mode: 0644]
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/ActionShapes.java [new file with mode: 0644]
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/RouteGraphNode.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/JavaMathOperation.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/java/JavaModule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/elaboration/constraints/ReduceSerializable.java
bundles/org.simantics.scl.db/scl/Simantics/DB.scl
bundles/org.simantics.scl.runtime/scl/Databoard.scl [new file with mode: 0644]
bundles/org.simantics.scl.runtime/scl/Prelude.scl
bundles/org.simantics.scl.runtime/scl/StandardLibrary.scl
bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java

diff --git a/bundles/org.simantics.browsing.ui.nattable/images/transparent.png b/bundles/org.simantics.browsing.ui.nattable/images/transparent.png
new file mode 100644 (file)
index 0000000..e9cd02b
Binary files /dev/null and b/bundles/org.simantics.browsing.ui.nattable/images/transparent.png differ
index bcb8bba53a445da1172ffebca139e83bd6486ee5..41d5f2e4617bfe6b628e881186371e3a811d0fb5 100644 (file)
@@ -1,13 +1,19 @@
 package org.simantics.browsing.ui.nattable;\r
 \r
+import org.eclipse.core.runtime.FileLocator;\r
+import org.eclipse.core.runtime.Path;\r
+import org.eclipse.nebula.widgets.nattable.painter.cell.BackgroundPainter;\r
 import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter;\r
 import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.PaddingDecorator;\r
 import org.eclipse.nebula.widgets.nattable.style.theme.ModernNatTableThemeConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.tree.painter.IndentedTreeImagePainter;\r
+import org.eclipse.nebula.widgets.nattable.tree.painter.TreeImagePainter;\r
+import org.eclipse.nebula.widgets.nattable.ui.util.CellEdgeEnum;\r
 import org.eclipse.nebula.widgets.nattable.util.GUIHelper;\r
 \r
 public class GENatTableThemeConfiguration extends ModernNatTableThemeConfiguration{\r
        \r
-       public GENatTableThemeConfiguration(GETreeData treeData) {\r
+       public GENatTableThemeConfiguration(GETreeData treeData, int style) {\r
                super();\r
                this.oddRowBgColor = GUIHelper.getColor(250, 250, 250);\r
                this.defaultCellPainter =\r
@@ -20,6 +26,55 @@ public class GENatTableThemeConfiguration extends ModernNatTableThemeConfigurati
                                        0,\r
                                        5,\r
                                        false)));\r
+               \r
+                TreeImagePainter treeImagePainter =\r
+                       new TreeImagePainter(\r
+                               false,\r
+                               GUIHelper.getImage("right"), //$NON-NLS-1$\r
+                               GUIHelper.getImage("right_down"), //$NON-NLS-1$\r
+                               GUIHelper.getImageByURL("transparent", \r
+                                               FileLocator.find(Activator.getDefault().getBundle(), \r
+                                               new Path("images/transparent.png"), null))); //$NON-NLS-1$\r
+               this.treeStructurePainter =\r
+                       new BackgroundPainter(\r
+                               new PaddingDecorator(\r
+                                       new IndentedTreeImagePainter(\r
+                                               10,\r
+                                               null,\r
+                                               CellEdgeEnum.LEFT,\r
+                                               treeImagePainter,\r
+                                               false,\r
+                                               2,\r
+                                               true),\r
+                                       0,\r
+                                       5,\r
+                                       0,\r
+                                       5,\r
+                                       false));\r
+               TreeImagePainter treeSelectionImagePainter =\r
+                       new TreeImagePainter(\r
+                               false,\r
+                               GUIHelper.getImage("right_inv"), //$NON-NLS-1$\r
+                               GUIHelper.getImage("right_down_inv"), //$NON-NLS-1$\r
+                               GUIHelper.getImageByURL("transparent", \r
+                                               FileLocator.find(Activator.getDefault().getBundle(), \r
+                                               new Path("images/transparent.png"), null))); //$NON-NLS-1$\r
+               this.treeStructureSelectionPainter =\r
+                       new BackgroundPainter(\r
+                               new PaddingDecorator(\r
+                                       new IndentedTreeImagePainter(\r
+                                               10,\r
+                                               null,\r
+                                               CellEdgeEnum.LEFT,\r
+                                               treeSelectionImagePainter,\r
+                                               false,\r
+                                               2,\r
+                                               true),\r
+                                       0,\r
+                                       5,\r
+                                       0,\r
+                                       5,\r
+                                       false));\r
        }\r
 \r
 }\r
index dbc30050ae63a0ac038bcc441cec4ddbb358bfa2..309e4daa85f5bfa084416b043449d90be8250b65 100644 (file)
@@ -1,9 +1,9 @@
 package org.simantics.browsing.ui.nattable;\r
 \r
 import java.util.ArrayList;\r
-import java.util.Collection;\r
 import java.util.Collections;\r
 import java.util.Comparator;\r
+import java.util.HashSet;\r
 import java.util.Iterator;\r
 import java.util.List;\r
 import java.util.Set;\r
@@ -31,7 +31,7 @@ import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
 public class GETreeLayer  extends TreeLayer2 {\r
 \r
        //Set<IEcoReportTask> collapsed = new HashSet<IEcoReportTask>();\r
-       Set<TreeNode> collapsed = new IdentityHashSet<TreeNode>();\r
+       Set<TreeNode> expanded = new IdentityHashSet<TreeNode>();\r
        GETreeData treeData;\r
        Comparator<int[]> comparator = new FirstElementComparator();\r
        \r
@@ -51,7 +51,7 @@ public class GETreeLayer  extends TreeLayer2 {
        @Override\r
        public void collapseTreeRow(int parentIndex) {\r
                TreeNode task = treeData.getDataAtIndex(parentIndex);\r
-               collapsed.add(task);\r
+               expanded.remove(task);\r
                task.setExpanded(false);\r
                super.collapseTreeRow(parentIndex);\r
        }\r
@@ -73,7 +73,7 @@ public class GETreeLayer  extends TreeLayer2 {
        @Override\r
        public void expandTreeRow(int parentIndex) {\r
                TreeNode task = treeData.getDataAtIndex(parentIndex);\r
-               collapsed.remove(task);\r
+               expanded.add(task);\r
                task.setExpanded(true);\r
                super.expandTreeRow(parentIndex);\r
        }\r
@@ -117,7 +117,7 @@ public class GETreeLayer  extends TreeLayer2 {
                                TreeNode task = treeData.getDataAtIndex(parentIndex);\r
                                if (task != null) {\r
                                        task.setExpanded(false);\r
-                                       collapsed.add(task);\r
+                                       expanded.remove(task);\r
                                }\r
                                rowIndexes.addAll(getModel().collapse(parentIndex));\r
                        }\r
@@ -145,7 +145,7 @@ public class GETreeLayer  extends TreeLayer2 {
                        if (parentIndex >= 0) {\r
                                TreeNode task = treeData.getDataAtIndex(parentIndex);\r
                                task.setExpanded(false);\r
-                               collapsed.add(task);\r
+                               expanded.remove(task);\r
                                rowIndexes.addAll(getModel().collapse(parentIndex));\r
                        }\r
                }\r
@@ -175,7 +175,7 @@ public class GETreeLayer  extends TreeLayer2 {
                                \r
                        } \r
                        t.setExpanded(false);\r
-                       collapsed.add(t);\r
+                       expanded.remove(t);\r
                        getModel().collapse(i);\r
                        \r
                }\r
@@ -189,8 +189,9 @@ public class GETreeLayer  extends TreeLayer2 {
                for (int parentIndex : parentIndices) {\r
                        TreeNode task = treeData.getDataAtIndex(parentIndex);\r
                        task.setExpanded(true);\r
-                       collapsed.remove(task);\r
+                       expanded.add(task);\r
                        rowIndexes.addAll(getModel().expand(parentIndex));\r
+                       rowIndexes.add(parentIndex);\r
                }\r
                \r
                //Implementation uses tree set, so removing in reverse order is faster.\r
@@ -207,7 +208,7 @@ public class GETreeLayer  extends TreeLayer2 {
                for (int parentIndex : parentIndices) {\r
                        TreeNode task = treeData.getDataAtIndex(parentIndex);\r
                        task.setExpanded(true);\r
-                       collapsed.remove(task);\r
+                       expanded.add(task);\r
                        rowIndexes.addAll(getModel().expand(parentIndex));\r
                }\r
                \r
@@ -220,20 +221,20 @@ public class GETreeLayer  extends TreeLayer2 {
                fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes));\r
        }\r
        \r
-       public void expandAllRows() {\r
-               Collection<Integer> parentIndices = getHiddenRowIndexes();\r
-               List<Integer> rowIndexes = new ArrayList<Integer>();\r
-               for (int parentIndex : parentIndices) {\r
-                       rowIndexes.addAll(getModel().expand(parentIndex));\r
-               }\r
-               for (TreeNode t : collapsed)\r
-                       t.setExpanded(true);\r
-               collapsed.clear();\r
-               getHiddenRowIndexes().clear();\r
-               ((GETreeRowModel)getModel()).clear();\r
-               invalidateCache();\r
-               fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes));\r
-       }\r
+//     public void expandAllRows() {\r
+//             Collection<Integer> parentIndices = getHiddenRowIndexes();\r
+//             List<Integer> rowIndexes = new ArrayList<Integer>();\r
+//             for (int parentIndex : parentIndices) {\r
+//                     rowIndexes.addAll(getModel().expand(parentIndex));\r
+//             }\r
+//             for (TreeNode t : collapsed)\r
+//                     t.setExpanded(true);\r
+//             collapsed.clear();\r
+//             getHiddenRowIndexes().clear();\r
+//             ((GETreeRowModel)getModel()).clear();\r
+//             invalidateCache();\r
+//             fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes));\r
+//     }\r
        \r
        @Override\r
        protected void invalidateCache() {\r
@@ -242,6 +243,23 @@ public class GETreeLayer  extends TreeLayer2 {
                hiddenPos.add(new int[]{0,0});\r
        }\r
        \r
+       private void _collapseAllRows() {\r
+               int count = treeData.getElementCount();\r
+               List <Integer> rowIndexes = new ArrayList<Integer>(count);\r
+               for (int i = 0; i < count; i++) {\r
+                       TreeNode t = treeData.getDataAtIndex(i);\r
+                       // we don't want to hide the roots of the tree\r
+                       if (!treeData.isRoot(t)) { \r
+                               rowIndexes.add(i);\r
+                               \r
+                       } \r
+                       getModel().collapse(i);\r
+                       \r
+               }\r
+               this.getHiddenRowIndexes().addAll(rowIndexes);\r
+               invalidateCache();\r
+       }\r
+       \r
        @Override\r
        public void handleLayerEvent(ILayerEvent event) {\r
                // Currently sorting is implemented by sorting the underlaying list.\r
@@ -251,31 +269,68 @@ public class GETreeLayer  extends TreeLayer2 {
                // Another option would use some sort of sorting layers, so that the original data is kept intact, and\r
                // sorting layer would map the row indexes to sorted row positions.\r
                \r
-               // preserve collapsed nodes \r
+               // preserve expanded nodes \r
                Set<TreeNode> coll = null;\r
+//             int hiddenCount = 0;\r
                if (event instanceof IStructuralChangeEvent) {\r
                        IStructuralChangeEvent structuralChangeEvent = (IStructuralChangeEvent) event;\r
                        if (structuralChangeEvent.isVerticalStructureChanged()) {\r
-                               // expand old indices\r
-                               ((GETreeRowModel)getModel()).clear();\r
+                               // store old indices\r
+                               internalRefresh = true;\r
+                               ((GETreeRowModel<?>)getModel()).clear();\r
+//                             hiddenCount = getHiddenRowIndexes().size();\r
                                getHiddenRowIndexes().clear();\r
-                               coll = collapsed;\r
+                               // store expanded nodes and clear disposed nodes.\r
+                               coll = new HashSet<>();\r
+                               for (TreeNode n : expanded)\r
+                                       if (!n.isDisposed())\r
+                                               coll.add(n);\r
+                               expanded.clear();\r
+                               expanded.addAll(coll);\r
+                               // filter hidden nodes (nodes that have collapsed ancestors)\r
+                               coll.clear();\r
+                               for (TreeNode n : expanded)\r
+                                       if (!n.isHidden())\r
+                                               coll.add(n);\r
                        }\r
                }\r
                super.handleLayerEvent(event);\r
                if (coll != null) {\r
-                       // collapse new indices\r
+                       _collapseAllRows();\r
+                       // expand new indices\r
                        int ind[] = new int[coll.size()];\r
                        Iterator<TreeNode> iter = coll.iterator();\r
                        for (int i = 0; i < ind.length; i++) {\r
                                ind[i] = treeData.indexOf(iter.next());\r
                        }\r
-                       collapseTreeRow(ind);\r
+                       expandTreeRow(ind);\r
+//                     if (getHiddenRowIndexes().size() != hiddenCount) {\r
+//                             System.out.println(getHiddenRowIndexes().size() + " != " + hiddenCount);\r
+//                             ((GETreeRowModel<?>)getModel()).clear();\r
+//                             getHiddenRowIndexes().clear();\r
+//                             _collapseAllRows();\r
+//                             //collapseAll();\r
+//                             // expand new indices\r
+//                             iter = coll.iterator();\r
+//                             for (int i = 0; i < ind.length; i++) {\r
+//                                     ind[i] = treeData.indexOf(iter.next());\r
+//                             }\r
+//                             expandTreeRow(ind);\r
+//                     }\r
+                       internalRefresh = false;\r
                }\r
        }\r
        \r
-       public Set<TreeNode> getCollapsed() {\r
-               return collapsed;\r
+       private boolean internalRefresh = false;\r
+       \r
+       public void fireLayerEvent(ILayerEvent event) {\r
+               if (!internalRefresh)\r
+                       super.fireLayerEvent(event);\r
+               \r
+       }\r
+       \r
+       public Set<TreeNode> getExpanded() {\r
+               return expanded;\r
        }\r
        \r
        List<int[]> hiddenPos;\r
index ebfb962db7a129cf7af9cdc93e7f64f433d2585c..762b47ce008ab29f1e96d8ed520ba402d0e685d5 100644 (file)
@@ -22,7 +22,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
 public class GETreeRowModel<T> implements ITreeRowModel<T>{\r
        //private final HashSet<Integer> parentIndexes = new HashSet<Integer>();\r
        //private final TIntHashSet parentIndexes = new TIntHashSet(1000, 0.8f);\r
-       private final IntOpenHashSet parentIndexes = new IntOpenHashSet();\r
+       private final IntOpenHashSet expandedIndexes = new IntOpenHashSet();\r
 \r
        private final Collection<ITreeRowModelListener> listeners = new HashSet<ITreeRowModelListener>();\r
 \r
@@ -59,11 +59,11 @@ public class GETreeRowModel<T> implements ITreeRowModel<T>{
        }\r
        \r
        public boolean isCollapsed(int index) {\r
-               return this.parentIndexes.contains(index);\r
+               return !this.expandedIndexes.contains(index);\r
        }\r
 \r
        public void clear() {\r
-               this.parentIndexes.clear();\r
+               this.expandedIndexes.clear();\r
        }\r
        \r
        @Override\r
@@ -73,16 +73,18 @@ public class GETreeRowModel<T> implements ITreeRowModel<T>{
 \r
        @Override\r
        public List<Integer> collapse(int index) {\r
-               this.parentIndexes.add(index);\r
+               this.expandedIndexes.remove(index);\r
                notifyListeners();\r
-               return getChildIndexes(index);\r
+               List<Integer> list = getChildIndexes(index);\r
+               //this.parentIndexes.addAll(list);\r
+               return list;\r
        }\r
        \r
        \r
 \r
        @Override\r
        public List<Integer> expand(int index) {\r
-               this.parentIndexes.remove(index);\r
+               this.expandedIndexes.add(index);\r
                notifyListeners();\r
                List<Integer> children = getExpandedChildIndexes(index);\r
                return children;\r
@@ -90,7 +92,6 @@ public class GETreeRowModel<T> implements ITreeRowModel<T>{
        \r
        @Override\r
        public List<Integer> collapseAll() {\r
-               // TODO Auto-generated method stub\r
                return null;\r
        }\r
        \r
@@ -195,7 +196,7 @@ public class GETreeRowModel<T> implements ITreeRowModel<T>{
                        int index = this.treeData.indexOf(child);\r
                        if (index >= 0) {\r
                                result.add(index);\r
-                               if (!parentIndexes.contains(index))\r
+                               if (expandedIndexes.contains(index))\r
                                        result.addAll(getExpandedChildIndexes(index));\r
                        } else {\r
                                result.addAll(getExpandedChildIndexes(child));\r
@@ -211,7 +212,7 @@ public class GETreeRowModel<T> implements ITreeRowModel<T>{
                        int index = this.treeData.indexOf(child);\r
                        if (index >= 0) {\r
                                result.add(index);\r
-                               if (!parentIndexes.contains(index))\r
+                               if (expandedIndexes.contains(index))\r
                                        result.addAll(getExpandedChildIndexes(index));\r
                        } else {\r
                                result.addAll(getExpandedChildIndexes(child));\r
diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/KeyToSelectionAdapter.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/KeyToSelectionAdapter.java
new file mode 100644 (file)
index 0000000..9d43c35
--- /dev/null
@@ -0,0 +1,163 @@
+package org.simantics.browsing.ui.nattable;\r
+\r
+import java.util.Collection;\r
+import java.util.List;\r
+import java.util.regex.Pattern;\r
+\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.nebula.widgets.nattable.NatTable;\r
+import org.eclipse.swt.events.KeyAdapter;\r
+import org.eclipse.swt.events.KeyEvent;\r
+import org.simantics.browsing.ui.GraphExplorer;\r
+import org.simantics.utils.ui.AdaptionUtils;\r
+\r
+/**\r
+ * Selects tree items based on pressed key events.<p>\r
+ * \r
+ * The default implementation of SWT.Tree (Windows?) uses only the the first column when matching the items.<p>\r
+ * \r
+ * This implementation checks all columns. Override <pre>matches(), matchesColumn()</pre> for customized behavior.<p>\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class KeyToSelectionAdapter extends KeyAdapter {\r
+\r
+       private static final int KEY_INPUT_DELAY = 500;\r
+       \r
+    private final NatTableGraphExplorer          explorer;\r
+\r
+    private String matcher = "";\r
+    private int prevEvent = 0;\r
+    private int columns = 0;\r
+        \r
+    protected Pattern alphaNum;\r
+    \r
+    /**\r
+     * @param contextProvider\r
+     * @param explorer\r
+     */\r
+    public KeyToSelectionAdapter(GraphExplorer explorer) {\r
+        assert explorer != null;\r
+\r
+        this.explorer = (NatTableGraphExplorer)explorer;\r
+        this.alphaNum = Pattern.compile("\\p{Alnum}");\r
+    }\r
+\r
+    @Override\r
+    public void keyPressed(KeyEvent e) {\r
+       if (explorer.isDisposed())\r
+            return;\r
+\r
+         \r
+         if (!alphaNum.matcher(Character.toString(e.character)).matches())\r
+                return;\r
+         // concatenate / replace matcher.\r
+         if ((e.time - prevEvent) > KEY_INPUT_DELAY )\r
+                matcher = "";\r
+        prevEvent = e.time;\r
+        matcher = matcher += Character.toString(e.character);\r
+\r
+        \r
+        //TreeItem item = null;\r
+        NatTable tree = explorer.getControl();\r
+        columns = explorer.getColumns().length;\r
+        \r
+        IStructuredSelection sel = (IStructuredSelection)explorer.getWidgetSelection();\r
+        Collection<RowSelectionItem> selected = AdaptionUtils.adaptToCollection(sel, RowSelectionItem.class);\r
+        \r
+         \r
+        TreeNode item = find(tree, selected);\r
+        \r
+        if (item == null && matcher.length() > 1) {\r
+                matcher = matcher.substring(matcher.length()-1);\r
+                item = find(tree, selected);\r
+        }\r
+        \r
+        if (item != null) {\r
+                explorer.select(item);\r
+                explorer.show(item);\r
+//                      tree.select(item);\r
+//                      tree.showItem(item);\r
+                \r
+                       \r
+                } \r
+        // without this the default handling would take over.\r
+        e.doit = false;\r
+    }\r
+    \r
+    private TreeNode previous = null;\r
+    private boolean foundPrev = false;\r
+    \r
+       private TreeNode find(NatTable tree, Collection<RowSelectionItem> selected) {\r
+               TreeNode item = null;\r
+\r
+               List<TreeNode> items = explorer.getItems();\r
+               \r
+               if (selected.size() == 0) {\r
+                       previous = null;\r
+                       foundPrev = true;\r
+                       item = findItem(items);\r
+\r
+               } else {\r
+                       previous = selected.iterator().next().item;\r
+                       foundPrev = false;\r
+                       item = findItem(items);\r
+                       if (item == null) {\r
+                               previous = null;\r
+                               foundPrev = true;\r
+                               item = findItem(items);\r
+                       }\r
+               }\r
+               return item;\r
+       }\r
+    \r
+    private TreeNode findItem(List<TreeNode> items) {\r
+       for (int i = 0; i < items.size(); i++) {\r
+               TreeNode item = items.get(i);\r
+               if (item != previous) {\r
+                       if (foundPrev && matches(item, columns, matcher))\r
+                               return item;\r
+                       \r
+               } else {\r
+                       foundPrev = true;\r
+               }\r
+       }\r
+       return null;\r
+    }\r
+    \r
+    \r
+    /**\r
+     * \r
+     * @param item\r
+     * @param depth Depth of the item in the tree.\r
+     * @param columns Number of columns.\r
+     * @param string Matching string.\r
+     * @return\r
+     */\r
+    protected boolean matches(TreeNode item, int columns, String matcher) {\r
+       for (int c = 0; c < columns; c++) {     \r
+                       if (matchesColumn(item, c, matcher)) {\r
+                               return true;\r
+                       }\r
+               }\r
+       return false;\r
+    }\r
+    \r
+    /**\r
+     * \r
+     * @param item\r
+     * @param column\r
+     * @param matcher\r
+     * @return\r
+     */\r
+    protected boolean matchesColumn(TreeNode item, int column, String matcher) {\r
+       String text = item.getValueString(column);\r
+               if (text.toLowerCase().startsWith(matcher)) {\r
+                       return true;\r
+               }\r
+               return false;\r
+    }\r
+\r
+\r
+}\r
index aa2c5b21e568485fdfdd709534a2619cf252b711..f38f5fd9350bae2d3b5f4ecf338eb396afb2527b 100644 (file)
@@ -28,8 +28,6 @@ import org.eclipse.core.runtime.MultiStatus;
 import org.eclipse.core.runtime.Platform;\r
 import org.eclipse.core.runtime.Status;\r
 import org.eclipse.core.runtime.jobs.Job;\r
-import org.eclipse.jface.layout.GridDataFactory;\r
-import org.eclipse.jface.layout.TreeColumnLayout;\r
 import org.eclipse.jface.resource.ColorDescriptor;\r
 import org.eclipse.jface.resource.DeviceResourceException;\r
 import org.eclipse.jface.resource.DeviceResourceManager;\r
@@ -55,11 +53,13 @@ import org.eclipse.nebula.widgets.nattable.coordinate.Range;
 import org.eclipse.nebula.widgets.nattable.data.IDataProvider;\r
 import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;\r
 import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDisplayConverter;\r
+import org.eclipse.nebula.widgets.nattable.data.validate.IDataValidator;\r
+import org.eclipse.nebula.widgets.nattable.data.validate.ValidationFailedException;\r
 import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;\r
 import org.eclipse.nebula.widgets.nattable.edit.EditConfigHelper;\r
 import org.eclipse.nebula.widgets.nattable.edit.ICellEditHandler;\r
-import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditBindings;\r
 import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.edit.config.DialogErrorHandling;\r
 import org.eclipse.nebula.widgets.nattable.edit.editor.AbstractCellEditor;\r
 import org.eclipse.nebula.widgets.nattable.edit.editor.ComboBoxCellEditor;\r
 import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor;\r
@@ -85,14 +85,18 @@ import org.eclipse.nebula.widgets.nattable.layer.LabelStack;
 import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnOverrideLabelAccumulator;\r
 import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;\r
 import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;\r
-import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;\r
+import org.eclipse.nebula.widgets.nattable.painter.NatTableBorderOverlayPainter;\r
 import org.eclipse.nebula.widgets.nattable.reorder.ColumnReorderLayer;\r
 import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;\r
 import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;\r
+import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand;\r
 import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;\r
 import org.eclipse.nebula.widgets.nattable.style.DisplayMode;\r
+import org.eclipse.nebula.widgets.nattable.style.Style;\r
 import org.eclipse.nebula.widgets.nattable.ui.menu.AbstractHeaderMenuConfiguration;\r
 import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder;\r
+import org.eclipse.nebula.widgets.nattable.util.GUIHelper;\r
 import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;\r
 import org.eclipse.nebula.widgets.nattable.widget.EditModeEnum;\r
 import org.eclipse.swt.SWT;\r
@@ -106,7 +110,6 @@ import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;\r
 import org.eclipse.swt.events.SelectionListener;\r
 import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.graphics.GC;\r
 import org.eclipse.swt.graphics.Point;\r
 import org.eclipse.swt.graphics.RGB;\r
 import org.eclipse.swt.graphics.Rectangle;\r
@@ -202,11 +205,13 @@ import gnu.trove.map.hash.THashMap;
 import gnu.trove.map.hash.TObjectIntHashMap;\r
 \r
 /**\r
- * NatTable base GraphExplorer\r
+ * NatTable based GraphExplorer\r
+ * \r
+ * This GraphExplorer is not fully compatible with the other implementations, since it is not based on SWT.Tree. \r
+ * \r
+ * This implementation is useful in scenarios, where there are a lot of data to be displayed, the performance of NatTable is much better to SWT.Tree based implementations.\r
  * \r
  * \r
- * FIXME : asynchronous node loading does not work properly + check expanded/collapsed sate handling\r
- * TODO: InputValidators + input errors\r
  * TODO: ability to hide headers\r
  * TODO: code cleanup (copied from GraphExplorerImpl2) \r
  * \r
@@ -214,7 +219,7 @@ import gnu.trove.map.hash.TObjectIntHashMap;
  *\r
  */\r
 public class NatTableGraphExplorer extends GraphExplorerImplBase implements GraphExplorer{\r
-    public static final int      DEFAULT_MAX_CHILDREN                    = 1000;\r
+    public static final int      DEFAULT_MAX_CHILDREN                    = 10000;\r
        private static final boolean DEBUG_SELECTION_LISTENERS = false;\r
        private static final boolean DEBUG = false;\r
        \r
@@ -349,7 +354,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                originalFont = JFaceResources.getDefaultFontDescriptor();\r
 \r
                columns = new Column[0];\r
-               createNatTable();\r
+               createNatTable(style);\r
                layout = new NatTableColumnLayout(natTable, columnHeaderDataProvider, rowHeaderDataLayer);\r
                this.composite.setLayout(layout);\r
                                \r
@@ -531,8 +536,6 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
         //refreshColumnSizes();\r
         rootNode = new TreeNode(rootContext, explorerContext);\r
         if (DEBUG) System.out.println("setRoot " + rootNode);\r
-      \r
-       // viewer.setInput(rootNode);\r
         \r
         // Delay content reading.\r
         \r
@@ -545,8 +548,8 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                        public void run() {\r
                                if (rootNode != null) {\r
                                    rootNode.updateChildren();\r
+                                   rootNode.setExpanded(true);\r
                                    listReIndex();\r
-                                   natTable.refresh(true);\r
                                }\r
                        }\r
                });\r
@@ -554,9 +557,13 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
     }\r
     \r
     private synchronized void listReIndex() {\r
+       for (TreeNode n : list) {\r
+               n.setListIndex(-2);\r
+       }\r
        list.clear();\r
        for (TreeNode c : rootNode.getChildren())\r
                _insertToList(c);\r
+       natTable.refresh();\r
     }\r
     \r
     private void _insertToList(TreeNode n) {\r
@@ -567,6 +574,10 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
        }\r
     }\r
     \r
+    public List<TreeNode> getItems() {\r
+       return Collections.unmodifiableList(list);\r
+    }\r
+    \r
     private void initializeState() {\r
         if (persistor == null)\r
             return;\r
@@ -689,7 +700,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                     if (natTable.isDisposed())\r
                         return;\r
                     doSetColumns(columns, callback);\r
-                    natTable.refresh(true);\r
+                    natTable.refresh();\r
                     natTable.getParent().layout();\r
                 }\r
             });\r
@@ -1065,6 +1076,30 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
         \r
     }\r
     \r
+       public boolean select(TreeNode node) {\r
+               assertNotDisposed();\r
+\r
+               if (!list.contains(node)) {\r
+                       StructuredSelection s = new StructuredSelection();\r
+            selectionAdaptor.setSelection(s);\r
+            selectionProvider.setAndFireNonEqualSelection(s);\r
+                       return true;\r
+               }\r
+               selectionAdaptor.setSelection(new StructuredSelection(node));\r
+               return false;\r
+       }\r
+       \r
+       public void show(TreeNode node) {\r
+               int index = node.getListIndex();\r
+               \r
+               int position = treeLayer.getRowPositionByIndex(index);\r
+               if (position < 0) {\r
+                       treeLayer.expandToTreeRow(index);\r
+                       position = treeLayer.getRowPositionByIndex(index);\r
+               }\r
+               viewportLayer.moveRowPositionIntoViewport(position);\r
+       }\r
+    \r
     @Override\r
     public boolean selectPath(Collection<NodeContext> contexts) {\r
        \r
@@ -1171,7 +1206,6 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                else\r
                        treeLayer.collapseTreeRow(n.getListIndex());\r
        }\r
-       //viewer.setExpandedState(context, expanded);\r
        \r
     }\r
     \r
@@ -1179,7 +1213,6 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
     public void setAutoExpandLevel(int level) {\r
         this.autoExpandLevel = level;\r
         treeLayer.expandAllToLevel(level);\r
-        //viewer.setAutoExpandLevel(level);\r
     }\r
     \r
     int maxChildren = DEFAULT_MAX_CHILDREN;\r
@@ -1244,22 +1277,51 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                                if (element.isDisposed()) {\r
                                return;\r
                                }\r
-                       if (((TreeNode)element).updateChildren()) {\r
+                       if (element.updateChildren()) {\r
+                               if (DEBUG) {\r
+                                       System.out.println("Update Item updateChildren " + element.listIndex + " " + element);\r
+                                       printDebug(NatTableGraphExplorer.this);\r
+                               }\r
                                listReIndex();\r
-                               natTable.refresh(true);\r
-                               //viewer.refresh(element,true);\r
+                               if (!element.isHidden()) { \r
+                                       if (!element.isExpanded()) {\r
+                                               if (element.listIndex >= 0)\r
+                                                       treeLayer.collapseTreeRow(element.listIndex);\r
+                                               if (DEBUG) {\r
+                                                       System.out.println("Update Item collapse " + element.listIndex);\r
+                                                       printDebug(NatTableGraphExplorer.this);\r
+                                               }\r
+                                       } else {\r
+                                               for (TreeNode c : element.getChildren())\r
+                                                       c.initData();\r
+                                       }\r
+                               } else {\r
+                                       TreeNode p = element.getCollapsedAncestor();\r
+                                       if (p != null) {\r
+                                               if (element.listIndex >= 0)\r
+                                                       treeLayer.collapseTreeRow(element.listIndex);\r
+                                               if (p.listIndex >= 0) \r
+                                                       treeLayer.collapseTreeRow(p.listIndex);\r
+                                               if (DEBUG) {\r
+                                                       System.out.println("Update Item ancetor collapse " + p.listIndex);\r
+                                                       printDebug(NatTableGraphExplorer.this);\r
+                                               }\r
+                                       }\r
+                               }\r
                        } else {\r
-                               if (columnIndex >= 0) {\r
-                                       natTable.redraw();\r
-                                       //viewer.update(element, new String[]{columns[columnIndex].getKey()});\r
-                               } else {\r
-                                       natTable.redraw();\r
-                                       //viewer.refresh(element,true);\r
-                               }\r
+//                             if (columnIndex >= 0) {\r
+//                                     viewer.update(element, new String[]{columns[columnIndex].getKey()});\r
+//                             } else {\r
+//                                     viewer.refresh(element,true);\r
+//                             }\r
+                               natTable.redraw();\r
                        }\r
                        \r
-                       if (!element.isDisposed() && autoExpandLevel > 1 && !element.isExpanded() && element.getDepth() <= autoExpandLevel) {\r
+                       if (!element.autoExpanded && !element.isDisposed() && autoExpandLevel > 1 && !element.isExpanded() && element.getDepth() <= autoExpandLevel) {\r
                                expand = true;\r
+                               element.autoExpanded = true;\r
+                               element.initData();\r
+                               if (DEBUG) System.out.println("Update Item expand " + element.listIndex);\r
                                treeLayer.expandTreeRow(element.getListIndex());\r
                                //viewer.setExpandedState(element, true);\r
                                expand = false;\r
@@ -1267,8 +1329,6 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                        } else {\r
                                if (rootNode.updateChildren()) {\r
                                        listReIndex();\r
-                               natTable.refresh(true);\r
-                                       //viewer.refresh(rootNode,true);\r
                                }\r
                        }\r
        }\r
@@ -1296,11 +1356,13 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
     }\r
     \r
     private void update(final TreeNode element, final int columnIndex) {\r
-       if (DEBUG)System.out.println("update " + element + " " + columnIndex);\r
        if (natTable.isDisposed())\r
                return;\r
+       if (element != null && element.isDisposed())\r
+               return;\r
+       if (DEBUG) System.out.println("update " + element + " " + columnIndex);\r
        synchronized (pendingItems) {\r
-                       pendingItems.add(new UpdateItem(element, columnIndex));\r
+               pendingItems.add(new UpdateItem(element, columnIndex));\r
                        if (updating) return;\r
                        updateCounter++;\r
                        scheduleUpdater();\r
@@ -1308,14 +1370,14 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
     }\r
 \r
     private void update(final TreeNode element) {\r
-       if (DEBUG)System.out.println("update " + element);\r
+       \r
        if (natTable.isDisposed())\r
                return;\r
        if (element != null && element.isDisposed())\r
                return;\r
+       if (DEBUG) System.out.println("update " + element);\r
        synchronized (pendingItems) {\r
-               \r
-                       pendingItems.add(new UpdateItem(element));\r
+               pendingItems.add(new UpdateItem(element));\r
                        if (updating) return;\r
                        updateCounter++;\r
                        scheduleUpdater();\r
@@ -1449,7 +1511,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                return (double)dpi.x/96.0;\r
        }\r
     \r
-    private void createNatTable() {\r
+    private void createNatTable(int style) {\r
        GETreeData treeData = new GETreeData(list);\r
                GETreeRowModel<TreeNode> treeRowModel = new GETreeRowModel<TreeNode>(treeData);\r
                columnAccessor = new GEColumnAccessor(this);\r
@@ -1529,7 +1591,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                natTable.addConfiguration(new SingleClickSortConfiguration());\r
                //natTable.addLayerListener(this);\r
                \r
-               natTable.addConfiguration(new GENatTableThemeConfiguration(treeData));\r
+               natTable.addConfiguration(new GENatTableThemeConfiguration(treeData, style));\r
                natTable.addConfiguration(new NatTableHeaderMenuConfiguration(natTable));\r
                \r
                natTable.addConfiguration(new AbstractRegistryConfiguration() {\r
@@ -1559,13 +1621,25 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
 \r
                                });\r
                                  configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new AdaptableCellEditor());\r
+                                 configRegistry.registerConfigAttribute(EditConfigAttributes.CONVERSION_ERROR_HANDLER, new DialogErrorHandling(), DisplayMode.EDIT);\r
+                                 configRegistry.registerConfigAttribute(EditConfigAttributes.VALIDATION_ERROR_HANDLER, new DialogErrorHandling(), DisplayMode.EDIT);\r
+                                 configRegistry.registerConfigAttribute(EditConfigAttributes.DATA_VALIDATOR, new AdaptableDataValidator(),DisplayMode.EDIT);\r
+                                 \r
+                                 Style conversionErrorStyle = new Style();\r
+                                 conversionErrorStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_RED);\r
+                                 conversionErrorStyle.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR, GUIHelper.COLOR_WHITE);\r
+                                 configRegistry.registerConfigAttribute(EditConfigAttributes.CONVERSION_ERROR_STYLE, conversionErrorStyle, DisplayMode.EDIT);\r
+                                 \r
                                  configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER, new DefaultDisplayConverter(),DisplayMode.EDIT);\r
-                                // configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new GECellPainter(),DisplayMode.NORMAL);\r
-\r
-                               \r
+                                 \r
+                                 \r
                        }\r
                });\r
                \r
+               if ((style & SWT.BORDER) > 0) {\r
+                       natTable.addOverlayPainter(new NatTableBorderOverlayPainter());\r
+               }\r
+               \r
                natTable.configure();\r
                \r
 //             natTable.addListener(SWT.MenuDetect, new NatTableMenuListener());\r
@@ -1764,8 +1838,29 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                public Rectangle calculateControlBounds(Rectangle cellBounds) {\r
                        return editor.calculateControlBounds(cellBounds);\r
                }\r
+    }\r
+    \r
+    private class AdaptableDataValidator implements IDataValidator {\r
+       @Override\r
+       public boolean validate(ILayerCell cell, IConfigRegistry configRegistry, Object newValue) {\r
+               int col = cell.getColumnIndex();\r
+                       int row = cell.getRowIndex();\r
+                       return validate(col, row, newValue);\r
+       }\r
        \r
-       \r
+       @Override\r
+       public boolean validate(int col, int row, Object newValue) {\r
+               TreeNode node = list.get(row);\r
+                       Modifier modifier = getModifier(node, col);\r
+                       if (modifier == null)\r
+                               return false;\r
+                       \r
+                       String err =  modifier.isValid(newValue.toString());\r
+                       if (err == null)\r
+                               return true;\r
+                       modifier.isValid(newValue.toString());\r
+                       throw new ValidationFailedException(err);\r
+       }\r
     }\r
     \r
     private class CustomCellEditor extends AbstractCellEditor {\r
@@ -2079,7 +2174,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                }\r
                if (DEBUG) System.out.println("UpdateRunner.doRun() " + items.size());\r
 \r
-               ge.natTable.setRedraw(false);\r
+               //ge.natTable.setRedraw(false);\r
             for (UpdateItem item : items) {\r
                 item.update(ge.natTable);\r
             }\r
@@ -2091,7 +2186,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                ge.natTable.getParent().layout();\r
             }\r
             \r
-            ge.natTable.setRedraw(true);\r
+            //ge.natTable.setRedraw(true);\r
             \r
                synchronized (ge.pendingItems) {\r
                    if (!ge.scheduleUpdater()) {\r
@@ -2100,13 +2195,36 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                }\r
                if (DEBUG) {\r
                        if (!ge.updating) {\r
-                                ge.printTree(ge.rootNode, 0);\r
+                                printDebug(ge); \r
                        }\r
                }\r
            }\r
 \r
        }\r
     \r
+       private static void printDebug(NatTableGraphExplorer ge) {\r
+                ge.printTree(ge.rootNode, 0);\r
+                System.out.println("Expanded");\r
+                for (TreeNode n : ge.treeLayer.expanded)\r
+                        System.out.println(n);\r
+                System.out.println("Expanded end");\r
+                System.out.println("Hidden ");\r
+                for (int i : ge.treeLayer.getHiddenRowIndexes()) {\r
+                        System.out.print(i + " ");\r
+                }\r
+                System.out.println();\r
+//              Display.getCurrent().timerExec(1000, new Runnable() {\r
+//                     \r
+//                     @Override\r
+//                     public void run() {\r
+//                              System.out.println("Hidden delayed ");\r
+//                              for (int i : ge.treeLayer.getHiddenRowIndexes()) {\r
+//                                      System.out.print(i + " ");\r
+//                              }\r
+//                              System.out.println();\r
+//                     }\r
+//             });\r
+       }\r
     \r
     \r
     public static class GeViewerContext extends AbstractDisposable implements IGraphExplorerContext {\r
@@ -2348,23 +2466,22 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                        \r
                        @Override\r
                        public void handleLayerEvent(ILayerEvent event) {\r
-                               // TODO Auto-generated method stub\r
                                if (event instanceof ShowRowPositionsEvent) {\r
                                        ShowRowPositionsEvent e = (ShowRowPositionsEvent)event;\r
                                        for (Range r : e.getRowPositionRanges()) {\r
                                                int expanded = viewportLayer.getRowIndexByPosition(r.start-2)+1;\r
-                                               //System.out.println("ex " + expanded);\r
-                                               if (expanded < 0) {\r
+                                               if (DEBUG)System.out.println("IsExpandedProcessor expand " + expanded);\r
+                                               if (expanded < 0 || expanded >= list.size()) {\r
                                                        return;\r
                                                }\r
-                                               nodeStatusChanged(list.get(expanded).getContext(), false);\r
+                                               nodeStatusChanged(list.get(expanded).getContext(), true);\r
                                        }\r
                                } else if (event instanceof HideRowPositionsEvent) {\r
                                        HideRowPositionsEvent e = (HideRowPositionsEvent)event;\r
                                        for (Range r : e.getRowPositionRanges()) {\r
-                                               int collapsed = viewportLayer.getRowIndexByPosition(r.start-2)+1;\r
-                                               //System.out.println("col " + collapsed);\r
-                                               if (collapsed < 0) {\r
+                                               int collapsed = viewportLayer.getRowIndexByPosition(r.start-2);\r
+                                               if (DEBUG)System.out.println("IsExpandedProcessor collapse " + collapsed);\r
+                                               if (collapsed < 0 || collapsed >= list.size()) {\r
                                                        return;\r
                                                }\r
                                                nodeStatusChanged(list.get(collapsed).getContext(), false);\r
@@ -2714,7 +2831,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
                }\r
     }\r
     \r
-private class NatTableHeaderMenuConfiguration extends AbstractHeaderMenuConfiguration {\r
+    private class NatTableHeaderMenuConfiguration extends AbstractHeaderMenuConfiguration {\r
                \r
                \r
                public NatTableHeaderMenuConfiguration(NatTable natTable) {\r
@@ -2755,8 +2872,8 @@ private class NatTableHeaderMenuConfiguration extends AbstractHeaderMenuConfigur
         Point point = new Point(e.x, e.y);\r
         int y = natTable.getRowPositionByY(point.y);\r
         int x = natTable.getColumnPositionByX(point.x);\r
-        if (x < 0 | y < 0)\r
+        if (x < 0 | y <= 0)\r
                return null;\r
-        return list.get(y); \r
+        return list.get(y-1); \r
     }\r
 }\r
index 4302cdeacf74d4d69bca07c6de6bfdd7ff476772..03588ae76736ecafa64cb054f0fc12d41c629ed2 100644 (file)
@@ -1,6 +1,7 @@
 package org.simantics.browsing.ui.nattable;\r
 \r
 import java.util.ArrayList;\r
+import java.util.Collection;\r
 import java.util.List;\r
 \r
 import org.eclipse.jface.viewers.IPostSelectionProvider;\r
@@ -21,6 +22,7 @@ import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Point;\r
 import org.eclipse.swt.widgets.Event;\r
 import org.simantics.utils.datastructures.MapList;\r
+import org.simantics.utils.ui.AdaptionUtils;\r
 \r
 public class NatTableSelectionAdaptor implements ISelectionProvider, IPostSelectionProvider, ILayerListener {\r
        NatTable natTable;\r
@@ -76,9 +78,41 @@ public class NatTableSelectionAdaptor implements ISelectionProvider, IPostSelect
        public void setSelection(ISelection selection) {\r
                if (!(selection instanceof StructuredSelection))\r
                        throw new IllegalArgumentException("Selection must be structured selection");\r
+               if (selection.isEmpty()) {\r
+                       selectionLayer.clear(false);\r
+                       natTable.redraw();\r
+                       return;\r
+               }\r
+               List<RowSelectionItem> rowItems = new ArrayList<>(AdaptionUtils.adaptToCollection(selection, RowSelectionItem.class));\r
+               if (rowItems.size() > 0) {\r
+               \r
+                       setSelectionExternal(rowItems);\r
+                       return;\r
+               }\r
+               Collection<TreeNode> nodes = AdaptionUtils.adaptToCollection(selection, TreeNode.class);\r
+               if (nodes.size() > 0) {\r
+                       List<RowSelectionItem> selected = new ArrayList<>();\r
+                       int allCols[] = new int[selectionLayer.getColumnCount()];\r
+                       for (int i = 0; i < allCols.length; i++)\r
+                               allCols[i] = i;\r
+                       for (TreeNode n : nodes) {\r
+                               selected.add(new RowSelectionItem(n, n.listIndex, allCols));\r
+                       }\r
+                       setSelectionExternal(selected);\r
+                       return;\r
+               }\r
                \r
        }\r
        \r
+       private void setSelectionExternal(List<RowSelectionItem> items) {\r
+               selectionLayer.clear(true);\r
+               for (RowSelectionItem item : items) {\r
+                       for (int c : item.columnIndex)\r
+                               selectionLayer.selectCell(c, item.rowIndex, false, true);\r
+               }\r
+               selection = new StructuredSelection(items);\r
+               fireEvents();\r
+       }\r
        \r
        \r
        private List<Point> selectedCells = new ArrayList<Point>();\r
index 941c6f319be56e491909cc35472e7173a5040ccf..30a37e3292205da607911c2d757528bf555d47f5 100644 (file)
@@ -38,6 +38,7 @@ public class TreeNode implements IAdaptable {
        TreeNode parent;\r
        List<TreeNode> children = new ArrayList<TreeNode>();\r
        boolean expanded;\r
+       boolean autoExpanded = false;\r
        \r
        public TreeNode(NodeContext context, GeViewerContext explorerContext) {\r
                this.context = context;\r
@@ -47,13 +48,13 @@ public class TreeNode implements IAdaptable {
                explorerContext.getContextToNodeMap().add(context, this);\r
        }\r
        \r
-       int getDepth() {\r
+       public int getDepth() {\r
                if (parent == null)\r
                        return 0;\r
                return parent.getDepth() + 1;\r
        }\r
        \r
-       int listIndex;\r
+       int listIndex = -1;\r
        \r
        public int getListIndex() {\r
                return listIndex;\r
@@ -79,6 +80,27 @@ public class TreeNode implements IAdaptable {
                return expanded;\r
        }\r
        \r
+       public boolean isHidden() {\r
+               TreeNode n = parent;\r
+               while (n != null) {\r
+                       if (!n.isExpanded())\r
+                               return true;\r
+                       n = n.getParent();\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       public TreeNode getCollapsedAncestor() {\r
+               TreeNode collapsed = null;\r
+               TreeNode n = parent;\r
+               while (n != null) {\r
+                       if (!n.isExpanded())\r
+                               collapsed = n;\r
+                       n = n.getParent();\r
+               }\r
+               return collapsed;\r
+       }\r
+       \r
        public NodeContext getContext() {\r
                return context;\r
        }\r
@@ -92,9 +114,8 @@ public class TreeNode implements IAdaptable {
        Map<String, String> runtimeLabels;\r
        \r
        public String getValueString(int column) {\r
-               if (column == 0) {\r
+               if (column == 0)\r
                        initData();\r
-               }\r
                if (labeler != null) {\r
                        String key = explorerContext.getGe().getColumns()[column].getKey();\r
                        String s = null;\r
@@ -199,7 +220,7 @@ public class TreeNode implements IAdaptable {
 \r
        }\r
        \r
-       private void initData() {\r
+       public void initData() {\r
                labeler = manager.query(context, BuiltinKeys.SELECTED_LABELER);\r
                imager = manager.query(context, BuiltinKeys.SELECTED_IMAGER);\r
                labelDecorators = manager.query(context, BuiltinKeys.LABEL_DECORATORS);\r
@@ -319,7 +340,13 @@ public class TreeNode implements IAdaptable {
                                \r
                        }\r
                        for (int i = oldCount; i < childContexts.length; i++) {\r
-                               addChild(childContexts[i], explorerContext);\r
+                               Integer oldIndex = indexes.getLeft(i);\r
+                               if (oldIndex == null) {\r
+                                       addChild(childContexts[i], explorerContext);\r
+                               } else {\r
+                                       TreeNode n = oldChildren.get(oldIndex);\r
+                                       children.add(n);\r
+                               }\r
                        }\r
                        } else {\r
                                for (int i = 0; i < childContexts.length; i++) {\r
@@ -363,5 +390,10 @@ public class TreeNode implements IAdaptable {
                \r
                return context.getAdapter(adapter);\r
        }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               return "TreeNode: " + listIndex + " " + (expanded ? "(+)" : "(-)") + " " + context ;\r
+       }\r
 \r
 }\r
index 54c1160c5169c2dd0ee334c7913d4c2406f291b1..73f2d2f16d167d34de11a541e097cadf78890378 100644 (file)
@@ -20,6 +20,7 @@ import org.simantics.databoard.binding.impl.BooleanArrayBinding;
 import org.simantics.databoard.binding.impl.BooleanBindingDefault;\r
 import org.simantics.databoard.binding.impl.ByteArrayBinding;\r
 import org.simantics.databoard.binding.impl.ByteBindingDefault;\r
+import org.simantics.databoard.binding.impl.DefaultMapBinding;\r
 import org.simantics.databoard.binding.impl.DoubleArrayBinding;\r
 import org.simantics.databoard.binding.impl.DoubleBindingDefault;\r
 import org.simantics.databoard.binding.impl.FloatArrayBinding;\r
@@ -30,7 +31,6 @@ import org.simantics.databoard.binding.impl.LongArrayBinding;
 import org.simantics.databoard.binding.impl.LongBindingDefault;\r
 import org.simantics.databoard.binding.impl.ObjectArrayBinding;\r
 import org.simantics.databoard.binding.impl.StringBindingDefault;\r
-import org.simantics.databoard.binding.impl.TreeMapBinding;\r
 import org.simantics.databoard.binding.mutable.ContainerOptionalBinding;\r
 import org.simantics.databoard.binding.mutable.UnionTaggedObjectBinding;\r
 import org.simantics.databoard.type.ArrayType;\r
@@ -180,9 +180,9 @@ public class DefaultBindingFactory extends TypeBindingFactory {
                        return binding;\r
                }               
                
-               if (type instanceof MapType) {                  
+               if (type instanceof MapType) {
                        MapType mapType = (MapType) type;
-                       TreeMapBinding binding = new TreeMapBinding(mapType, null, null);
+                       DefaultMapBinding binding = new DefaultMapBinding(mapType, null, null);
                        inprogress.put(type, binding);\r
                        binding.setKeyBinding( construct(mapType.keyType) );\r
                        binding.setValueBinding( construct(mapType.valueType) );\r
index e43b7bc736bca5986125f93f22d9b8cc72a26a61..b173cb6eb5ce092c05632cd8efe340fd44215bab 100644 (file)
@@ -28,6 +28,8 @@ import org.simantics.databoard.binding.error.BindingConstructionException;
 import org.simantics.databoard.binding.impl.ArrayListBinding;\r
 import org.simantics.databoard.binding.impl.BooleanArrayBinding;\r
 import org.simantics.databoard.binding.impl.ByteArrayBinding;\r
+import org.simantics.databoard.binding.impl.DefaultMapBinding;\r
+import org.simantics.databoard.binding.impl.DefaultSetBinding;\r
 import org.simantics.databoard.binding.impl.DoubleArrayBinding;\r
 import org.simantics.databoard.binding.impl.FloatArrayBinding;\r
 import org.simantics.databoard.binding.impl.HashMapBinding;\r
@@ -101,7 +103,7 @@ public class JavaUtilBindingsProvider implements BindingProvider {
         if (Set.class.isAssignableFrom(request.getClazz())) {\r
             MapType type = new MapType();\r
             type.valueType = Datatypes.VOID;\r
-               return new TreeSetBinding(type, null);\r
+               return new DefaultSetBinding(type, null);\r
         }\r
                \r
         if (TreeMap.class.isAssignableFrom(request.getClazz())) {\r
@@ -113,7 +115,7 @@ public class JavaUtilBindingsProvider implements BindingProvider {
         }\r
 \r
         if (Map.class.isAssignableFrom(request.getClazz())) {\r
-               return new HashMapBinding(new MapType(), null, null);\r
+               return new DefaultMapBinding(new MapType(), null, null);\r
         }\r
                        \r
                return null;\r
index e635e12a03d27a70a5e37a19d8a63e1c692c6f52..0f9a4dc767b46a5e0ae02a22f75ea383da09f059 100644 (file)
@@ -103,6 +103,9 @@ public class TroveBindingsProvider implements BindingProvider {
                \r
                @Override\r
                public Object create(Map<?, ?> initialMap) throws BindingException {\r
+                   if (initialMap instanceof THashMap)\r
+                       return initialMap;\r
+                   \r
                        // Replace with TreeMap. Create comparator from binding.\r
                        THashMap<Object, Object> result = new THashMap<Object, Object>();\r
                        putAll(result, initialMap);\r
@@ -134,10 +137,14 @@ public class TroveBindingsProvider implements BindingProvider {
                }\r
 \r
                public Object create(Set<?> initialSet) throws BindingException {\r
+                   if (initialSet instanceof THashSet)\r
+                       return initialSet;\r
+                   \r
                        return new THashSet<Object>(initialSet);\r
                }\r
 \r
-               @Override\r
+               @SuppressWarnings({ "unchecked", "rawtypes" })\r
+        @Override\r
                public Object create(Map initialMap) throws BindingException {\r
                        return new THashSet<Object>(initialMap.keySet());\r
                }\r
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/DefaultMapBinding.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/DefaultMapBinding.java
new file mode 100644 (file)
index 0000000..43c1e97
--- /dev/null
@@ -0,0 +1,326 @@
+/*******************************************************************************\r
+ *  Copyright (c) 2010 Association for Decentralized Information Management in\r
+ *  Industry THTH ry.\r
+ *  All rights reserved. This program and the accompanying materials\r
+ *  are made available under the terms of the Eclipse Public License v1.0\r
+ *  which accompanies this distribution, and is available at\r
+ *  http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ *  Contributors:\r
+ *      VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.binding.impl;\r
+\r
+import java.util.IdentityHashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.Set;\r
+import java.util.TreeMap;\r
+\r
+import org.simantics.databoard.binding.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.MapBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.type.MapType;\r
+\r
+/**\r
+ * Binds java.util.Map to MapType\r
+ * \r
+ * This Binding type accepts all java.util.Map instances, but creates\r
+ * java.util.TreeMap instances by default.\r
+ * \r
+ * @author Reino Ruusu <reino.ruusu@vtt.fi>\r
+ */\r
+@SuppressWarnings("rawtypes")\r
+public class DefaultMapBinding extends MapBinding {\r
+\r
+    public DefaultMapBinding(Binding keyBinding, Binding valueBinding) {\r
+        super(keyBinding, valueBinding);\r
+    }\r
+\r
+    public DefaultMapBinding(MapType mapType, Binding keyBinding,\r
+            Binding valueBinding) {\r
+        super(mapType, keyBinding, valueBinding);\r
+    }\r
+\r
+    public void postConstruction() {\r
+    }\r
+\r
+    @Override\r
+    public Object create() {\r
+        return new TreeMap<Object,Object>( keyBinding );\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public Object create(Object[] keys, Object[] values) {\r
+        if (keys.length != values.length)\r
+            throw new IllegalArgumentException("Equal length arrays expected");\r
+\r
+        int len = keys.length;\r
+        Map result = new TreeMap<Object,Object>( keyBinding );\r
+\r
+        for (int i = 0; i < len; i++) {\r
+            Object key = keys[i];\r
+            Object value = values[i];\r
+            result.put(key, value);\r
+        }\r
+\r
+        return result;\r
+    }\r
+    \r
+    \r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public Object create(List<Object> keys, List<Object> values) {\r
+        if (keys.size()!=values.size())\r
+            throw new IllegalArgumentException("Equal length arrays expected");\r
+        \r
+        int len = keys.size();\r
+        Map result = new TreeMap<Object,Object>( keyBinding );\r
+        \r
+        for (int i=0; i<len; i++) {\r
+            Object key = keys.get(i);\r
+            Object value = values.get(i);\r
+            result.put(key, value);\r
+        }\r
+        \r
+        return result;\r
+    }   \r
+\r
+    @Override\r
+    public Object create(Map<?,?> map) {\r
+        return map;\r
+    }\r
+    \r
+    @Override\r
+    public void clear(Object map) {\r
+        ((Map) map).clear();\r
+    }\r
+\r
+    @Override\r
+    public boolean containsKey(Object map, Object key) {\r
+        Map m = ((Map) map);\r
+        return m.containsKey(key);\r
+    }\r
+\r
+    @Override\r
+    public boolean containsValue(Object map, Object value) {\r
+        Map m = ((Map) map);\r
+        Binding vb = getValueBinding();\r
+        for (Object v : m.values())\r
+        {\r
+            if (vb.equals(v, value)) return true;\r
+        }\r
+        return false;\r
+    }\r
+\r
+    @Override\r
+    public Object get(Object map, Object key) {\r
+        Map m = ((Map) map);\r
+        return m.get(key);\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public Object[] getKeys(Object map) {\r
+        Map m = ((Map) map);\r
+        return m.keySet().toArray(new Object[m.size()]);\r
+    }\r
+    \r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public void getKeys(Object map, Set<Object> keys) throws BindingException {\r
+        Map m = ((Map)map);\r
+        keys.addAll(m.keySet());\r
+    }   \r
+    \r
+    /**\r
+     * Count the number of entries between two keyes\r
+     * @param from\r
+     * @param fromInclusive\r
+     * @param end \r
+     * @param endInclusive\r
+     * @throws BindingException\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public int count(Object src, Object from, boolean fromInclusive, Object end, boolean endInclusive) throws BindingException {\r
+        // Assert end > from\r
+        if (keyBinding.compare(from, end)>0) return 0;\r
+        \r
+        if (src instanceof TreeMap) {\r
+            TreeMap m = (TreeMap) src;\r
+            Map sm = m.subMap(from, fromInclusive, end, endInclusive);\r
+            return sm.size();\r
+        }\r
+        else {\r
+            int result = 0;\r
+            Map<Object, Object> m = ((Map<Object, Object>)src);\r
+            for (Object k : m.keySet()) {\r
+                int fk = keyBinding.compare(from, k);\r
+                int ek = keyBinding.compare(k, end);\r
+                boolean fromMatches = fromInclusive ? fk<=0 : fk<0;\r
+                boolean endMatches = endInclusive ? ek<=0 : ek <0;          \r
+                if ( fromMatches && endMatches ) result++;\r
+            }       \r
+            return result;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Read a range of entries\r
+     * \r
+     * @param src\r
+     * @param from\r
+     * @param fromInclusive\r
+     * @param end \r
+     * @param endInclusive\r
+     * @param dstKeyArrayBinding\r
+     * @param dstKeyArray\r
+     * @param dstValueArrayBinding\r
+     * @param dstValueArray\r
+     * @throws BindingException\r
+     */\r
+    public int getEntries(Object src, Object from, boolean fromInclusive, Object end, boolean endInclusive, ArrayBinding dstKeyArrayBinding, Object dstKeyArray, ArrayBinding dstValueArrayBinding, Object dstValueArray, int limit) throws BindingException {\r
+        if (src instanceof TreeMap) {\r
+            return new TreeMapBinding(keyBinding, valueBinding).getEntries(src, from, fromInclusive, end, endInclusive, dstKeyArrayBinding, dstKeyArray, dstValueArrayBinding, dstValueArray, limit);\r
+        }\r
+        else {\r
+            return new HashMapBinding(keyBinding, valueBinding).getEntries(src, from, fromInclusive, end, endInclusive, dstKeyArrayBinding, dstKeyArray, dstValueArrayBinding, dstValueArray, limit);\r
+        }\r
+    }\r
+    \r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public Object[] getValues(Object map) {\r
+        Map m = ((Map) map);\r
+        return m.values().toArray(new Object[m.size()]);\r
+    }\r
+\r
+    @Override\r
+    public <K, V> void put(Object map, K key, V value) {\r
+        @SuppressWarnings("unchecked")\r
+        Map<K, V> m = ((Map<K, V>) map);\r
+        m.put(key, value);\r
+    }\r
+\r
+    @Override\r
+    public <K, V> void putAll(Object dstMap, Map<K, V> srcMap) {\r
+        @SuppressWarnings("unchecked")\r
+        Map<K, V> dst = ((Map<K, V>) dstMap);\r
+        dst.putAll(srcMap);\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public void getAll(Object mapFrom, Map to) {\r
+        Map<?, ?> m = ((Map<?, ?>) mapFrom);\r
+        to.putAll(m);\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public void getAll(Object mapFrom, Object[] keys, Object[] values) {\r
+        Map m = (Map) mapFrom;\r
+        int i = 0;\r
+        for (Entry<Object, Object> e : (Set<Entry<Object, Object>>) m.entrySet()) {\r
+            keys[i] = e.getKey();\r
+            values[i] = e.getValue();\r
+            i++;\r
+        }\r
+    }\r
+    \r
+    @Override\r
+    public Object remove(Object map, Object key) {\r
+        Map m = ((Map) map);\r
+        return m.remove(key);\r
+    }\r
+\r
+    @Override\r
+    public int size(Object map) {\r
+        Map m = ((Map) map);\r
+        return m.size();\r
+    }\r
+\r
+    @Override\r
+    public boolean isInstance(Object obj) {\r
+        return obj instanceof Map;\r
+    }\r
+\r
+    @Override\r
+    public int deepHashValue(Object map, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {\r
+        int result = 0;\r
+        Map m = ((Map) map);\r
+        @SuppressWarnings("unchecked")\r
+        Set<Entry> s = m.entrySet();\r
+        for (Entry e : s) {\r
+            int keyTree = getKeyBinding().deepHashValue(e.getKey(), hashedObjects);\r
+            int valueTree = getValueBinding().deepHashValue(e.getValue(), hashedObjects);\r
+            result += (keyTree ^ valueTree);\r
+        }\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public Object getCeilingKey(Object map, Object key) {\r
+        if (map instanceof TreeMap) {\r
+            return new TreeMapBinding(keyBinding, valueBinding).getCeilingKey(map, key);\r
+        }\r
+        else {\r
+            return new HashMapBinding(keyBinding, valueBinding).getCeilingKey(map, key);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Object getFirstKey(Object map) {\r
+        if (map instanceof TreeMap) {\r
+            return new TreeMapBinding(keyBinding, valueBinding).getFirstKey(map);\r
+        }\r
+        else {\r
+            return new HashMapBinding(keyBinding, valueBinding).getFirstKey(map);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Object getFloorKey(Object map, Object key) {\r
+        if (map instanceof TreeMap) {\r
+            return new TreeMapBinding(keyBinding, valueBinding).getFloorKey(map, key);\r
+        }\r
+        else {\r
+            return new HashMapBinding(keyBinding, valueBinding).getFloorKey(map, key);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Object getHigherKey(Object map, Object key) {\r
+        if (map instanceof TreeMap) {\r
+            return new TreeMapBinding(keyBinding, valueBinding).getHigherKey(map, key);\r
+        }\r
+        else {\r
+            return new HashMapBinding(keyBinding, valueBinding).getHigherKey(map, key);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Object getLastKey(Object map) {\r
+        if (map instanceof TreeMap) {\r
+            return new TreeMapBinding(keyBinding, valueBinding).getLastKey(map);\r
+        }\r
+        else {\r
+            return new HashMapBinding(keyBinding, valueBinding).getLastKey(map);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Object getLowerKey(Object map, Object key) {\r
+        if (map instanceof TreeMap) {\r
+            return new TreeMapBinding(keyBinding, valueBinding).getLowerKey(map, key);\r
+        }\r
+        else {\r
+            return new HashMapBinding(keyBinding, valueBinding).getLowerKey(map, key);\r
+        }\r
+    }\r
+}\r
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/DefaultSetBinding.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/DefaultSetBinding.java
new file mode 100644 (file)
index 0000000..783f80b
--- /dev/null
@@ -0,0 +1,239 @@
+/*******************************************************************************\r
+ *  Copyright (c) 2010 Association for Decentralized Information Management in\r
+ *  Industry THTH ry.\r
+ *  All rights reserved. This program and the accompanying materials\r
+ *  are made available under the terms of the Eclipse Public License v1.0\r
+ *  which accompanies this distribution, and is available at\r
+ *  http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ *  Contributors:\r
+ *      VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.binding.impl;\r
+\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+import org.simantics.databoard.binding.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.MapBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.reflection.VoidBinding;\r
+import org.simantics.databoard.type.MapType;\r
+import org.simantics.databoard.type.RecordType;\r
+\r
+/**\r
+ * Binds java.util.Set to Map(T, {})\r
+ * \r
+ * This binding accepts all java.util.Set instances, but instantiates\r
+ * java.util.TreeSet objects.\r
+ *\r
+ * @author Reino Ruusu <reino.ruusu@vtt.fi>\r
+ */\r
+@SuppressWarnings("unchecked")\r
+public class DefaultSetBinding extends MapBinding {\r
+       \r
+       public DefaultSetBinding(MapType mapType, Binding elementBinding) {\r
+               super(mapType, elementBinding, VoidBinding.VOID_BINDING);\r
+       }\r
+       \r
+       public DefaultSetBinding(Binding elementBinding) {\r
+               super(new MapType(elementBinding.type(), RecordType.VOID_TYPE), elementBinding, VoidBinding.VOID_BINDING);\r
+       }\r
+\r
+       @Override\r
+       public void clear(Object set) throws BindingException {\r
+               Set<Object> _set = (Set<Object>) set;\r
+               _set.clear();\r
+       }\r
+\r
+       @Override\r
+       public boolean containsKey(Object set, Object key) throws BindingException {\r
+               Set<Object> _set = (Set<Object>) set;\r
+               return _set.contains(key);\r
+       }\r
+\r
+       @Override\r
+       public boolean containsValue(Object set, Object value)\r
+                       throws BindingException {\r
+               return false;\r
+       }\r
+\r
+    @Override\r
+    public Object create() throws BindingException {\r
+        return new TreeSet<Object>( keyBinding );\r
+    }\r
+\r
+       public Object create(Set<?> initialSet) throws BindingException {\r
+           return initialSet;\r
+       }\r
+\r
+       @Override\r
+       public Object create(Map<?, ?> initialMap) throws BindingException {\r
+               Set<Object> result = new TreeSet<Object>( keyBinding );\r
+               result.addAll(initialMap.keySet());\r
+               return result;\r
+       }\r
+\r
+       @Override\r
+       public Object create(Object[] keys, Object[] values)\r
+       throws BindingException {               \r
+               Set<Object> result = new TreeSet<Object>( keyBinding );\r
+               for (int i=0; i<keys.length; i++) {\r
+                       result.add( keys[i] );\r
+               }\r
+               return result;\r
+       }\r
+       \r
+       @Override\r
+       public Object create(List<Object> keys, List<Object> values) {\r
+               Set<Object> result = new TreeSet<Object>( keyBinding );\r
+               for (int i=0; i<keys.size(); i++)\r
+                       result.add(keys.get(i));\r
+               return result;\r
+       }       \r
+\r
+       @Override\r
+       public Object get(Object set, Object key) throws BindingException {\r
+               return null;\r
+       }\r
+       \r
+    @Override\r
+    public <K, V> void getAll(Object setFrom, Map<K, V> to) throws BindingException {\r
+               Map<K, V> _to = (Map<K, V>) to;\r
+               Set<K> _setFrom = (Set<K>) setFrom;\r
+               for (K k : _setFrom)\r
+                       _to.put(k, null);\r
+       }\r
+\r
+       @Override\r
+       public void getAll(Object setFrom, Object[] keys, Object[] values)\r
+                       throws BindingException {\r
+               Set<Object> _setFrom = (Set<Object>) setFrom;\r
+               int i=0;\r
+               for (Object k : _setFrom) {\r
+                       keys[i] = k;\r
+                       values[i] = null;\r
+               }               \r
+       }\r
+\r
+       @Override\r
+       public Object[] getKeys(Object set) throws BindingException {\r
+               Set<Object> _set = (Set<Object>) set;\r
+               return _set.toArray(new Object[_set.size()]);\r
+       }\r
+\r
+       @Override\r
+       public void getKeys(Object set, Set<Object> keys) throws BindingException {\r
+               Set<Object> s = (Set<Object>) set;\r
+               keys.addAll(s);\r
+       }\r
+       \r
+       @Override\r
+       public Object[] getValues(Object set) throws BindingException {\r
+               Set<Object> _set = (Set<Object>) set;\r
+               return new Object[_set.size()];\r
+       }\r
+       \r
+       @Override\r
+       public int count(Object src, Object from, boolean fromInclusive, Object end, boolean endInclusive) throws BindingException {\r
+           if (src instanceof TreeSet)\r
+            return new TreeSetBinding(keyBinding).count(src, from, fromInclusive, end, endInclusive);\r
+           else\r
+               return new HashSetBinding(keyBinding).count(src, from, fromInclusive, end, endInclusive);\r
+       }\r
+       \r
+       @Override\r
+       public int getEntries(Object src, Object from, boolean fromInclusive, Object end, boolean endInclusive, ArrayBinding dstKeyArrayBinding, Object dstKeyArray, ArrayBinding dstValueArrayBinding, Object dstValueArray, int limit) throws BindingException {\r
+               return 0;\r
+       }\r
+\r
+       @Override\r
+       public void put(Object set, Object key, Object value)\r
+                       throws BindingException {\r
+               Set<Object> _set = (Set<Object>) set;\r
+               if (value!=null) throw new BindingException("Cannot put non-null to a Set");\r
+               _set.add(key);\r
+       }\r
+\r
+       public void putAll(Object setTo, Set<?> from) {\r
+               Set<Object> _set = (Set<Object>) setTo;\r
+               _set.addAll(from);\r
+       }\r
+       \r
+       @Override\r
+       public <K,V> void putAll(Object setTo, Map<K,V> from) throws BindingException {\r
+               Set<Object> _set = (Set<Object>) setTo;\r
+               _set.addAll(from.keySet());\r
+       }\r
+\r
+       @Override\r
+       public Object remove(Object set, Object key) throws BindingException {\r
+               Set<Object> _set = (Set<Object>) set;\r
+               _set.remove(key);\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public int size(Object set) throws BindingException {\r
+               Set<Object> _set = (Set<Object>) set;\r
+               return _set.size();\r
+       }\r
+\r
+       @Override\r
+       public boolean isInstance(Object obj) {\r
+               return obj instanceof Set;\r
+       }\r
+\r
+       @Override\r
+       public Object getCeilingKey(Object set, Object key) {\r
+        if (set instanceof TreeSet)\r
+            return new TreeSetBinding(keyBinding).getCeilingKey(set, key);\r
+        else\r
+            return new HashSetBinding(keyBinding).getCeilingKey(set, key);\r
+       }\r
+\r
+       @Override\r
+       public Object getFirstKey(Object set) {\r
+        if (set instanceof TreeSet)\r
+            return new TreeSetBinding(keyBinding).getFirstKey(set);\r
+        else\r
+            return new HashSetBinding(keyBinding).getFirstKey(set);\r
+       }\r
+\r
+       @Override\r
+       public Object getFloorKey(Object set, Object key) {\r
+        if (set instanceof TreeSet)\r
+            return new TreeSetBinding(keyBinding).getFloorKey(set, key);\r
+        else\r
+            return new HashSetBinding(keyBinding).getFloorKey(set, key);\r
+       }\r
+\r
+       @Override\r
+       public Object getHigherKey(Object set, Object key) {\r
+        if (set instanceof TreeSet)\r
+            return new TreeSetBinding(keyBinding).getHigherKey(set, key);\r
+        else\r
+            return new HashSetBinding(keyBinding).getHigherKey(set, key);\r
+       }\r
+\r
+       @Override\r
+       public Object getLastKey(Object set) {\r
+        if (set instanceof TreeSet)\r
+            return new TreeSetBinding(keyBinding).getLastKey(set);\r
+        else\r
+            return new HashSetBinding(keyBinding).getLastKey(set);\r
+       }\r
+\r
+       @Override\r
+       public Object getLowerKey(Object set, Object key) {\r
+        if (set instanceof TreeSet)\r
+            return new TreeSetBinding(keyBinding).getLowerKey(set, key);\r
+        else\r
+            return new HashSetBinding(keyBinding).getLowerKey(set, key);\r
+       }\r
+\r
+}\r
+\r
index d3a9d8c75c46cbb6b060c373c812aeebd0543282..76241a0c7f3eaebd2e7f51d699c5e983d43cbb3b 100644 (file)
@@ -53,13 +53,11 @@ public class HashMapBinding extends MapBinding {
                super(mapType, keyBinding, valueBinding);
        }
        
-       public void postConstruction() {}\r
-       \r
-       @Override
-       public Object create() {                
-               return new HashMap<Object, Object>();
-       }
-       
+    @Override\r
+    public Object create() {        \r
+        return new HashMap<Object, Object>();\r
+    }\r
+    \r
        @Override
        public Object create(Object[] keys, Object[] values) {
                if (keys.length!=values.length)
@@ -97,7 +95,10 @@ public class HashMapBinding extends MapBinding {
        }
        
        @Override
-       public Object create(Map<?, ?> initialMap) throws BindingException {
+       public Object create(Map<?, ?> initialMap) throws BindingException {\r
+           if (initialMap instanceof HashMap)\r
+               return initialMap;\r
+           
                // Replace with TreeMap. Create comparator from binding.
                HashMap<Object, Object> result = new HashMap<Object, Object>();
                putAll(result, initialMap);
index efeb38493eb08bf7d8fa205bb55438b7ec5a27d3..494b3d9e8e6f60de0a1dbcc0d0979e7daae99991 100644 (file)
@@ -32,7 +32,7 @@ import org.simantics.databoard.type.RecordType;
  *
  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
  */\r
-@SuppressWarnings("all")
+@SuppressWarnings({"rawtypes", "unchecked"})\r
 public class HashSetBinding extends MapBinding {
        
        public HashSetBinding(MapType mapType, Binding elementBinding) {
@@ -43,7 +43,6 @@ public class HashSetBinding extends MapBinding {
                super(new MapType(elementBinding.type(), RecordType.VOID_TYPE), elementBinding, VoidBinding.VOID_BINDING);
        }
 
-       @SuppressWarnings("unchecked")
        @Override
        public void clear(Object set) throws BindingException {
                Set _set = (Set) set;
@@ -139,7 +138,6 @@ public class HashSetBinding extends MapBinding {
                keys.addAll(s);
        }
        \r
-       @SuppressWarnings("unchecked")\r
        @Override\r
        public int count(Object src, Object from, boolean fromInclusive,\r
                        Object end, boolean endInclusive) throws BindingException {\r
@@ -183,7 +181,6 @@ public class HashSetBinding extends MapBinding {
                s.add(key);
        }
        
-       @SuppressWarnings("unchecked")
        Object getComparableKey(Object set, Object key) {
                // if (keyIsComparable) return key;
                
@@ -201,11 +198,9 @@ public class HashSetBinding extends MapBinding {
                _set.addAll(from);
        }
        
-       @SuppressWarnings("unchecked")
        @Override
        public void putAll(Object setTo, Map from) throws BindingException {
                Set<Object> s = (Set<Object>) setTo;
-               Binding kb = getKeyBinding();
                for (Entry<Object, Object> e : (Set<Entry<Object, Object>>) from.entrySet()) {
                        Object k = getComparableKey(s, e.getKey());
                        s.remove(k);                    
index 304b3cad4a4dc80e0150ca86618f6f27957abf51..50028b3a164914a10d1d859f4d1e1a7f724f9190 100644 (file)
@@ -58,12 +58,15 @@ public class TreeSetBinding extends MapBinding {
                return false;
        }
 
-       @Override
-       public Object create() throws BindingException {
-               return new TreeSet<Object>( getKeyBinding() );
-       }
-
-       public Object create(Set<?> initialSet) throws BindingException {
+    @Override\r
+    public Object create() throws BindingException {\r
+        return new TreeSet<Object>( getKeyBinding() );\r
+    }\r
+\r
+       public Object create(Set<?> initialSet) throws BindingException {\r
+           if (initialSet instanceof TreeSet && ((TreeSet<?>) initialSet).comparator() == getKeyBinding())\r
+               return initialSet;\r
+           
                TreeSet<Object> result = new TreeSet<Object>(getKeyBinding());
                result.addAll(initialSet);
                return result;
index eda90ce84ae96db74f5a8ad3256925185924be75..72053ec5b6317e93ecee85e2c5d2afa528b8f79c 100644 (file)
Binary files a/bundles/org.simantics.diagram.ontology/graph.tg and b/bundles/org.simantics.diagram.ontology/graph.tg differ
index 652ea695bb05a9f9577e284530ad538d7edb90ba..072bf49d8f41aed3a47571a2455720202a41df24 100644 (file)
@@ -79,4 +79,8 @@ DIA.Profile.defaultEnabled
   \r
 DIA.ConfigurableProfile <T L0.Entity\r
 \r
+DIA.HasTemplate <R L0.ConsistsOf\r
+   L0.HasDomain DIA.ProfileEntry\r
+   L0.HasRange DIA.ProfileEntry\r
+\r
 \r
index b2cd20448485763a07737d72276af300fef31a9d..f3ec1598b2cbdbc11ace84075aad7825d3d2cc53 100644 (file)
@@ -176,6 +176,8 @@ public class DiagramResource {
     public final Resource HasSymbolContributionFilter;\r
     public final Resource HasSymbol_Inverse;\r
     public final Resource HasTailConnector;\r
+    public final Resource HasTemplate;\r
+    public final Resource HasTemplate_Inverse;\r
     public final Resource HasText;\r
     public final Resource HasText_Inverse;\r
     public final Resource HasTransform;\r
@@ -582,6 +584,8 @@ public class DiagramResource {
         public static final String HasSymbolContributionFilter = "http://www.simantics.org/Diagram-2.2/HasSymbolContributionFilter";\r
         public static final String HasSymbol_Inverse = "http://www.simantics.org/Diagram-2.2/HasSymbol/Inverse";\r
         public static final String HasTailConnector = "http://www.simantics.org/Diagram-2.2/HasTailConnector";\r
+        public static final String HasTemplate = "http://www.simantics.org/Diagram-2.2/HasTemplate";\r
+        public static final String HasTemplate_Inverse = "http://www.simantics.org/Diagram-2.2/HasTemplate/Inverse";\r
         public static final String HasText = "http://www.simantics.org/Diagram-2.2/HasText";\r
         public static final String HasText_Inverse = "http://www.simantics.org/Diagram-2.2/HasText/Inverse";\r
         public static final String HasTransform = "http://www.simantics.org/Diagram-2.2/HasTransform";\r
@@ -998,6 +1002,8 @@ public class DiagramResource {
         HasSymbolContributionFilter = getResourceOrNull(graph, URIs.HasSymbolContributionFilter);\r
         HasSymbol_Inverse = getResourceOrNull(graph, URIs.HasSymbol_Inverse);\r
         HasTailConnector = getResourceOrNull(graph, URIs.HasTailConnector);\r
+        HasTemplate = getResourceOrNull(graph, URIs.HasTemplate);\r
+        HasTemplate_Inverse = getResourceOrNull(graph, URIs.HasTemplate_Inverse);\r
         HasText = getResourceOrNull(graph, URIs.HasText);\r
         HasText_Inverse = getResourceOrNull(graph, URIs.HasText_Inverse);\r
         HasTransform = getResourceOrNull(graph, URIs.HasTransform);\r
index 8ecf158745efb601864335cd19411e36196d03dd..16495f4cc36af5f9c153d9956b197c746f26866b 100644 (file)
@@ -127,7 +127,13 @@ public class ModelledConnectionAdvisor implements IConnectionAdvisor {
             cps.add(getConnectionPoint(graph, element2, term2, true));\r
 \r
         ConnectionJudgement judgement = modelingRules.judgeConnection(graph, cps);\r
-        if (judgement.type == ConnectionJudgementType.LEGAL)\r
+        if (judgement.type == ConnectionJudgementType.LEGAL\r
+                // #6751, Apros #12404: a connection should not be automatically\r
+                // denied just because it is not perfectly legal. Further legality\r
+                // should be decided on the client side even though the IConnectionAdvisor\r
+                // interface is not documented to return ConnectionJudgement instances,\r
+                // because the interface knows nothing about this class.\r
+                || judgement.type == ConnectionJudgementType.CANBEMADELEGAL) \r
             return judgement;\r
         return null;\r
     }\r
index 0f1a96563348b196f46bbab138d7d65c34cfe3a7..a11c10319bcc1cb269511f819547d6893cd84a91 100644 (file)
@@ -49,16 +49,17 @@ public abstract class AbstractFlagType implements IFlagType {
     }\r
 \r
     public static Mode getMode(ReadGraph graph, Resource flag) throws DatabaseException {\r
-        int joinCount = graph.getObjects(flag, DiagramResource.getInstance(graph).FlagIsJoinedBy).size();\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        int joinCount = graph.getObjects(flag, DIA.FlagIsJoinedBy).size();\r
         if(joinCount == 0)\r
             return FlagClass.Mode.Internal;\r
         else if(joinCount == 1) {\r
-            Resource otherFlag = FlagUtil.getPossibleCounterpart(graph, flag);\r
-            if(otherFlag == null /* FIXME just to get around npe */ || \r
-                    DiagramGraphUtil.onSameDiagram(graph, flag, otherFlag))\r
-                return FlagClass.Mode.Internal;\r
-            else\r
-                return FlagClass.Mode.External;\r
+            for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy))\r
+                for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag))\r
+                    if (!flag.equals(otherFlag)\r
+                            && !DiagramGraphUtil.onSameDiagram(graph, flag, otherFlag))\r
+                        return FlagClass.Mode.External;\r
+            return FlagClass.Mode.Internal;\r
         }\r
         else\r
             return new FlagClass.External(joinCount);\r
index 27dc9e307e69038ac40daa53f5c24dc8057b412e..2a0e14b933aa7fad2c5c2364fd07b3c6f898796e 100644 (file)
@@ -28,6 +28,7 @@ import org.simantics.db.common.utils.NameUtils;
 import org.simantics.db.common.utils.OrderedSetUtils;\r
 import org.simantics.db.exception.DatabaseException;\r
 import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.function.DbBiFunction;\r
 import org.simantics.db.function.DbConsumer;\r
 import org.simantics.db.layer0.util.RemoverUtil;\r
 import org.simantics.db.layer0.variable.Variable;\r
@@ -130,6 +131,21 @@ public final class FlagUtil {
         return count;\r
     }\r
 \r
+    public static int forCounterparts(ReadGraph graph, Resource flag, DbBiFunction<Resource, Resource, Boolean> procedure) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        int count = 0;\r
+        for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {\r
+            for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {\r
+                if (!flag.equals(otherFlag)) {\r
+                    if (!procedure.apply(connectionJoin, otherFlag))\r
+                        return ++count;\r
+                    ++count;\r
+                }\r
+            }\r
+        }\r
+        return count;\r
+    }\r
+\r
     /**\r
      * Returns all flags that are joined with the given flag including the flag given as parameter.\r
      */\r
index 4aaa717d843109cb5d92e97e925fc3dd6dfab020..71a8d28290f9b7e020ef3bbb368ccc994287f8bc 100644 (file)
@@ -25,7 +25,6 @@ import java.util.Arrays;
 import java.util.Collection;\r
 import java.util.Collections;\r
 import java.util.Deque;\r
-import java.util.HashSet;\r
 import java.util.Iterator;\r
 import java.util.List;\r
 \r
@@ -39,12 +38,15 @@ import org.simantics.db.common.utils.NameUtils;
 import org.simantics.db.exception.DatabaseException;\r
 import org.simantics.diagram.connection.RouteGraph;\r
 import org.simantics.diagram.connection.RouteGraphConnectionClass;\r
+import org.simantics.diagram.connection.RouteLine;\r
 import org.simantics.diagram.connection.RouteTerminal;\r
+import org.simantics.diagram.connection.delta.RouteGraphDelta;\r
 import org.simantics.diagram.connection.rendering.arrows.PlainLineEndStyle;\r
 import org.simantics.diagram.content.ResourceTerminal;\r
 import org.simantics.diagram.stubs.DiagramResource;\r
 import org.simantics.diagram.synchronization.ISynchronizationContext;\r
 import org.simantics.diagram.synchronization.SynchronizationHints;\r
+import org.simantics.diagram.synchronization.graph.RouteGraphConnection;\r
 import org.simantics.g2d.canvas.ICanvasContext;\r
 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;\r
 import org.simantics.g2d.canvas.impl.DependencyReflection.Reference;\r
@@ -54,6 +56,7 @@ import org.simantics.g2d.connection.IConnectionAdvisor;
 import org.simantics.g2d.diagram.DiagramHints;\r
 import org.simantics.g2d.diagram.DiagramUtils;\r
 import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.handler.PickContext;\r
 import org.simantics.g2d.diagram.handler.Topology.Terminal;\r
 import org.simantics.g2d.diagram.participant.ElementPainter;\r
 import org.simantics.g2d.diagram.participant.TerminalPainter;\r
@@ -70,6 +73,7 @@ import org.simantics.g2d.element.IElementClassProvider;
 import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;\r
 import org.simantics.g2d.element.handler.SceneGraph;\r
 import org.simantics.g2d.element.handler.TerminalTopology;\r
+import org.simantics.g2d.element.handler.impl.BranchPointTerminal;\r
 import org.simantics.g2d.element.impl.Element;\r
 import org.simantics.g2d.elementclass.BranchPoint;\r
 import org.simantics.g2d.elementclass.BranchPoint.Direction;\r
@@ -77,8 +81,8 @@ import org.simantics.g2d.elementclass.FlagClass;
 import org.simantics.g2d.elementclass.FlagHandler;\r
 import org.simantics.g2d.participant.RenderingQualityInteractor;\r
 import org.simantics.g2d.participant.TransformUtil;\r
+import org.simantics.g2d.utils.geom.DirectionSet;\r
 import org.simantics.modeling.ModelingResources;\r
-import org.simantics.scenegraph.INode;\r
 import org.simantics.scenegraph.g2d.G2DParentNode;\r
 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;\r
 import org.simantics.scenegraph.g2d.events.KeyEvent;\r
@@ -101,6 +105,8 @@ import org.simantics.utils.logging.TimeLogger;
 import org.simantics.utils.ui.ErrorLogger;\r
 import org.simantics.utils.ui.ExceptionUtils;\r
 \r
+import gnu.trove.map.hash.THashMap;\r
+\r
 /**\r
  * A basic tool for making connection on diagrams.\r
  * \r
@@ -141,6 +147,9 @@ public class ConnectTool2 extends AbstractMode {
     @Dependency\r
     protected PointerInteractor      pi;\r
 \r
+    @Dependency\r
+    protected PickContext            pickContext;\r
+\r
     /**\r
      * Start element terminal of the connection. <code>null</code> if connection\r
      * was started from a flag or a branch point.\r
@@ -269,6 +278,8 @@ public class ConnectTool2 extends AbstractMode {
 \r
     protected G2DParentNode          endFlagNode;\r
 \r
+    private RouteGraphTarget         lastRouteGraphTarget;\r
+\r
     /**\r
      * @param startTerminal\r
      * @param mouseId\r
@@ -387,9 +398,9 @@ public class ConnectTool2 extends AbstractMode {
 \r
         ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
         pathNode.setColor(new Color(160, 0, 0));\r
-        pathNode.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,\r
-                new float[] { 5f, 2f }, 0));\r
-        pathNode.setScaleStroke(true);\r
+        pathNode.setStroke(new BasicStroke(0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,\r
+                new float[] { 0.5f, 0.2f }, 0));\r
+        pathNode.setScaleStroke(false);\r
         pathNode.setZIndex(0);\r
 \r
         G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class);\r
@@ -443,105 +454,18 @@ public class ConnectTool2 extends AbstractMode {
 \r
         ControlPoint begin = controlPoints.getFirst();\r
         ControlPoint end = controlPoints.getLast();\r
-        \r
+\r
         RouteGraph routeGraph = new RouteGraph();\r
         RouteTerminal a = addControlPoint(routeGraph, begin);\r
         RouteTerminal b = addControlPoint(routeGraph, end);\r
         routeGraph.link(a, b);\r
-        \r
-        // Route connection segments separately\r
-        /*Router2 router = ElementUtils.getHintOrDefault(diagram, DiagramHints.ROUTE_ALGORITHM, TrivialRouter2.INSTANCE);\r
-        final List<Segment> segments = toSegments(controlPoints);\r
-        //System.out.println("controlpoints: " + controlPoints);\r
-        //System.out.println("segments: " + segments);\r
-        router.route(new IConnection() {\r
-            @Override\r
-            public Collection<? extends Object> getSegments() {\r
-                return segments;\r
-            }\r
-\r
-            @Override\r
-            public Connector getBegin(Object seg) {\r
-                return getConnector(((Segment) seg).begin);\r
-            }\r
-\r
-            @Override\r
-            public Connector getEnd(Object seg) {\r
-                return getConnector(((Segment) seg).end);\r
-            }\r
-\r
-            private Connector getConnector(ControlPoint cp) {\r
-                Connector c = new Connector();\r
-                c.x = cp.getPosition().getX();\r
-                c.y = cp.getPosition().getY();\r
-\r
-                TerminalInfo ti = cp.getAttachedTerminal();\r
-                if (ti != null && (ti == startFlag || ti != endFlag)) {\r
-                    //System.out.println("CP1: " + cp);\r
-                    c.parentObstacle = DiagramUtils.getObstacleShape(ti.e);\r
-                    ConnectionDirectionUtil.determineAllowedDirections(c);\r
-                } else {\r
-                    //System.out.println("CP2: " + cp);\r
-                    c.parentObstacle = GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
-                            BranchPointClass.DEFAULT_IMAGE2.getBounds());\r
-                    c.allowedDirections = toAllowedDirections(cp.getDirection());\r
-                }\r
-\r
-                return c;\r
-            }\r
 \r
-            @Override\r
-            public void setPath(Object seg, Path2D path) {\r
-                ((Segment) seg).path = (Path2D) path.clone();\r
-            }\r
-\r
-            private int toAllowedDirections(BranchPoint.Direction direction) {\r
-                switch (direction) {\r
-                    case Any:\r
-                        return 0xf;\r
-                    case Horizontal:\r
-                        return Constants.EAST_FLAG | Constants.WEST_FLAG;\r
-                    case Vertical:\r
-                        return Constants.NORTH_FLAG | Constants.SOUTH_FLAG;\r
-                    default:\r
-                        throw new IllegalArgumentException("unrecognized direction: " + direction);\r
-                }\r
-            }\r
-        });\r
-\r
-        // Combine the routed paths\r
-        Path2D path = new Path2D.Double();\r
-        for (Segment seg : segments) {\r
-            //System.out.println("SEG: " + seg);\r
-            if (seg.path != null)\r
-                path.append(seg.path.getPathIterator(null), true);\r
-        }*/\r
-        \r
         Path2D path = routeGraph.getPath2D();\r
 \r
         // Create scene graph to visualize the connection.\r
         ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
         pathNode.setShape(path);\r
 \r
-        G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class);\r
-        HashSet<INode> unusedChildren = new HashSet<INode>(points.getNodes());\r
-        int i = 0;\r
-        for (ControlPoint cp : controlPoints) {\r
-            if (cp.isAttachedToTerminal())\r
-                continue;\r
-\r
-            String id = String.valueOf(i);\r
-            BranchPointNode bpn = points.getOrCreateNode(id, BranchPointNode.class);\r
-            bpn.setDegree(2);\r
-            bpn.setDirection((byte) cp.getDirection().ordinal());\r
-            bpn.setTransform(AffineTransform.getTranslateInstance(cp.getPosition().getX(), cp.getPosition().getY()));\r
-\r
-            ++i;\r
-            unusedChildren.remove(bpn);\r
-        }\r
-        for (INode unusedChild : unusedChildren)\r
-            points.removeNode(unusedChild);\r
-\r
         setDirty();\r
     }\r
 \r
@@ -668,12 +592,48 @@ public class ConnectTool2 extends AbstractMode {
 \r
                     // Make sure that we are ending with a flag if ALT is pressed\r
                     // and no end terminal is defined.\r
-                    endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
-\r
-                    updateSG();\r
+                    if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)))\r
+                        updateSG();\r
                     return false;\r
                 }\r
             }\r
+        } else {\r
+            RouteGraphTarget cp = RouteGraphConnectTool.pickRouteGraphConnection(\r
+                    diagram,\r
+                    pi.getCanvasPickShape(me.controlPosition),\r
+                    pi.getPickDistance());\r
+            if (cp != null) {\r
+                // Remove branch point highlight from previously picked route graph.\r
+                if (lastRouteGraphTarget != null && cp.getNode() != lastRouteGraphTarget.getNode())\r
+                    cp.getNode().showBranchPoint(null);\r
+                lastRouteGraphTarget = cp;\r
+\r
+                // Validate connection before visualizing connectability\r
+                Point2D isectPos = cp.getIntersectionPosition();\r
+                TerminalInfo ti = TerminalInfo.create(\r
+                        isectPos,\r
+                        cp.getElement(),\r
+                        BranchPointTerminal.existingTerminal(\r
+                                isectPos,\r
+                                DirectionSet.ANY,\r
+                                BranchPointNode.SHAPE),\r
+                        BranchPointNode.SHAPE);\r
+                Pair<ConnectionJudgement, TerminalInfo> canConnect = canConnect(ti.e, ti.t);\r
+                if (canConnect != null) {\r
+                    connectionJudgment = canConnect.first;\r
+                    controlPoints.getLast().setPosition(ti.posDia).setAttachedToTerminal(ti);\r
+                    endTerminal = ti;\r
+                    cp.getNode().showBranchPoint(isectPos);\r
+                    if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)))\r
+                        updateSG();\r
+                    return false;\r
+                }\r
+            } else {\r
+                if (lastRouteGraphTarget != null) {\r
+                    lastRouteGraphTarget.getNode().showBranchPoint(null);\r
+                    lastRouteGraphTarget = null;\r
+                }\r
+            }\r
         }\r
 \r
         connectionJudgment = null;\r
@@ -705,9 +665,8 @@ public class ConnectTool2 extends AbstractMode {
 \r
         // Make sure that we are ending with a flag if ALT is pressed and no end\r
         // terminal is defined.\r
-        endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
-\r
-        updateSG();\r
+        if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)))\r
+            updateSG();\r
 \r
         return false;\r
     }\r
@@ -729,8 +688,13 @@ public class ConnectTool2 extends AbstractMode {
             if (snapAdvisor != null)\r
                 snapAdvisor.snap(mouseCanvasPos);\r
 \r
-            // Clicked on an allowed end terminal. End connection & end mode.\r
-            if (isEndTerminalDefined()) {\r
+            if (lastRouteGraphTarget != null) {\r
+                lastRouteGraphTarget.getNode().showBranchPoint(null);\r
+                attachToConnection();\r
+                remove();\r
+                return true;\r
+            } else if (isEndTerminalDefined()) {\r
+                // Clicked on an allowed end terminal. End connection & end mode.\r
                 createConnection();\r
                 remove();\r
                 return true;\r
@@ -772,6 +736,53 @@ public class ConnectTool2 extends AbstractMode {
         return false;\r
     }\r
 \r
+    private void attachToConnection() {\r
+        ConnectionJudgement judgment = this.connectionJudgment;\r
+        if (judgment == null) {\r
+            ErrorLogger.defaultLogError("Cannot attach to connection, no judgment available on connection validity", null);\r
+            return;\r
+        }\r
+\r
+        ConnectionBuilder builder = new ConnectionBuilder(this.diagram);\r
+        RouteGraph before = lastRouteGraphTarget.getNode().getRouteGraph();\r
+        THashMap<Object, Object> copyMap = new THashMap<>();\r
+        RouteGraph after = before.copy(copyMap);\r
+\r
+        RouteLine attachTo = (RouteLine) copyMap.get(lastRouteGraphTarget.getLine());\r
+        after.makePersistent(attachTo);\r
+        for (RouteLine line : after.getAllLines()) {\r
+            if (!line.isTransient() && line.isHorizontal() == attachTo.isHorizontal()\r
+                    && line.getPosition() == attachTo.getPosition()) {\r
+                attachTo = line;\r
+                break;\r
+            }\r
+        }\r
+        RouteLine attachToLine = attachTo;\r
+        RouteGraphDelta delta = new RouteGraphDelta(before, after);\r
+\r
+        Simantics.getSession().asyncRequest(new WriteRequest() {\r
+            @Override\r
+            public void perform(WriteGraph graph) throws DatabaseException {\r
+                graph.markUndoPoint();\r
+                Resource connection = ElementUtils.getObject(endTerminal.e);\r
+                if (!delta.isEmpty()) {\r
+                    new RouteGraphConnection(graph, connection).synchronize(graph, before, after, delta);\r
+                }\r
+                Resource line = RouteGraphConnection.deserialize(graph, attachToLine.getData());\r
+                Deque<ControlPoint> cps = new ArrayDeque<>();\r
+                for (Iterator<ControlPoint> iterator = controlPoints.descendingIterator(); iterator.hasNext();)\r
+                    cps.add(iterator.next());\r
+                builder.attachToRouteGraph(graph, judgment, connection, line, cps, startTerminal, FlagClass.Type.In);\r
+            }\r
+        }, new Callback<DatabaseException>() {\r
+            @Override\r
+            public void run(DatabaseException parameter) {\r
+                if (parameter != null)\r
+                    ExceptionUtils.logAndShowError(parameter);\r
+            }\r
+        });\r
+    }\r
+\r
     protected boolean cancelPreviousBend() {\r
         if (!routePointsAllowed())\r
             return false;\r
@@ -912,10 +923,16 @@ public class ConnectTool2 extends AbstractMode {
         return endFlag != null;\r
     }\r
 \r
-    protected void endWithoutTerminal(Point2D mousePos, boolean altDown) {\r
+    /**\r
+     * @param mousePos\r
+     * @param altDown\r
+     * @return <code>true</code> if updateSG was executed, <code>false</code>\r
+     *         otherwise\r
+     */\r
+    protected boolean endWithoutTerminal(Point2D mousePos, boolean altDown) {\r
         // Just go with branch points if flags are not allowed.\r
         if (!createFlags)\r
-            return;\r
+            return false;\r
 \r
         boolean endTerminalDefined = isEndTerminalDefined();\r
 \r
@@ -931,6 +948,7 @@ public class ConnectTool2 extends AbstractMode {
                 setHint(TerminalPainter.TERMINAL_HOVER_STRATEGY, terminalHoverStrategy);\r
 \r
                 updateSG();\r
+                return true;\r
             }\r
         } else {\r
             if (isEndingInFlag()) {\r
@@ -954,8 +972,10 @@ public class ConnectTool2 extends AbstractMode {
                 setHint(TerminalPainter.TERMINAL_HOVER_STRATEGY, terminalHoverStrategy);\r
 \r
                 updateSG();\r
+                return true;\r
             }\r
         }\r
+        return false;\r
     }\r
 \r
     protected void createConnection() {\r
index 1fcf074cdf8c2863517aea5b22f225f265097764..b36961f87a589595d939d3045c0482bd3e71939c 100644 (file)
@@ -475,7 +475,8 @@ public class ConnectionBuilder {
             Resource attachToConnection,\r
             Resource attachToLine,\r
             Deque<ControlPoint> controlPoints,\r
-            TerminalInfo endTerminal)\r
+            TerminalInfo endTerminal,\r
+            FlagClass.Type flagType)\r
                     throws DatabaseException\r
     {\r
         initializeResources(graph);\r
@@ -502,9 +503,10 @@ public class ConnectionBuilder {
             if (endTerminal != null) {\r
                 endConnector = createConnectorForNode(graph, attachToConnection, endTerminal, EdgeEnd.End, judgment);\r
             } else if (createFlags) {\r
-                IElement endFlag = createFlag(graph, attachToConnection, EdgeEnd.End, controlPoints.getLast(), FlagClass.Type.Out, null);\r
+                EdgeEnd end = flagType == FlagClass.Type.In ? EdgeEnd.Begin : EdgeEnd.End;\r
+                IElement endFlag = createFlag(graph, attachToConnection, end, controlPoints.getLast(), flagType, null);\r
                 endConnector = createConnectorForNode(graph, attachToConnection, (Resource) ElementUtils.getObject(endFlag),\r
-                        ElementUtils.getSingleTerminal(endFlag), EdgeEnd.End, judgment);\r
+                        ElementUtils.getSingleTerminal(endFlag), end, judgment);\r
             }\r
 \r
             cu.connect(attachToLine, endConnector.getConnector());\r
index af1f48f5d89d42dc253257995bd09cc8cddacc25..57f5cd4900310263031a81d3227c99f355a25917 100644 (file)
@@ -763,7 +763,7 @@ public class RouteGraphConnectTool extends AbstractMode {
                     new RouteGraphConnection(graph, connection).synchronize(graph, rgs.first, rgs.second, rgs.third);\r
                 }\r
                 Resource attachToLine = RouteGraphConnection.deserialize(graph, attachedToRouteLine.getData());\r
-                builder.attachToRouteGraph(graph, judgment, connection, attachToLine, controlPoints, endTerminal);\r
+                builder.attachToRouteGraph(graph, judgment, connection, attachToLine, controlPoints, endTerminal, FlagClass.Type.Out);\r
             }\r
         }, new Callback<DatabaseException>() {\r
             @Override\r
index 9baa067f783294da74d63c8ba02c5e339230e277..0246143d24dccd590583e299980c54fc20979a43 100644 (file)
@@ -15,17 +15,28 @@ import java.util.ArrayList;
 import java.util.HashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
+import java.util.Set;\r
 \r
 import org.simantics.databoard.Bindings;\r
 import org.simantics.db.ReadGraph;\r
 import org.simantics.db.Resource;\r
 import org.simantics.db.WriteGraph;\r
+import org.simantics.db.WriteOnlyGraph;\r
 import org.simantics.db.common.request.WriteRequest;\r
 import org.simantics.db.common.utils.ListUtils;\r
 import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.impl.DefaultCopyHandler;\r
+import org.simantics.db.layer0.adapter.impl.DefaultPasteImportAdvisor;\r
+import org.simantics.db.layer0.util.ClipboardUtils;\r
+import org.simantics.db.layer0.util.SimanticsClipboard;\r
+import org.simantics.db.layer0.util.SimanticsClipboardImpl;\r
+import org.simantics.db.layer0.util.SimanticsKeys;\r
 import org.simantics.db.layer0.variable.Variable;\r
 import org.simantics.db.service.VirtualGraphSupport;\r
 import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.graph.db.TransferableGraphs;\r
+import org.simantics.graph.representation.Root;\r
+import org.simantics.graph.representation.TransferableGraph1;\r
 import org.simantics.layer0.Layer0;\r
 import org.simantics.modeling.ModelingResources;\r
 import org.simantics.simulation.ontology.SimulationResource;\r
@@ -201,7 +212,6 @@ public class Profiles {
                                        for (Resource r : enabled) {\r
                                                graph.claim(p, SIM.IsActive, r);\r
                                        }\r
-\r
                                }\r
                        });\r
                }\r
@@ -255,6 +265,35 @@ public class Profiles {
                Double priority = graph.getPossibleRelatedValue(entry, DIA.ProfileEntry_HasPriority, Bindings.DOUBLE);\r
                if (priority != null) {\r
                        graph.claimLiteral(instance, DIA.ProfileEntry_HasPriority, priority, Bindings.DOUBLE);\r
+               }\r
+               for (Resource template : graph.getObjects(entry, DIA.HasTemplate)) {\r
+                       SimanticsClipboardImpl builder = new SimanticsClipboardImpl();\r
+                       DefaultCopyHandler handler = new DefaultCopyHandler(template);\r
+                       DefaultPasteImportAdvisor advisor = new DefaultPasteImportAdvisor(instance) {\r
+                               @Override\r
+                               public Resource createRoot(WriteOnlyGraph graph, Root root, Resource resource)\r
+                                               throws DatabaseException {\r
+                                       Layer0 l0 = graph.getService(Layer0.class);\r
+                                       DiagramResource DIA = graph.getService(DiagramResource.class);  \r
+                                       \r
+                                       if(resource == null) resource = graph.newResource();\r
+                                       \r
+                                       graph.claim(library, DIA.HasTemplate, DIA.HasTemplate_Inverse, resource);\r
+                                       \r
+                                       String newName = getName(root);\r
+                                       graph.addLiteral(resource, l0.HasName, l0.NameOf, l0.String, newName, Bindings.STRING);\r
+                                       \r
+                                       addRootInfo(root, newName, resource);\r
+                                       \r
+                                       return resource;\r
+                               }\r
+                       };\r
+                       handler.copyToClipboard(graph, builder);\r
+                       for(Set<SimanticsClipboard.Representation> object : builder.getContents()) {\r
+                   TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);\r
+                   TransferableGraphs.importGraph1(graph, tg, advisor);\r
+               }\r
+                        \r
                }\r
                return instance;\r
        }\r
index ba933d71c33a0ea0f29179ee8a6c52cb65bb392a..eb957c8f62df21833e4c93dde1cc50568e4e806c 100644 (file)
  *******************************************************************************/\r
 package org.simantics.document.server.io;\r
 \r
+import java.io.InputStream;\r
+\r
 public class Content {\r
-       private byte[] data;\r
+       private InputStream input;\r
        private String mimeType;\r
        private long lastModified;\r
+       private int length;\r
        \r
-       public Content(byte[] data, String mimeType, long lastModified) {\r
-               this.data = data;\r
+       public Content(InputStream input, String mimeType, long lastModified, int length) {\r
+               this.input = input;\r
                this.mimeType = mimeType;\r
                this.lastModified = lastModified;\r
+               this.length = length;\r
        }\r
 \r
-       public byte[] getData() {\r
-               return data;\r
+       public InputStream getInputStream() {\r
+               return input;\r
        }\r
 \r
-       public void setData(byte[] data) {\r
-               this.data = data;\r
+       public void setInputStream(InputStream input) {\r
+               this.input = input;\r
        }\r
 \r
        public String getMimeType() {\r
@@ -46,4 +50,12 @@ public class Content {
        public void setLastModified(long lastModified) {\r
                this.lastModified = lastModified;\r
        }\r
+\r
+       public int getLength() {\r
+               return length;\r
+       }\r
+\r
+       public void setLength(int length) {\r
+               this.length = length;\r
+       }\r
 }\r
index bb85be21fe878143cb864547df0576043625efc3..c4b83aa994c3c3c9585b39f3a503fd28b9b95416 100644 (file)
@@ -1,10 +1,12 @@
 package org.simantics.event.util;\r
 \r
+import java.util.List;\r
 import java.util.UUID;\r
 \r
 import org.simantics.databoard.Bindings;\r
 import org.simantics.db.Resource;\r
 import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.PossibleTypedParent;\r
 import org.simantics.db.exception.DatabaseException;\r
 import org.simantics.event.ontology.EventResource;\r
 import org.simantics.layer0.Layer0;\r
@@ -25,5 +27,46 @@ public class EventUtils {
         graph.claimLiteral(log, EVENT.HasModificationCounter, 0, Bindings.INTEGER);\r
         return log;\r
        }\r
-       \r
+\r
+    /**\r
+     * Bumps the modification counter value of the event log of the specified\r
+     * events using {@link #bumpModificationCounter(WriteGraph, Resource)}.\r
+     * <p>\r
+     * The code assumes that all events are from the same log.\r
+     * \r
+     * @param graph\r
+     * @param forLogOfEvents\r
+     * @throws DatabaseException\r
+     */\r
+    public static void bumpModificationCounter(WriteGraph graph, List<Resource> forLogOfEvents) throws DatabaseException {\r
+        EventResource EVENT = EventResource.getInstance(graph);\r
+        for (Resource event : forLogOfEvents) {\r
+            Resource log = graph.syncRequest(new PossibleTypedParent(event, EVENT.EventLog));\r
+            if (log != null) {\r
+                bumpModificationCounter(graph, log);\r
+                return;\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Bumps the modification counter of the specified event log by 1.\r
+     * \r
+     * @param graph\r
+     * @param eventLog\r
+     * @return new modification counter value\r
+     * @throws DatabaseException\r
+     */\r
+    public static int bumpModificationCounter(WriteGraph graph, Resource eventLog) throws DatabaseException {\r
+        EventResource EVENT = EventResource.getInstance(graph);\r
+        Resource counter = graph.getPossibleObject(eventLog, EVENT.HasModificationCounter);\r
+        if (counter != null) {\r
+            Integer c = graph.getValue(counter, Bindings.INTEGER);\r
+            c = c == null ? 1 : c+1;\r
+            graph.claimValue(counter, c, Bindings.INTEGER);\r
+            return c;\r
+        }\r
+        return 0;\r
+    }\r
+\r
 }\r
index e6e59966c37f7d0a15696d6d7d53e369f048ff6e..9b9ea8bfe07437702a1403ce715e567d33637595 100644 (file)
@@ -116,20 +116,25 @@ public enum ProjectEventsRule implements ChildRule {
             if (!showHiddenEvents && graph.hasStatement(event, EVENT.Hidden))\r
                 continue;\r
 \r
+            boolean isReturnEvent = hideReturnEvents || showOnlyActiveEvents\r
+                    ? graph.hasStatement(event, EVENT.ReturnEvent) : false;\r
+\r
+            // Skip all return events if thus preferred.\r
+            if (hideReturnEvents && isReturnEvent) {\r
+                continue;\r
+            }\r
+\r
+            // Skip all return events and starting events that have been returned,\r
+            // if thus preferred. Also skip events that are defined non-returnable.\r
             if (showOnlyActiveEvents\r
-                    && (graph.hasStatement(event, EVENT.Returns)\r
+                    && (isReturnEvent\r
+                            || graph.hasStatement(event, EVENT.Returns)\r
                             || graph.hasStatement(event, EVENT.ReturnedBy)\r
                             || graph.hasStatement(event, EVENT.NoReturn)))\r
             {\r
                 continue;\r
             }\r
 \r
-            // Skip return events if thus preferred.\r
-            if (hideReturnEvents && graph.hasStatement(event, EVENT.ReturnEvent)) {\r
-                if (graph.getPossibleObject(event, EVENT.Returns) != null)\r
-                    continue;\r
-            }\r
-\r
             // Filter by event type severity\r
             Resource eventType = graph.getPossibleObject(event, EVENT.Event_type);\r
             if (eventType != null) {\r
diff --git a/bundles/org.simantics.event/src/org/simantics/event/view/handler/Hide.java b/bundles/org.simantics.event/src/org/simantics/event/view/handler/Hide.java
deleted file mode 100644 (file)
index 778c5fb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2007, 2011 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.event.view.handler;\r
-\r
-import org.simantics.event.ontology.EventResource;\r
-\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- */\r
-public class Hide extends PreferenceHandler {\r
-\r
-    public Hide() {\r
-        super("experiments", EventResource.URIs.Hidden, true);\r
-    }\r
-\r
-}\r
index ddd70fb7fa6d46add38bf7a0b99c6268e20a15d1..9b125ed446342deb269dd77ec5b2c02517ba9074 100644 (file)
@@ -24,6 +24,7 @@ import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.SelectionHints;\r
 import org.simantics.event.Activator;\r
 import org.simantics.event.ontology.EventResource;\r
+import org.simantics.event.util.EventUtils;\r
 import org.simantics.ui.contribution.DynamicMenuContribution;\r
 import org.simantics.ui.workbench.action.PerformDefaultAction;\r
 import org.simantics.utils.ui.ISelectionUtils;\r
@@ -147,13 +148,17 @@ public class MenuActions extends DynamicMenuContribution {
     }\r
 \r
     private IAction hideAction(List<Resource> input) {\r
-        return tagAction("Hide", Activator.HIDE_ICON, EventResource.URIs.Hidden, true, input);\r
+        return contentChangingTagAction("Hide", Activator.HIDE_ICON, EventResource.URIs.Hidden, true, input);\r
     }\r
 \r
     private IAction tagAction(String label, ImageDescriptor image, String tagURI, boolean tag, List<Resource> input) {\r
         return new TagAction(label, image, VG_EXPERIMENTS, tagURI, tag, input);\r
     }\r
 \r
+    private IAction contentChangingTagAction(String label, ImageDescriptor image, String tagURI, boolean tag, List<Resource> input) {\r
+        return new ContentChangingTagAction(label, image, VG_EXPERIMENTS, tagURI, tag, input);\r
+    }\r
+\r
     private IAction setBaseline(Resource eventLog, Resource event) {\r
         return new SetBaseline(VG_EXPERIMENTS, eventLog, event);\r
     }\r
@@ -169,6 +174,17 @@ public class MenuActions extends DynamicMenuContribution {
         return new PerformDefaultAction(title, null, input);\r
     }\r
 \r
+    private static class ContentChangingTagAction extends TagAction {\r
+        public ContentChangingTagAction(String label, ImageDescriptor image, String virtualGraphId, String tagURI, boolean tag, List<Resource> input) {\r
+            super(label, image, virtualGraphId, tagURI, tag, input);\r
+        }\r
+\r
+        @Override\r
+        public void postTagWrite(WriteGraph graph) throws DatabaseException {\r
+            EventUtils.bumpModificationCounter(graph, resources);\r
+        }\r
+    }\r
+\r
     private static class ToClipboardAction extends Action {\r
         private String text;\r
 \r
index 0de441539f55d7a2293eab8ff09b48e13f4902af..3491e29f05ee9870c94ef45550d467a53282846f 100644 (file)
@@ -22,7 +22,7 @@ public class TagAction extends Action {
     private final String virtualGraphId;\r
     private final String tagURI;\r
     private final boolean tag;\r
-    private final List<Resource> resources;\r
+    protected final List<Resource> resources;\r
 \r
     /**\r
      * @param label\r
index a28cfa56360230f754c5c3b7359b5d1c3250153c..409af79d69e4e0febb7fd69375ccb8f76d867fe1 100644 (file)
@@ -78,6 +78,17 @@ public class TerminalUtil {
             .append(']');\r
             return sb.toString();\r
         }\r
+\r
+        public static TerminalInfo create(Point2D p, IElement e, Terminal t, Shape terminalShape) {\r
+            AffineTransform at = AffineTransform.getTranslateInstance(p.getX(), p.getY());\r
+            TerminalInfo ti = new TerminalInfo();\r
+            ti.e = e;\r
+            ti.t = t;\r
+            ti.posElem = at;\r
+            ti.posDia = at;\r
+            ti.shape = terminalShape;\r
+            return ti;\r
+        }\r
     }\r
     private static final Rectangle2D POINT_PICK_SHAPE = new Rectangle2D.Double(0, 0, 0.001, 0.001);\r
 \r
index bce157dd5d035d3768e1359ddb14c32b0dd1ca8c..3ad4a9f7502a61b73a4a3ff4db097b9aa4c91e68 100644 (file)
@@ -13,6 +13,7 @@ package org.simantics.g2d.element.handler.impl;
 \r
 import java.awt.Shape;\r
 import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Point2D;\r
 \r
 import org.simantics.g2d.utils.geom.DirectionSet;\r
 \r
@@ -39,4 +40,8 @@ public class BranchPointTerminal extends ObjectTerminal {
         return new BranchPointTerminal(EXISTING_BRANCH_POINT_DATA, transform, ds, shape);\r
     }\r
 \r
+    public static BranchPointTerminal existingTerminal(Point2D p, DirectionSet ds, Shape shape) {\r
+        return existingTerminal(AffineTransform.getTranslateInstance(p.getX(), p.getY()), ds, shape);\r
+    }\r
+\r
 }
\ No newline at end of file
index bbe8111e54ceb46168a94a6a5e0a0c3954303f94..882e04f0d20db2dcd5cdbd9eaf1b55d4213d97a9 100644 (file)
@@ -80,6 +80,7 @@ public class SyncActiveModelTypicals {
                 RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, msg.toString(), activeModelTypicalTemplates);\r
                 if(result == null) return;\r
 \r
+                session.markUndoPoint();\r
                 SyncTypicalTemplatesToInstances req = new SyncTypicalTemplatesToInstances(result.selectedRules, activeModelTypicalTemplates).logging(result.logging); \r
                 session.syncRequest(req);\r
                 if (result.logging) {\r
index 86bfdc0bbf97c226e1a6d49c508bf7661658f32c..b0d52e355910c316e77f0792778554caee79077f 100644 (file)
@@ -79,6 +79,7 @@ public class SyncCurrentTypicalInstanceWithTemplate {
             RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, "Synchronizing typical instance with its template.", new Resource[] { input.getResource() });\r
             if(result == null) return;\r
 \r
+            session.markUndoPoint();\r
             SyncTypicalTemplatesToInstances req = SyncTypicalTemplatesToInstances.syncSingleInstance(result.selectedRules, input.getResource()).logging(result.logging); \r
             session.syncRequest(req);\r
             if (result.logging) {\r
index f262cd56e53a3868e3ef4c86683769513dad9100..d3d1de3896c45100c4f22d04f03587931d620afd 100644 (file)
@@ -77,6 +77,7 @@ public class SyncCurrentTypicalTemplateToInstances {
             RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, "Synchronizing typical template to all its instances.", new Resource[] { input.getResource() });\r
             if(result == null) return;\r
 \r
+            session.markUndoPoint();\r
             SyncTypicalTemplatesToInstances req = new SyncTypicalTemplatesToInstances(result.selectedRules, input.getResource()).logging(result.logging); \r
             session.syncRequest(req);\r
             if (result.logging) {\r
index 5ba8b9f2d48466d7f5c28248859359307e8ae1a0..441702dd564ad375c92d5e851f0977d8ad13db8a 100644 (file)
@@ -80,6 +80,7 @@ public class SyncActiveModelTypicals extends AbstractHandler {
                 RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, msg.toString(), activeModelTypicalTemplates);\r
                 if(result == null) return null;\r
 \r
+                session.markUndoPoint();\r
                 SyncTypicalTemplatesToInstances req = new SyncTypicalTemplatesToInstances(result.selectedRules, activeModelTypicalTemplates).logging(result.logging); \r
                 session.syncRequest(req);\r
                 if (result.logging) {\r
index df049a6719009e4998bd6d6a36cb0cd25e79db25..3b1455f37057e1f3098b81174d83f511ef069ace 100644 (file)
@@ -44,6 +44,7 @@ public class SyncCurrentTypicalInstanceWithTemplate extends AbstractHandler {
             RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, "Synchronizing typical instance with its template.", new Resource[] { input.getResource() });\r
             if(result == null) return null;\r
 \r
+            session.markUndoPoint();\r
             SyncTypicalTemplatesToInstances req = SyncTypicalTemplatesToInstances.syncSingleInstance(result.selectedRules, input.getResource()).logging(result.logging); \r
             session.syncRequest(req);\r
             if (result.logging) {\r
index 931e3f7fac5da25d3031ec0ecec2227cb1ce25be..c4454831e94412de3990203ea899f64814bd9258 100644 (file)
@@ -43,6 +43,7 @@ public class SyncCurrentTypicalTemplateToInstances extends AbstractHandler {
             RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, "Synchronizing typical template to all its instances in the currently active model.", new Resource[] { input.getResource() });\r
             if(result == null) return null;\r
 \r
+            session.markUndoPoint();\r
             SyncTypicalTemplatesToInstances req = new SyncTypicalTemplatesToInstances(result.selectedRules, input.getResource()).logging(result.logging); \r
             session.syncRequest(req);\r
             if (result.logging) {\r
index e1494cf3201f3fd79fefe0efc9956d0c6e4ea5a8..709e981bc16850e11ab78f61accbc478c8c7727f 100644 (file)
@@ -2312,6 +2312,7 @@ public class ModelingUtils {
                String extension = (String)t.get(1);\r
                filterNames[index] = filterName;\r
                extensions[index] = extension;\r
+               index++;\r
         }\r
         \r
         dialog.setFilterExtensions(extensions);\r
index 96a33393aeac5bab1c972d995cd1e0754a33ae71..44b2abcfeae8d3ad1915a2bf16a827fd86313730 100644 (file)
@@ -49,6 +49,7 @@ import org.simantics.diagram.handler.CopyPasteStrategy;
 import org.simantics.diagram.handler.ElementObjectAssortment;\r
 import org.simantics.diagram.handler.PasteOperation;\r
 import org.simantics.diagram.handler.Paster;\r
+import org.simantics.diagram.handler.Paster.RouteLine;\r
 import org.simantics.diagram.stubs.DiagramResource;\r
 import org.simantics.diagram.synchronization.CollectingModificationQueue;\r
 import org.simantics.diagram.synchronization.CopyAdvisor;\r
@@ -206,9 +207,9 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
      */\r
     protected Map<Object, Object>            copyMap;\r
 \r
-    final private Map<Resource, List<String>> messageLogs = new HashMap<Resource, List<String>>();\r
+    final private Map<Resource, List<String>> messageLogs = new HashMap<>();\r
     \r
-    public List<Resource> logs = new ArrayList<Resource>();\r
+    public List<Resource> logs = new ArrayList<>();\r
 \r
        private boolean writeLog;\r
 \r
@@ -295,7 +296,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
        if(indexRoot == null) throw new DatabaseException("FATAL: Diagram is not under any index root.");\r
        List<String> log = messageLogs.get(indexRoot);\r
        if(log == null) {\r
-               log = new ArrayList<String>();\r
+               log = new ArrayList<>();\r
                messageLogs.put(indexRoot, log);\r
        }\r
        return log;\r
@@ -331,7 +332,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         this.syncCtx.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));\r
 \r
         this.metadata = new TypicalSynchronizationMetadata();\r
-        this.metadata.synchronizedTypicals = new ArrayList<Resource>();\r
+        this.metadata.synchronizedTypicals = new ArrayList<>();\r
 \r
         this.temporaryDiagram = Diagram.spawnNew(DiagramClass.DEFAULT);\r
         this.temporaryDiagram.setHint(SynchronizationHints.CONTEXT, syncCtx);\r
@@ -365,7 +366,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
                 Collection<Resource> libs = graph.syncRequest(new ObjectsWithType(indexRoot, L0.ConsistsOf, DOC.DocumentLibrary));\r
                 if(libs.isEmpty()) continue;\r
 \r
-                List<NamedResource> nrs = new ArrayList<NamedResource>();\r
+                List<NamedResource> nrs = new ArrayList<>();\r
                 for(Resource lib : libs) nrs.add(new NamedResource(NameUtils.getSafeName(graph, lib), lib));\r
                 Collections.sort(nrs, AlphanumComparator.CASE_INSENSITIVE_COMPARATOR);\r
                 Resource library = nrs.iterator().next().getResource();\r
@@ -416,7 +417,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         if (instances.isEmpty())\r
             return;\r
 \r
-        Set<Resource> templateElements = new THashSet<Resource>( graph.syncRequest(\r
+        Set<Resource> templateElements = new THashSet<>( graph.syncRequest(\r
                 new ObjectsWithType(template, L0.ConsistsOf, DIA.Element) ) );\r
 \r
         try {\r
@@ -436,7 +437,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         if (template == null)\r
             return;\r
 \r
-        Set<Resource> templateElements = new THashSet<Resource>( graph.syncRequest(\r
+        Set<Resource> templateElements = new THashSet<>( graph.syncRequest(\r
                 new ObjectsWithType(template, L0.ConsistsOf, DIA.Element) ) );\r
 \r
         try {\r
@@ -499,7 +500,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         // therefore clone the query result.\r
         typicalInfoBean = (TypicalInfoBean) typicalInfoBean.clone();\r
         typicalInfoBean.templateElements = currentTemplateElements;\r
-        typicalInfoBean.auxiliary = new HashMap<Object, Object>(1);\r
+        typicalInfoBean.auxiliary = new HashMap<>(1);\r
 \r
         TypicalInfo info = new TypicalInfo();\r
         info.monitor = monitor;\r
@@ -523,12 +524,12 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         // instance elements that do not have a MOD.HasElementSource\r
         // relation but have a MOD.IsTemplatized tag.\r
         Set<Resource> instanceElementsRemovedFromTemplate = findInstanceElementsRemovedFromTemplate(\r
-                graph, info, new THashSet<Resource>(dSizeAbs));\r
+                graph, info, new THashSet<>(dSizeAbs));\r
 \r
         // Find elements in template that do not yet exist in the instance\r
         Set<Resource> templateElementsAddedToTemplate = findTemplateElementsMissingFromInstance(\r
                 graph, currentTemplateElements, info,\r
-                new THashSet<Resource>(dSizeAbs));\r
+                new THashSet<>(dSizeAbs));\r
 \r
         Set<Resource> changedTemplateElements = changedElementsByDiagram.removeValues(template);\r
 \r
@@ -625,7 +626,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
 \r
         ElementObjectAssortment assortment = new ElementObjectAssortment(graph, elementsAddedToTemplate);\r
         if (copyMap == null)\r
-            copyMap = new THashMap<Object, Object>();\r
+            copyMap = new THashMap<>();\r
         else\r
             copyMap.clear();\r
 \r
@@ -666,7 +667,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
 \r
         ModelingResources MOD = ModelingResources.getInstance(graph);\r
         Resource instanceComposite = graph.getPossibleObject(instance, MOD.DiagramToComposite);\r
-        List<Resource> instanceComponents = new ArrayList<Resource>(elementsAddedToTemplate.size());\r
+        List<Resource> instanceComponents = new ArrayList<>(elementsAddedToTemplate.size());\r
 \r
         // Post-process added elements after typicalInfo has been updated and\r
         // template mapping statements are in place.\r
@@ -872,6 +873,17 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         return changed;\r
     }\r
 \r
+    private static class Connector {\r
+        public final Resource attachmentRelation;\r
+        public final Resource connector;\r
+        public RouteLine attachedTo;\r
+\r
+        public Connector(Resource attachmentRelation, Resource connector) {\r
+            this.attachmentRelation = attachmentRelation;\r
+            this.connector = connector;\r
+        }\r
+    }\r
+\r
     /**\r
      * Synchronizes two route graph connection topologies if and only if the\r
      * destination connection is not attached to any node elements besides\r
@@ -902,19 +914,28 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
             cu = new ConnectionUtil(graph);\r
 \r
         // 0.1. find mappings between source and target connection connectors\r
-        Collection<Resource> targetConnectors = graph.getObjects(targetConnection, DIA.HasConnector);\r
-        for (Resource targetConnector : targetConnectors) {\r
+        Collection<Statement> toTargetConnectors = graph.getStatements(targetConnection, DIA.HasConnector);\r
+        Map<Resource, Connector> targetConnectors = new THashMap<>(toTargetConnectors.size());\r
+        for (Statement toTargetConnector : toTargetConnectors) {\r
+            Resource targetConnector = toTargetConnector.getObject();\r
+            targetConnectors.put(targetConnector, new Connector(toTargetConnector.getPredicate(), targetConnector));\r
             Statement toNode = cu.getConnectedComponentStatement(targetConnection, targetConnector);\r
             if (toNode == null) {\r
                 // Corrupted target connection!\r
-                ErrorLogger.defaultLogError("Encountered corrupted typical template connection " + NameUtils.getSafeName(graph, targetConnection, true) + " with a stray DIA.Connector instance " + NameUtils.getSafeName(graph, targetConnector, true), new Exception("trace"));\r
+                ErrorLogger.defaultLogError("Encountered corrupted typical template connection "\r
+                        + NameUtils.getSafeName(graph, targetConnection, true) + " with a stray DIA.Connector instance "\r
+                        + NameUtils.getSafeName(graph, targetConnector, true) + " that is not attached to any element.",\r
+                        new Exception("trace"));\r
                 return false;\r
             }\r
-\r
-            // Check that the target connections does not connect to\r
-            // non-templatized elements before syncing.\r
-            if (!graph.hasStatement(toNode.getObject(), MOD.IsTemplatized))\r
+            if (!graph.hasStatement(targetConnector, DIA.AreConnected)) {\r
+                // Corrupted target connection!\r
+                ErrorLogger.defaultLogError("Encountered corrupted typical template connection "\r
+                        + NameUtils.getSafeName(graph, targetConnection, true) + " with a stray DIA.Connector instance "\r
+                        + NameUtils.getSafeName(graph, targetConnector, true) + " that is not connected to any other route node.",\r
+                        new Exception("trace"));\r
                 return false;\r
+            }\r
 \r
             //Resource templateNode = typicalInfo.instanceToTemplate.get(toNode.getObject());\r
             Resource templateNode = graph.getPossibleObject(toNode.getObject(), MOD.HasElementSource);\r
@@ -929,7 +950,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
                             t2s.put(targetConnector, templateConnector);\r
 \r
                             if (DEBUG)\r
-                                System.out.println("Mapping connector "\r
+                                debug(typicalInfo, "Mapping connector "\r
                                         + NameUtils.getSafeName(graph, templateConnector, true)\r
                                         + " to " + NameUtils.getSafeName(graph, targetConnector, true));\r
                         }\r
@@ -941,14 +962,17 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         // 0.2. find mapping between source and target route lines\r
         Collection<Resource> sourceInteriorRouteNodes = graph.getObjects(sourceConnection, DIA.HasInteriorRouteNode);\r
         Collection<Resource> targetInteriorRouteNodes = graph.getObjects(targetConnection, DIA.HasInteriorRouteNode);\r
-        Map<Resource, Paster.RouteLine> sourceToRouteLine = new THashMap<Resource, Paster.RouteLine>();\r
-        Map<Resource, Paster.RouteLine> targetToRouteLine = new THashMap<Resource, Paster.RouteLine>();\r
+        Map<Resource, Paster.RouteLine> sourceToRouteLine = new THashMap<>();\r
+        Map<Resource, Paster.RouteLine> targetToRouteLine = new THashMap<>();\r
 \r
         for (Resource source : sourceInteriorRouteNodes)\r
             sourceToRouteLine.put(source, Paster.readRouteLine(graph, source));\r
         for (Resource target : targetInteriorRouteNodes)\r
             targetToRouteLine.put(target, Paster.readRouteLine(graph, target));\r
 \r
+        Map<Resource, Paster.RouteLine> originalSourceToRouteLine = new THashMap<>(sourceToRouteLine);\r
+        Map<Resource, Paster.RouteLine> originalTargetToRouteLine = new THashMap<>(targetToRouteLine);\r
+\r
         nextSourceLine:\r
             for (Iterator<Map.Entry<Resource, Paster.RouteLine>> sourceIt = sourceToRouteLine.entrySet().iterator(); !targetToRouteLine.isEmpty() && sourceIt.hasNext();) {\r
                 Map.Entry<Resource, Paster.RouteLine> sourceEntry = sourceIt.next();\r
@@ -962,7 +986,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
                         targetIt.remove();\r
 \r
                         if (DEBUG)\r
-                            System.out.println("Mapping routeline "\r
+                            debug(typicalInfo, "Mapping routeline "\r
                                     + NameUtils.getSafeName(graph, sourceEntry.getKey(), true)\r
                                     + " - " + sourceEntry.getValue()\r
                                     + " to " + NameUtils.getSafeName(graph, targetEntry.getKey(), true)\r
@@ -974,20 +998,40 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
             }\r
 \r
         if (DEBUG) {\r
-            System.out.println("Take 1: Source to target route nodes map : " + s2t);\r
-            System.out.println("Take 1: Target to source route nodes map : " + t2s);\r
+            debug(typicalInfo, "Take 1: Source to target route nodes map : " + s2t);\r
+            debug(typicalInfo, "Take 1: Target to source route nodes map : " + t2s);\r
         }\r
 \r
-        // 1.1 remove excess connectors\r
-        for (Resource targetConnector : targetConnectors) {\r
-            if (!t2s.containsKey(targetConnector)) {\r
-               typicalInfo.messageLog.add("\t\t\tremove excess connector from target connection: " + NameUtils.getSafeName(graph, targetConnector));\r
-                cu.removeConnectionPart(targetConnector);\r
-                changed = true;\r
+        // 1.1. Temporarily disconnect instance-specific connectors from the the connection .\r
+        //      They will be added back to the connection after the templatized parts of the\r
+        //      connection have been synchronized.\r
+\r
+        // Stores diagram connectors that are customizations in the synchronized instance.\r
+        List<Connector> instanceOnlyConnectors = null;\r
+\r
+        for (Connector connector : targetConnectors.values()) {\r
+            if (!t2s.containsKey(connector.connector)) {\r
+                typicalInfo.messageLog.add("\t\tencountered instance-specific diagram connector in target connection: " + NameUtils.getSafeName(graph, connector.connector));\r
+\r
+                // Find the RouteLine this connectors is connected to.\r
+                for (Resource rl : graph.getObjects(connector.connector, DIA.AreConnected)) {\r
+                    connector.attachedTo = originalTargetToRouteLine.get(rl);\r
+                    if (connector.attachedTo != null)\r
+                        break;\r
+                }\r
+\r
+                // Disconnect connector from connection\r
+                graph.deny(targetConnection, connector.attachmentRelation, connector.connector);\r
+                graph.deny(connector.connector, DIA.AreConnected);\r
+\r
+                // Keep track of the disconnected connector\r
+                if (instanceOnlyConnectors == null)\r
+                    instanceOnlyConnectors = new ArrayList<>(targetConnectors.size());\r
+                instanceOnlyConnectors.add(connector);\r
             }\r
         }\r
 \r
-        // 1.2 add missing connectors to target\r
+        // 1.2. add missing connectors to target\r
         Collection<Resource> sourceConnectors = graph.getObjects(sourceConnection, DIA.HasConnector);\r
         for (Resource sourceConnector : sourceConnectors) {\r
             if (!s2t.containsKey(sourceConnector)) {\r
@@ -1017,7 +1061,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
 \r
         // 2. sync route lines and their connectivity:\r
         // 2.1. assign correspondences in target for each source route line\r
-        //      by reusing excess routelines in target and by creating new\r
+        //      by reusing excess route lines in target and by creating new\r
         //      route lines.\r
 \r
         Resource[] targetRouteLines = targetToRouteLine.keySet().toArray(Resource.NONE);\r
@@ -1028,7 +1072,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
             Resource source = sourceEntry.getKey();\r
             Paster.RouteLine sourceLine = sourceEntry.getValue();\r
 \r
-            typicalInfo.messageLog.add("\t\t\tassign an instance-side routeline complement for " + NameUtils.getSafeName(graph, source, true) + " - " + sourceLine);\r
+            typicalInfo.messageLog.add("\t\t\tassign an instance-side routeline counterpart for " + NameUtils.getSafeName(graph, source, true) + " - " + sourceLine);\r
 \r
             // Assign target route line for source\r
             Resource target = null;\r
@@ -1052,16 +1096,16 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         }\r
 \r
         if (targetRouteLine >= 0) {\r
-               typicalInfo.messageLog.add("\t\t\tremove excess route lines (" + (targetRouteLine + 1) + ") from target connection");\r
+            typicalInfo.messageLog.add("\t\t\tremove excess route lines (" + (targetRouteLine + 1) + ") from target connection");\r
             for (; targetRouteLine >= 0; targetRouteLine--) {\r
-               typicalInfo.messageLog.add("\t\t\t\tremove excess route line: " + NameUtils.getSafeName(graph, targetRouteLines[targetRouteLine], true));\r
+                typicalInfo.messageLog.add("\t\t\t\tremove excess route line: " + NameUtils.getSafeName(graph, targetRouteLines[targetRouteLine], true));\r
                 cu.removeConnectionPart(targetRouteLines[targetRouteLine]);\r
             }\r
         }\r
 \r
         if (DEBUG) {\r
-            System.out.println("Take 2: Source to target route nodes map : " + s2t);\r
-            System.out.println("Take 2: Target to source route nodes map : " + t2s);\r
+            debug(typicalInfo, "Take 2: Source to target route nodes map : " + s2t);\r
+            debug(typicalInfo, "Take 2: Target to source route nodes map : " + t2s);\r
         }\r
 \r
         // 2.2. Synchronize target connection topology (DIA.AreConnected)\r
@@ -1072,9 +1116,100 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         changed |= cu.removeExtraInteriorRouteNodes(targetConnection) > 0;\r
         changed |= cu.removeUnusedConnectors(targetConnection) > 0;\r
 \r
+        // 3.1. Ensure that all mapped route nodes in the target connection\r
+        //      are tagged with MOD.IsTemplatized. Future synchronization\r
+        //      can then take advantage of this information to more easily\r
+        //      decide which parts of the connection are originated from\r
+        //      the template and which are not.\r
+        changed |= markMappedRouteNodesTemplatized(graph, s2t.values());\r
+\r
+        // 4. Add temporarily disconnected instance-specific connectors\r
+        //    back to the synchronized connection. The route line to attach\r
+        //    to is based on a simple heuristic.\r
+        if (instanceOnlyConnectors != null) {\r
+            if (originalSourceToRouteLine.isEmpty()) {\r
+                // If there are 0 route lines in the template connection,\r
+                // then one must be added to the instance connection.\r
+                // This can only happen if the template connection is\r
+                // simple, i.e. just between two terminals without any\r
+                // custom routing.\r
+\r
+                // Attach all target connection connectors to the newly created route line\r
+                Resource rl = cu.newRouteLine(targetConnection, null, null);\r
+                for (Resource sourceConnector : sourceConnectors) {\r
+                    Resource targetConnector = s2t.get(sourceConnector);\r
+                    graph.deny(targetConnector, DIA.AreConnected);\r
+                    graph.claim(targetConnector, DIA.AreConnected, DIA.AreConnected, rl);\r
+                }\r
+\r
+                // Copy orientation and position for new route line from original target route lines.\r
+                // This is a simplification that will attach any amount of route lines in the original\r
+                // target connection into just one route line. There is room for improvement here\r
+                // but it will require a more elaborate algorithm to find and cut the non-templatized\r
+                // route lines as well as connectors out of the connection before synchronizing it.\r
+                //\r
+                // TODO: This implementation chooses the added route line position at random if\r
+                //       there are multiple route lines in the target connection.\r
+                if (!originalTargetToRouteLine.isEmpty()) {\r
+                    RouteLine originalRl = originalTargetToRouteLine.values().iterator().next();\r
+                    setRouteLine(graph, rl, originalRl);\r
+                }\r
+\r
+                // Attach the instance specific connectors also to the only route line\r
+                for (Connector connector : instanceOnlyConnectors) {\r
+                    graph.claim(targetConnection, connector.attachmentRelation, connector.connector);\r
+                    graph.claim(connector.connector, DIA.AreConnected, DIA.AreConnected, rl);\r
+                }\r
+\r
+                changed = true;\r
+            } else {\r
+                for (Connector connector : instanceOnlyConnectors) {\r
+                    // Find the route line that most closely matches the original\r
+                    // route line that the connector was connected to.\r
+                    Resource closestMatch = null;\r
+                    double closestDistance = Double.MAX_VALUE;\r
+                    if (connector.attachedTo != null) {\r
+                        for (Map.Entry<Resource, Paster.RouteLine> sourceLine : originalSourceToRouteLine.entrySet()) {\r
+                            double dist = distance(sourceLine.getValue(), connector.attachedTo);\r
+                            if (dist < closestDistance) {\r
+                                closestMatch = s2t.get(sourceLine.getKey());\r
+                                closestDistance = dist;\r
+                            }\r
+                        }\r
+                    } else {\r
+                        closestMatch = originalSourceToRouteLine.keySet().iterator().next();\r
+                    }\r
+                    graph.claim(targetConnection, connector.attachmentRelation, connector.connector);\r
+                    graph.claim(connector.connector, DIA.AreConnected, DIA.AreConnected, closestMatch);\r
+                    if (closestDistance > 0)\r
+                        changed = true;\r
+                    typicalInfo.messageLog.add("\t\t\treattached instance-specific connector "\r
+                            + NameUtils.getSafeName(graph, connector.connector) + " to nearest existing route line "\r
+                            + NameUtils.getSafeName(graph, closestMatch) + " with distance " + closestDistance);\r
+                }\r
+            }\r
+        }\r
+\r
         return changed;\r
     }\r
 \r
+    private boolean markMappedRouteNodesTemplatized(WriteGraph graph, Iterable<Resource> routeNodes) throws DatabaseException {\r
+        boolean changed = false;\r
+        for (Resource rn : routeNodes) {\r
+            if (!graph.hasStatement(rn, MOD.IsTemplatized)) {\r
+                graph.claim(rn, MOD.IsTemplatized, MOD.IsTemplatized, rn);\r
+                changed = true;\r
+            }\r
+        }\r
+        return changed;\r
+    }\r
+\r
+    private static double distance(RouteLine l1, RouteLine l2) {\r
+        double dist = Math.abs(l2.getPosition() - l1.getPosition());\r
+        dist *= l2.isHorizontal() == l1.isHorizontal() ? 1 : 1000;\r
+        return dist;\r
+    }\r
+\r
     private boolean connectRouteNodes(WriteGraph graph, TypicalInfo typicalInfo, Collection<Resource> sourceRouteNodes) throws DatabaseException {\r
         boolean changed = false;\r
         for (Resource src : sourceRouteNodes) {\r
@@ -1115,6 +1250,15 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
         return changed;\r
     }\r
 \r
+    private void setRouteLine(WriteGraph graph, Resource line, double position, boolean horizontal) throws DatabaseException {\r
+        graph.claimLiteral(line, DIA.HasPosition, L0.Double, position, Bindings.DOUBLE);\r
+        graph.claimLiteral(line, DIA.IsHorizontal, L0.Boolean, horizontal, Bindings.BOOLEAN);\r
+    }\r
+\r
+    private void setRouteLine(WriteGraph graph, Resource line, RouteLine rl) throws DatabaseException {\r
+        setRouteLine(graph, line, rl.getPosition(), rl.isHorizontal());\r
+    }\r
+\r
     private void copyRouteLine(WriteGraph graph, Resource src, Resource tgt) throws DatabaseException {\r
         Double pos = graph.getPossibleRelatedValue(src, DIA.HasPosition, Bindings.DOUBLE);\r
         Boolean hor = graph.getPossibleRelatedValue(src, DIA.IsHorizontal, Bindings.BOOLEAN);\r
@@ -1143,9 +1287,16 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest {
 \r
     private static <K, V> Map<K, V> newOrClear(Map<K, V> current) {\r
         if (current == null)\r
-            return new THashMap<K, V>();\r
+            return new THashMap<>();\r
         current.clear();\r
         return current;\r
     }\r
 \r
+    private void debug(TypicalInfo typicalInfo, String message) {\r
+        if (DEBUG) {\r
+            System.out.println(message);\r
+            typicalInfo.messageLog.add(message);\r
+        }\r
+    }\r
+\r
 }
\ No newline at end of file
index de670af552057cf38a39ea5ad591b3e4b1de721e..47085403ce2aec944cdbe71845e95048990df701 100644 (file)
@@ -1,5 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>\r
 <classpath>\r
+       <classpathentry exported="true" kind="lib" path="lib/batik-awt-util-1.8.jar"/>\r
+       <classpathentry exported="true" kind="lib" path="lib/batik-util-1.8.jar"/>\r
+       <classpathentry exported="true" kind="lib" path="lib/batik-parser-1.8.jar"/>\r
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>\r
        <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
        <classpathentry kind="src" path="src"/>\r
index 80ef76d7c33ea538ef119bd990ee6cce454537fa..dad71c00d9e81a7828071e1a15633fe11f1c0f11 100644 (file)
@@ -16,7 +16,10 @@ Require-Bundle: gnu.trove3;bundle-version="3.0.0",
  org.simantics.utils;bundle-version="1.1.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ClassPath: .,
- lib/svgSalamander-tiny.jar
+ lib/svgSalamander-tiny.jar,
+ lib/batik-parser-1.8.jar,
+ lib/batik-awt-util-1.8.jar,
+ lib/batik-util-1.8.jar
 Export-Package: com.kitfox.svg,
  com.kitfox.svg.xml,
  org.simantics.scenegraph,
index 03f349f6cf2e179a37a2a574fb21aaac3a628932..3dca05bdf7393e4501afe86534e43b59dc88c1d2 100644 (file)
@@ -17,4 +17,8 @@ bin.includes = META-INF/,\
                TROVE-README-license.txt,\\r
                TROVE-LICENSE.txt,\\r
                README.txt,\\r
-               JSI-LICENSE.txt
\ No newline at end of file
+               JSI-LICENSE.txt,\\r
+               lib/batik-parser-1.8.jar,\\r
+               lib/batik-awt-util-1.8.jar,\\r
+               lib/batik-util-1.8.jar\r
+\r
diff --git a/bundles/org.simantics.scenegraph/lib/batik-awt-util-1.8.jar b/bundles/org.simantics.scenegraph/lib/batik-awt-util-1.8.jar
new file mode 100644 (file)
index 0000000..ce0be3c
Binary files /dev/null and b/bundles/org.simantics.scenegraph/lib/batik-awt-util-1.8.jar differ
diff --git a/bundles/org.simantics.scenegraph/lib/batik-parser-1.8.jar b/bundles/org.simantics.scenegraph/lib/batik-parser-1.8.jar
new file mode 100644 (file)
index 0000000..01108ad
Binary files /dev/null and b/bundles/org.simantics.scenegraph/lib/batik-parser-1.8.jar differ
diff --git a/bundles/org.simantics.scenegraph/lib/batik-util-1.8.jar b/bundles/org.simantics.scenegraph/lib/batik-util-1.8.jar
new file mode 100644 (file)
index 0000000..cb1c63f
Binary files /dev/null and b/bundles/org.simantics.scenegraph/lib/batik-util-1.8.jar differ
diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/ActionShapes.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/ActionShapes.java
new file mode 100644 (file)
index 0000000..cc44d37
--- /dev/null
@@ -0,0 +1,65 @@
+/*******************************************************************************\r
+ * Copyright (c) 2016 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     Semantum Oy - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.scenegraph.g2d.nodes.connection;\r
+\r
+import java.awt.Shape;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.PathIterator;\r
+import java.awt.geom.Rectangle2D;\r
+import java.io.IOException;\r
+import java.io.StringReader;\r
+\r
+import org.apache.batik.parser.AWTPathProducer;\r
+import org.apache.batik.parser.ParseException;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ * @since 1.22.2, 1.25.0\r
+ */\r
+class ActionShapes {\r
+\r
+       private static final String SCISSOR_PATH = "M 1.0204323,-0.337727 C 0.92746851,-0.449273 0.76034565,-0.444851 0.6356318,-0.396443 l -0.78340687,0.296247 c -0.22844697,-0.124111 -0.45371804,-0.08771 -0.45389716,-0.148477 -1.3989e-4,-0.0475 0.0435015,-0.03722 0.0366086,-0.160853 -0.006619,-0.118717 -0.1308295,-0.206188 -0.24796642,-0.198065 -0.11720479,-3.56e-4 -0.23843025,0.08983 -0.23910595,0.213676 -0.00836,0.124786 0.096897,0.240343 0.221027,0.248145 0.14544563,0.02121 0.40264226,-0.06761 0.5240569,0.148471 -0.0894972,0.166266 -0.24914468,0.167198 -0.39351418,0.159315 -0.11985922,-0.0065 -0.26369532,0.02823 -0.32050912,0.146186 -0.0549,0.113051 -2.567e-4,0.27357 0.12665686,0.307747 0.12812523,0.04659 0.30371326,-0.01328 0.33371488,-0.160538 0.0231253,-0.113504 -0.0573489,-0.166568 -0.0266378,-0.207838 0.0231733,-0.03113 0.17097889,-0.01358 0.4338543,-0.13258 l 0.85013888,0.296862 c 0.10739722,0.02964 0.23851917,0.02826 0.33326488,-0.07755 L 0.14842838,0.004094 1.0204312,-0.337731 Z m -1.7489069,-0.176336 c 0.12383244,0.06866 0.11428878,0.255942 -0.0140755,0.292584 -0.11605716,0.0408 -0.2648432,-0.0717 -0.2281757,-0.197724 0.021388,-0.103377 0.15747907,-0.141864 0.24225133,-0.09486 z m 0.007633,0.765633 c 0.12914301,0.04727 0.1078809,0.265594 -0.0232155,0.295316 -0.0869168,0.03046 -0.2114303,-0.01258 -0.2205326,-0.115113 -0.017329,-0.124578 0.12880443,-0.237615 0.24374818,-0.180208 z";\r
+\r
+       private static final String CROSS_PATH = "M 0.82205219,-1.16919 0.00195748,-0.3491 -0.81813723,-1.16919 -1.1707871,-0.81654 -0.35069244,0.00355 -1.1707871,0.82364 -0.81813723,1.17629 0.00195748,0.3562 0.82205219,1.17629 1.1747021,0.82364 0.35460739,0.00355 l 0,0 0.82009471,-0.82009 z";\r
+\r
+       static Shape parsePath(String path, AffineTransform xform) {\r
+               try {\r
+                       Shape s = AWTPathProducer.createShape(new StringReader(path), PathIterator.WIND_EVEN_ODD);\r
+                       return xform != null ? xform.createTransformedShape(s) : s;\r
+               } catch (ParseException | IOException e) {\r
+                       // Should not happen\r
+                       throw new Error(e);\r
+               }\r
+       }\r
+\r
+       static Shape transformShape(Shape shape, double scaleX, double scaleY, double offsetX, double offsetY, double rotate) {\r
+               AffineTransform tr = new AffineTransform();\r
+               tr.translate(offsetX, offsetY);\r
+               tr.scale(scaleX, scaleY);\r
+               if (rotate != 0)\r
+                       tr.rotate(rotate);\r
+               return tr.createTransformedShape(shape);\r
+       }\r
+\r
+       public static final Shape SCISSOR_SHAPE = parsePath(SCISSOR_PATH, null);\r
+       public static final Shape CROSS_SHAPE = parsePath(CROSS_PATH, null);\r
+\r
+       private static final Rectangle2D SCISSOR_BOUNDS = SCISSOR_SHAPE.getBounds2D();\r
+       private static final Rectangle2D CROSS_BOUNDS = CROSS_SHAPE.getBounds2D();\r
+\r
+       public static final double SCISSOR_WIDTH = SCISSOR_BOUNDS.getWidth();\r
+       public static final double SCISSOR_HEIGHT = SCISSOR_BOUNDS.getHeight();\r
+\r
+       public static final double CROSS_WIDTH = CROSS_BOUNDS.getWidth();\r
+       public static final double CROSS_HEIGHT = CROSS_BOUNDS.getHeight();\r
+\r
+}\r
index 04d08e3ec155242b1b6d58fad89f62adbab6e3d7..7f7bd3cd9b99f434f16c68b6a55adfcd2ab3b357 100644 (file)
@@ -13,23 +13,23 @@ package org.simantics.scenegraph.g2d.nodes.connection;
 \r
 import java.awt.AlphaComposite;\r
 import java.awt.BasicStroke;\r
+import java.awt.Color;\r
 import java.awt.Composite;\r
 import java.awt.Graphics2D;\r
+import java.awt.Shape;\r
 import java.awt.Stroke;\r
 import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Point2D;\r
 import java.awt.geom.Rectangle2D;\r
-import java.awt.image.BufferedImage;\r
-import java.io.IOException;\r
-import java.net.URL;\r
 import java.util.ArrayList;\r
 import java.util.Collection;\r
 \r
-import javax.imageio.ImageIO;\r
-\r
 import org.simantics.diagram.connection.RouteGraph;\r
 import org.simantics.diagram.connection.RouteLineHalf;\r
 import org.simantics.diagram.connection.actions.IAction;\r
 import org.simantics.diagram.connection.rendering.IRouteGraphRenderer;\r
+import org.simantics.scenegraph.utils.Quality;\r
+import org.simantics.scenegraph.utils.QualityHints;\r
 \r
 /**\r
  * @author Tuukka Lehtonen\r
@@ -67,26 +67,25 @@ public class HighlightActionPointsAction implements IAction {
         }\r
     }\r
 \r
-    static BufferedImage                cross;\r
-    static BufferedImage                cut;\r
+    private static final Shape          CROSS_SHAPE             = ActionShapes.CROSS_SHAPE;\r
+    private static final Shape          SCISSOR_SHAPE           = ActionShapes.transformShape(ActionShapes.SCISSOR_SHAPE, 1, 1, 0, 0, -Math.PI/2);\r
 \r
-    static {\r
-        cross = safeReadImage("cross.png");\r
-        cut = safeReadImage("cut.png");\r
-    }\r
+    private static final Color          CROSS_COLOR             = new Color(0xe4, 0x40, 0x61);\r
+    private static final Color          SCISSOR_COLOR           = new Color(20, 20, 20);\r
 \r
     public static final Stroke          STROKE                  = new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);\r
-    public static final AlphaComposite  COMPOSITE               = AlphaComposite.SrcOver.derive(0.6f);\r
+    public static final AlphaComposite  NO_HIT_COMPOSITE        = AlphaComposite.SrcOver.derive(0.8f);\r
+    public static final AlphaComposite  HIT_COMPOSITE           = AlphaComposite.SrcOver.derive(0.2f);\r
 \r
     public static final double          DEGENERATED_LINE_LENGTH = 1;\r
-    public static final double          CUT_DIST_FROM_END       = 0.5;\r
+    public static final double          CUT_DIST_FROM_END       = 0.75;\r
 \r
     RouteGraph                          rg;\r
 \r
     transient Collection<RouteLineHalf> lhs                     = new ArrayList<RouteLineHalf>();\r
     transient AffineTransform           transform               = new AffineTransform();\r
-    transient AffineTransform           transform2              = new AffineTransform();\r
     transient Rectangle2D               rect                    = new Rectangle2D.Double();\r
+    transient Point2D                   point                   = new Point2D.Double();\r
 \r
     public HighlightActionPointsAction(RouteGraph rg) {\r
         this.rg = rg;\r
@@ -98,94 +97,73 @@ public class HighlightActionPointsAction implements IAction {
 \r
     @Override\r
     public void render(Graphics2D g, IRouteGraphRenderer renderer, double mouseX, double mouseY) {\r
-        // Cannot perform cut or delete segment actions on connections between 2\r
-        // terminals.\r
+        // Cannot perform cut or delete segment actions\r
+        // on connections between 2 terminals.\r
         boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2);\r
         boolean branchedConnection = rg.getTerminals().size() > 2;\r
+        if (!branchedConnection || simpleConnection)\r
+            return;\r
+\r
+        AffineTransform preTr = g.getTransform();\r
+        double realViewScale = 1.0 / getScale(preTr);\r
+        //System.out.println(realViewScale);\r
+        // Don't render any of the actions if they could not be seen anyway.\r
+        if (realViewScale > 0.7)\r
+            return;\r
 \r
         lhs.clear();\r
         rg.getLineHalves(lhs);\r
 \r
-        AffineTransform preTr = g.getTransform();\r
-        double viewScale = 1.0 / getScale(preTr);\r
-        transform2.setToScale(viewScale, viewScale);\r
+        Pick pick = pickAction(rg, lhs, preTr, mouseX, mouseY);\r
+\r
         Composite originalComposite = g.getComposite();\r
-        g.setComposite(COMPOSITE);\r
+        Composite basicComposite = pick.action != null ? HIT_COMPOSITE : NO_HIT_COMPOSITE;\r
+        g.setComposite(basicComposite);\r
 \r
-        Pick pick = pickAction(rg, lhs, preTr, mouseX, mouseY);\r
+        // Always render these in high quality because otherwise the shapes\r
+        // will render with ugly artifacts when zoom level is a bit higher.\r
+        QualityHints origQualityHints = QualityHints.getQuality(g);\r
+        QualityHints.getHints(Quality.HIGH).setQuality(g);\r
 \r
+        // Render line removal markers\r
         if (!simpleConnection) {\r
-            double crossW = cross.getWidth()*viewScale*.5;\r
-            double crossH = cross.getHeight()*viewScale*.5;\r
-\r
-            // Render line removal markers\r
+            g.setPaint(CROSS_COLOR);\r
             for (RouteLineHalf lh : lhs) {\r
-//                if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH)\r
-//                    continue;\r
-//                if (!lh.getLine().isTransient())\r
-//                    continue;\r
-                if (lh.getLine().getTerminal() == null)\r
+                if (removeLocation(lh, point) == null)\r
                     continue;\r
-                double x = lh.getLink().getX();\r
-                double y = lh.getLink().getY();\r
-                if (lh.getLine().isHorizontal()) {\r
-                    x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5;\r
-                } else {\r
-                    y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5;\r
-                }\r
-\r
                 boolean hit = pick.matches(Action.REMOVE, lh);\r
-\r
                 if (hit)\r
                     g.setComposite(originalComposite);\r
-                transform.setToTranslation(x-crossW, y-crossH);\r
-                g.transform(transform);\r
-                g.drawImage(cross, transform2, null);\r
+                g.translate(point.getX(), point.getY());\r
+                g.fill(CROSS_SHAPE);\r
                 g.setTransform(preTr);\r
                 if (hit)\r
-                    g.setComposite(COMPOSITE);\r
+                    g.setComposite(basicComposite);\r
             }\r
         }\r
 \r
         // Render reconnection markers if the connection is branched.\r
         if (branchedConnection) {\r
-            double cutW = cut.getWidth()*viewScale*.5;\r
-            double cutH = cut.getHeight()*viewScale*.5;\r
-\r
-            final double dist = CUT_DIST_FROM_END;\r
+            g.setPaint(SCISSOR_COLOR);\r
             for (RouteLineHalf lh : lhs) {\r
-                if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3)\r
+                if (reconnectLocation(lh, point) == null)\r
                     continue;\r
-                double x = lh.getLink().getX();\r
-                double y = lh.getLink().getY();\r
-                if (lh.getLine().isHorizontal()) {\r
-                    if (lh.getLink() == lh.getLine().getBegin())\r
-                        x += dist*2;\r
-                    else\r
-                        x -= dist*2;\r
-                } else {\r
-                    if (lh.getLink() == lh.getLine().getBegin())\r
-                        y += dist*2;\r
-                    else\r
-                        y -= dist*2;\r
-                }\r
-\r
                 boolean hit = pick.matches(Action.RECONNECT, lh);\r
-\r
                 if (hit)\r
                     g.setComposite(originalComposite);\r
-                transform.setToTranslation(x-cutW, y-cutH);\r
-                if (!lh.getLine().isHorizontal()) {\r
-                    transform.rotate(Math.PI/2, cutW, cutH);\r
-                }\r
+                transform.setToTranslation(point.getX(), point.getY());\r
+                if (!lh.getLine().isHorizontal())\r
+                    transform.rotate(Math.PI/2);\r
+                transform.translate(0, 0.35);\r
                 g.transform(transform);\r
-                g.drawImage(cut, transform2, null);\r
+                g.fill(SCISSOR_SHAPE);\r
                 g.setTransform(preTr);\r
                 if (hit)\r
-                    g.setComposite(COMPOSITE);\r
+                    g.setComposite(basicComposite);\r
             }\r
         }\r
 \r
+        origQualityHints.setQuality(g);\r
         g.setComposite(originalComposite);\r
     }\r
 \r
@@ -205,35 +183,23 @@ public class HighlightActionPointsAction implements IAction {
         if (!branchedConnection || simpleConnection || viewTr == null)\r
             return Pick.MISS;\r
 \r
-        lhs.clear();\r
-        rg.getLineHalves(lhs);\r
+        double viewScale = 1.0 / getScale(viewTr);\r
+        if (viewScale > 0.7)\r
+            return Pick.MISS;\r
 \r
+        double nearest = Double.MAX_VALUE;\r
         RouteLineHalf selected = null;\r
         Action selectedAction = null;\r
-        double nearest = Double.MAX_VALUE;\r
-        double viewScale = 1.0 / getScale(viewTr);\r
 \r
+        // Pick line removal markers\r
         if (!simpleConnection) {\r
-            double crossW = cross.getWidth()*viewScale*.5;\r
-            double crossH = cross.getHeight()*viewScale*.5;\r
-\r
-            // Render line removal markers\r
+            double s = ActionShapes.CROSS_WIDTH * 0.25;\r
             for (RouteLineHalf lh : lhs) {\r
-//                if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH)\r
-//                    continue;\r
-//                if (!lh.getLine().isTransient())\r
-//                    continue;\r
-                if (lh.getLine().getTerminal() == null)\r
+                if (removeLocation(lh, point) == null)\r
                     continue;\r
-                double x = lh.getLink().getX();\r
-                double y = lh.getLink().getY();\r
-                if (lh.getLine().isHorizontal()) {\r
-                    x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5;\r
-                } else {\r
-                    y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5;\r
-                }\r
-\r
-                rect.setFrameFromCenter(x, y, x-crossW, y-crossH);\r
+                double x = point.getX();\r
+                double y = point.getY();\r
+                rect.setFrameFromCenter(x, y, x-s, y-s);\r
                 boolean hit = rect.contains(mouseX, mouseY);\r
                 if (hit) {\r
                     double distSq = distSq(x, y, mouseX, mouseY);\r
@@ -246,35 +212,21 @@ public class HighlightActionPointsAction implements IAction {
             }\r
         }\r
 \r
-        // Render reconnection markers if the connection is branched.\r
+        // Pick reconnection markers if the connection is branched.\r
         if (branchedConnection) {\r
-            double cutW = cut.getWidth()*viewScale*.5;\r
-            double cutH = cut.getHeight()*viewScale*.5;\r
-\r
-            final double dist = CUT_DIST_FROM_END;\r
+            double w = ActionShapes.SCISSOR_HEIGHT * 0.4;\r
+            double h = ActionShapes.SCISSOR_WIDTH * 0.3;\r
             for (RouteLineHalf lh : lhs) {\r
-                if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3)\r
+                if (reconnectLocation(lh, point) == null)\r
                     continue;\r
-                double x = lh.getLink().getX();\r
-                double y = lh.getLink().getY();\r
-                if (lh.getLine().isHorizontal()) {\r
-                    if (lh.getLink() == lh.getLine().getBegin())\r
-                        x += dist*2;\r
-                    else\r
-                        x -= dist*2;\r
-                } else {\r
-                    if (lh.getLink() == lh.getLine().getBegin())\r
-                        y += dist*2;\r
-                    else\r
-                        y -= dist*2;\r
-                }\r
-\r
-                rect.setFrameFromCenter(x, y, x-cutW, y-cutH);\r
+                double x = point.getX();\r
+                double y = point.getY();\r
+                rect.setFrameFromCenter(x, y, x-w, y-h);\r
                 boolean hit = rect.contains(mouseX, mouseY);\r
                 if (hit) {\r
                     double distSq = distSq(x, y, mouseX, mouseY);\r
                     if (distSq < nearest) {\r
-                        nearest = dist;\r
+                        nearest = distSq;\r
                         selected = lh;\r
                         selectedAction = Action.RECONNECT;\r
                     }\r
@@ -285,6 +237,43 @@ public class HighlightActionPointsAction implements IAction {
         return selected == null ? Pick.MISS : new Pick(selectedAction, selected);\r
     }\r
 \r
+    private static Point2D removeLocation(RouteLineHalf lh, Point2D p) {\r
+        if (lh.getLine().getTerminal() == null)\r
+            return null;\r
+\r
+        double x = lh.getLink().getX();\r
+        double y = lh.getLink().getY();\r
+        if (lh.getLine().isHorizontal()) {\r
+            x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5;\r
+        } else {\r
+            y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5;\r
+        }\r
+        p.setLocation(x, y);\r
+        return p;\r
+    }\r
+\r
+    private static Point2D reconnectLocation(RouteLineHalf lh, Point2D p) {\r
+        if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3)\r
+            return null;\r
+\r
+        final double dist = CUT_DIST_FROM_END;\r
+        double x = lh.getLink().getX();\r
+        double y = lh.getLink().getY();\r
+        if (lh.getLine().isHorizontal()) {\r
+            if (lh.getLink() == lh.getLine().getBegin())\r
+                x += dist*2;\r
+            else\r
+                x -= dist*2;\r
+        } else {\r
+            if (lh.getLink() == lh.getLine().getBegin())\r
+                y += dist*2;\r
+            else\r
+                y -= dist*2;\r
+        }\r
+        p.setLocation(x, y);\r
+        return p;\r
+    }\r
+\r
     private static double distSq(double x1, double y1, double x2, double y2) {\r
         double dx = x2 - x1;\r
         double dy = y2 - y1;\r
@@ -301,13 +290,4 @@ public class HighlightActionPointsAction implements IAction {
         return Math.sqrt(Math.abs(m00*m11 - m10*m01));\r
     }\r
 \r
-    private static BufferedImage safeReadImage(String name) {\r
-        try {\r
-            URL url = HighlightActionPointsAction.class.getResource(name);\r
-            return ImageIO.read(url);\r
-        } catch (IOException e) {\r
-            return null;\r
-        }\r
-    }\r
-\r
 }\r
index 34b1a635d766070867e0a3d2b3170305d0387e5f..e231476acfb00ead8f00699ca7f967e8f372ab25 100644 (file)
@@ -11,8 +11,6 @@
  *******************************************************************************/\r
 package org.simantics.scenegraph.g2d.nodes.connection;\r
 \r
-import gnu.trove.map.hash.THashMap;\r
-\r
 import java.awt.BasicStroke;\r
 import java.awt.Color;\r
 import java.awt.Graphics2D;\r
@@ -31,7 +29,6 @@ import java.util.Map;
 import org.simantics.diagram.connection.RouteGraph;\r
 import org.simantics.diagram.connection.RouteLine;\r
 import org.simantics.diagram.connection.RouteLink;\r
-import org.simantics.diagram.connection.RoutePoint;\r
 import org.simantics.diagram.connection.RouteTerminal;\r
 import org.simantics.diagram.connection.actions.IAction;\r
 import org.simantics.diagram.connection.actions.IReconnectAction;\r
@@ -69,6 +66,8 @@ import org.simantics.scenegraph.utils.GeometryUtils;
 import org.simantics.scenegraph.utils.InitValueSupport;\r
 import org.simantics.scenegraph.utils.NodeUtil;\r
 \r
+import gnu.trove.map.hash.THashMap;\r
+\r
 /**\r
  * @author Tuukka Lehtonen\r
  */\r
@@ -312,6 +311,10 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
         }\r
     }\r
 \r
+    public void showBranchPoint(Point2D p) {\r
+        newBranchPointPosition = p;\r
+    }\r
+\r
     @Override\r
     public void init() {\r
         super.init();\r
index e13c18563dc9fe67e3446f6e65c1836f83ade973..caf212a61283ec225f46a5a803a941c3fd6286fc 100644 (file)
@@ -61,6 +61,16 @@ public class JavaMathOperation extends FunctionValue {
     public static final JavaMathOperation SOR = new JavaMathOperation(Opcodes.IOR, Types.SHORT, Types.SHORT, Types.SHORT);
     public static final JavaMathOperation SXOR = new JavaMathOperation(Opcodes.IXOR, Types.SHORT, Types.SHORT, Types.SHORT);
     
+    public static final JavaMathOperation BADD = new JavaMathOperation(Opcodes.IADD, Types.BYTE, Types.BYTE, Types.BYTE);
+    public static final JavaMathOperation BSUB = new JavaMathOperation(Opcodes.ISUB, Types.BYTE, Types.BYTE, Types.BYTE);
+    public static final JavaMathOperation BMUL = new JavaMathOperation(Opcodes.IMUL, Types.BYTE, Types.BYTE, Types.BYTE);
+    public static final JavaMathOperation BDIV = new JavaMathOperation(Opcodes.IDIV, Types.BYTE, Types.BYTE, Types.BYTE);
+    public static final JavaMathOperation BREM = new JavaMathOperation(Opcodes.IREM, Types.BYTE, Types.BYTE, Types.BYTE);
+    public static final JavaMathOperation BNEG = new JavaMathOperation(Opcodes.INEG, Types.BYTE, Types.BYTE);
+    public static final JavaMathOperation BAND = new JavaMathOperation(Opcodes.IAND, Types.BYTE, Types.BYTE, Types.BYTE);
+    public static final JavaMathOperation BOR = new JavaMathOperation(Opcodes.IOR, Types.BYTE, Types.BYTE, Types.BYTE);
+    public static final JavaMathOperation BXOR = new JavaMathOperation(Opcodes.IXOR, Types.BYTE, Types.BYTE, Types.BYTE);
+
     public static final JavaMathOperation CADD = new JavaMathOperation(Opcodes.IADD, Types.CHARACTER, Types.CHARACTER, Types.INTEGER);
     public static final JavaMathOperation CSUB = new JavaMathOperation(Opcodes.ISUB, Types.INTEGER, Types.CHARACTER, Types.CHARACTER);
     
index 39c2dbec6ce87f2187eee6fabbfa70f24457c74d..cb39346e4a730483b2948e304c803d4805b9af20 100755 (executable)
@@ -56,6 +56,16 @@ public class JavaModule extends ConcreteModule {
         addValue("sor", JavaMathOperation.SOR);
         addValue("sxor", JavaMathOperation.SXOR);
         
+        addValue("badd", JavaMathOperation.BADD);
+        addValue("bsub", JavaMathOperation.BSUB);
+        addValue("bmul", JavaMathOperation.BMUL);
+        addValue("bdiv", JavaMathOperation.BDIV);
+        addValue("brem", JavaMathOperation.BREM);
+        addValue("bneg", JavaMathOperation.BNEG);
+        addValue("band", JavaMathOperation.BAND);
+        addValue("bor", JavaMathOperation.BOR);
+        addValue("bxor", JavaMathOperation.BXOR);
+        
         // Conversions
         for(JavaConversionOperation operation : JavaConversionOperation.OPCODES)
             addValue(operation.getMnemonic(), operation);
@@ -75,6 +85,13 @@ public class JavaModule extends ConcreteModule {
         addValue("lcmpgt", new JavaComparisonOperation(">", Types.LONG));
         addValue("lcmpge", new JavaComparisonOperation(">=", Types.LONG));     
         
+        addValue("bcmpeq", new JavaComparisonOperation("==", Types.BYTE));
+        addValue("bcmpne", new JavaComparisonOperation("!=", Types.BYTE));
+        addValue("bcmplt", new JavaComparisonOperation("<", Types.BYTE));
+        addValue("bcmple", new JavaComparisonOperation("<=", Types.BYTE));
+        addValue("bcmpgt", new JavaComparisonOperation(">", Types.BYTE));
+        addValue("bcmpge", new JavaComparisonOperation(">=", Types.BYTE));
+        
         addValue("scmpeq", new JavaComparisonOperation("==", Types.SHORT));
         addValue("scmpne", new JavaComparisonOperation("!=", Types.SHORT));
         addValue("scmplt", new JavaComparisonOperation("<", Types.SHORT));
@@ -112,7 +129,6 @@ public class JavaModule extends ConcreteModule {
         addValue("ifge", new JavaComparisonToZeroOperation(">="));
         
         TVar A = Types.var(Kinds.STAR);
-        TVar B = Types.var(Kinds.STAR);
         
         addValue("unsafeCoerce", UnsafeCoerce.INSTANCE);
         addValue("equals", new JavaMethod(true, 
index ea0276e354008fcbd1d32cace12feee41f57ee4a..3b7ef9d1c3d61c2dbc3d1394e976d8845a4eb10a 100644 (file)
@@ -98,8 +98,8 @@ public class ReduceSerializable {
     \r
     private static final THashMap<TCon,Constant> BINDING_CONSTANTS2 = new THashMap<TCon,Constant>();\r
     static {\r
-        BINDING_CONSTANTS2.put(MAP, new JavaConstructor("org/simantics/databoard/binding/impl/HashMapBinding", Types.NO_EFFECTS, Types.pred(Types.SERIALIZABLE, Types.apply(MAP, A, B)), Types.pred(Types.SERIALIZABLE, A), Types.pred(Types.SERIALIZABLE, B)));\r
-        BINDING_CONSTANTS2.put(MMAP, new JavaConstructor("org/simantics/databoard/binding/impl/HashMapBinding", Types.NO_EFFECTS, Types.pred(Types.SERIALIZABLE, Types.apply(MMAP, A, B)), Types.pred(Types.SERIALIZABLE, A), Types.pred(Types.SERIALIZABLE, B)));\r
+        BINDING_CONSTANTS2.put(MAP, new JavaConstructor("org/simantics/databoard/binding/impl/DefaultMapBinding", Types.NO_EFFECTS, Types.pred(Types.SERIALIZABLE, Types.apply(MAP, A, B)), Types.pred(Types.SERIALIZABLE, A), Types.pred(Types.SERIALIZABLE, B)));\r
+        BINDING_CONSTANTS2.put(MMAP, new JavaConstructor("org/simantics/databoard/binding/impl/DefaultMapBinding", Types.NO_EFFECTS, Types.pred(Types.SERIALIZABLE, Types.apply(MMAP, A, B)), Types.pred(Types.SERIALIZABLE, A), Types.pred(Types.SERIALIZABLE, B)));\r
     }\r
         \r
     public static Reduction reduceSerializable(Type parameter) {\r
index 02396067875b83abb5c4fc25e44b4841bb7e47e6..74bc4220436dbe2d7a991012d9385a8eab08e136 100644 (file)
@@ -11,31 +11,6 @@ effect WriteGraph
     "graph"\r
     "org.simantics.db.WriteGraph"\r
     \r
-importJava "org.simantics.databoard.type.Datatype" where\r
-    data Datatype\r
-    @JavaName toString\r
-    showDatatype :: Datatype -> String\r
-\r
-instance Show Datatype where\r
-    show = showDatatype\r
-\r
-importJava "org.simantics.databoard.Bindings" where\r
-    @JavaName getBinding    \r
-    datatypeBinding :: Datatype -> Binding Dynamic\r
-\r
-importJava "org.simantics.databoard.binding.mutable.Variant" where\r
-    @JavaName "<init>"\r
-    createVariant_ :: Binding Dynamic -> Dynamic -> Variant\r
-    @JavaName "type"\r
-    variantDatatype :: Variant -> Datatype\r
-\r
-createVariant :: Datatype -> Dynamic -> Variant\r
-createVariant dt v = createVariant_ (datatypeBinding dt) v\r
-\r
-importJava "org.simantics.databoard.Datatypes" where\r
-    @JavaName translate\r
-    translateDatatype :: String -> Datatype\r
-\r
 importJava "org.simantics.db.Resource" where\r
     "A resource is a node in a semantic graph."\r
     data Resource\r
diff --git a/bundles/org.simantics.scl.runtime/scl/Databoard.scl b/bundles/org.simantics.scl.runtime/scl/Databoard.scl
new file mode 100644 (file)
index 0000000..f813766
--- /dev/null
@@ -0,0 +1,279 @@
+import "Prelude"\r
+import "Random"\r
+\r
+/// Datatype ///\r
+\r
+"A data type component with component name and data type"\r
+@JavaType "org.simantics.databoard.type.Component"\r
+@FieldNames [name, "type"]\r
+data DatatypeComponent = DatatypeComponent String Datatype\r
+\r
+"""A data type that represents the data types supported by the Simantics\r
+Databoard plugin."""\r
+@JavaType "org.simantics.databoard.type.Datatype"\r
+data Datatype =\r
+    @JavaType "org.simantics.databoard.type.BooleanType"\r
+    BooleanType\r
+  | @JavaType "org.simantics.databoard.type.ByteType"\r
+    ByteType\r
+  | @JavaType "org.simantics.databoard.type.IntegerType"\r
+    IntegerType\r
+  | @JavaType "org.simantics.databoard.type.LongType"\r
+    LongType\r
+  | @JavaType "org.simantics.databoard.type.FloatType"\r
+    FloatType\r
+  | @JavaType "org.simantics.databoard.type.DoubleType"\r
+    DoubleType\r
+  | @JavaType "org.simantics.databoard.type.StringType"\r
+    StringType\r
+  | @JavaType "org.simantics.databoard.type.ArrayType"\r
+    @FieldNames [componentType]\r
+    ArrayType Datatype\r
+  | @JavaType "org.simantics.databoard.type.OptionalType"\r
+    @FieldNames [componentType]\r
+    OptionalType Datatype\r
+  | @JavaType "org.simantics.databoard.type.MapType"\r
+    @FieldNames [keyType, valueType]\r
+    MapType Datatype Datatype\r
+  | @JavaType "org.simantics.databoard.type.RecordType"\r
+    @FieldNames [components]\r
+    RecordType (Vector DatatypeComponent)\r
+  | @JavaType "org.simantics.databoard.type.UntionType"\r
+    @FieldNames [components]\r
+    UnionType (Vector DatatypeComponent)\r
+  | @JavaType "org.simantics.databoard.type.VariantType"\r
+    VariantType\r
+\r
+importJava "org.simantics.databoard.type.Datatype" where\r
+    @private\r
+    @JavaName toString\r
+    showDatatype :: Datatype -> String\r
+    \r
+    "Get the number of type components in an data type"\r
+    @JavaName getComponentCount\r
+    datatypeCompnentCount :: Datatype -> Integer\r
+\r
+    "Get a component type of a composite data type"\r
+    @JavaName getComponentType\r
+    datatypeComponentType :: Datatype -> ChildReference -> Datatype\r
+    \r
+    @private\r
+    @JavaName equals\r
+    datatypeEquals :: Datatype -> Datatype -> Boolean \r
+\r
+instance Show Datatype where\r
+    show = showDatatype\r
+\r
+instance Eq Datatype where\r
+    (==) = datatypeEquals\r
+\r
+/// Binding ///\r
+\r
+importJava "org.simantics.databoard.binding.Binding" where\r
+    "Check whether a dynamic object is an instance of a given binding"\r
+    @JavaName isInstance\r
+    isBindingInstance :: Binding Dynamic -> Dynamic -> Boolean\r
+\r
+    "Create a serializable object from a textual representation"\r
+    parseValueDefinition :: Serializable a => String -> a\r
+    \r
+    "Compare two serializable objects\n\nResult is -1, 0 or 1 depending the partial ordering of the objects."\r
+    @JavaName compare\r
+    compareObjects :: Serializable a => a -> a -> Integer\r
+\r
+    "Return true, if two serializable values are equal"    \r
+    @JavaName equals\r
+    serializableEq :: Serializable a => a -> a -> Boolean\r
+    \r
+    "The default value of a serializable type"\r
+    @JavaName createDefault\r
+    serializableDefaultValue :: Serializable a => a\r
+    \r
+    "Create a random value of a serializable type"\r
+    @JavaName createRandom\r
+    serializableRandomValue :: Serializable a => <Random> a\r
+    \r
+    "Get a textual representation of a serializable value"\r
+    @JavaName toString\r
+    showSerializable :: Serializable a => a -> String\r
+    \r
+    @private\r
+    @JavaName getComponent \r
+    getSerializableComponent_ :: Serializable a => a -> ChildReference -> Binding b -> b \r
+\r
+    "Get a component binding"\r
+    @JavaName getComponentBinding\r
+    getComponentBinding :: Binding a -> ChildReference -> Binding b\r
+    \r
+    @private\r
+    @JavaName equals\r
+    bindingEquals :: Binding a -> Binding a -> Boolean\r
+    \r
+instance Eq (Binding a) where\r
+   (==) = bindingEquals\r
+\r
+"Get a child data component of a composite serializable value"\r
+getSerializableComponent :: Serializable a => Serializable b => a -> ChildReference -> b\r
+getSerializableComponent object ref = getSerializableComponent_ object ref binding\r
+\r
+/// Serializer ///\r
+\r
+importJava "org.simantics.databoard.serialization.Serializer" where\r
+    "A data serializer for SCL type a" \r
+    data Serializer a\r
+\r
+    @private\r
+    @JavaName "serialize"    \r
+    serialize_ :: Serializer a -> a -> ByteArray\r
+    \r
+    @private\r
+    @JavaName "deserialize"\r
+    deserialize_ :: Serializer a -> ByteArray -> a\r
+\r
+importJava "org.simantics.databoard.Bindings" where\r
+    @private\r
+    @JavaName "getSerializer"\r
+    serializerOf :: Binding a -> Serializer a\r
+    \r
+    @private\r
+    @JavaName toString\r
+    bindingToString :: Binding a -> String\r
+\r
+    "Adapt between types using explicitly provided binding objects: `adapt_ value from to`"\r
+    @JavaName adapt\r
+    adapt_ :: a -> Binding a -> Binding b -> b\r
+    \r
+"Adapt value from one serializable type to another"\r
+adapt :: Serializable a => Serializable b => a -> b\r
+adapt x = adapt_ x binding binding\r
+    \r
+instance Show (Binding a) where\r
+    show = bindingToString\r
+\r
+"Serializes a value to a byte array using default serializer."\r
+serialize :: Serializable a => a -> ByteArray\r
+serialize v = serialize_ (serializerOf binding) v\r
+\r
+"Deserializes a value from a byte array using default serializer."\r
+deserialize :: Serializable a => ByteArray -> a\r
+deserialize ba = deserialize_ (serializerOf binding) ba\r
+\r
+importJava "org.simantics.databoard.Bindings" where\r
+    "Get a default binding for a given data type" \r
+    @JavaName getBinding    \r
+    datatypeBinding :: Datatype -> Binding Dynamic\r
+\r
+importJava "org.simantics.databoard.Datatypes" where\r
+    "Get a data type from a string representation"\r
+    @JavaName translate\r
+    translateDatatype :: String -> Datatype\r
+\r
+importJava "org.simantics.databoard.binding.mutable.Variant" where\r
+    // data Variant (in Builtins)\r
+    "Create a variant using an explicitly provided binding value (unchecked cast)"\r
+    @JavaName "<init>"\r
+    createVariant_ :: Binding Dynamic -> Dynamic -> Variant\r
+    \r
+    "Get the data type of a variant object"\r
+    @JavaName "type"\r
+    variantDatatype :: Variant -> Datatype\r
+    \r
+    "Get raw value contained by a variant (unchecked cast)"\r
+    @JavaName getValue\r
+    rawVariantValue :: Variant -> a\r
+    \r
+    "Create a variant from a raw object (based on Java class)"\r
+    @JavaName ofInstance\r
+    variantOf :: a -> Variant\r
+    \r
+    "Create a variant with explicitly provided binding and value"\r
+    @JavaName "<init>"\r
+    variant_ :: Binding a -> a -> Variant\r
+    \r
+    "Get value from a variant using a given binding"\r
+    @JavaName getValue\r
+    variantValue_ :: Variant -> Binding a -> a\r
+    \r
+    @private\r
+    @JavaName toString\r
+    showVariant :: Variant -> String\r
+    \r
+    "Get a component of compound data value in a variant"\r
+    @JavaName getComponent\r
+    variantComponent :: Variant -> ChildReference -> Variant\r
+\r
+"Create a variant of a given data type from an object in the default binding (unchecked, use with extreme caution)"\r
+createVariant :: Datatype -> Dynamic -> Variant\r
+createVariant dt v = createVariant_ (datatypeBinding dt) v\r
+\r
+"Create a variant from a serializable value"\r
+variant :: Serializable a => a -> Variant\r
+variant v = variant_ binding v\r
+\r
+"Get the value of a variant in a serializable type"\r
+variantValue :: Serializable a => Variant -> a\r
+variantValue v = variantValue_ v binding\r
+\r
+instance Show Variant where\r
+    show = showVariant\r
+\r
+"Get an element of a compound variant value using an index reference" \r
+variantElement :: Serializable a => Variant -> Integer -> a\r
+variantElement v i = variantValue (variantComponent v (indexReference i))\r
+\r
+importJava "org.simantics.databoard.accessor.reference.ChildReference" where\r
+    "A reference to a child element in a composite data type/binding or value"\r
+    data ChildReference\r
+\r
+    "Combine a list of child data object references into a single path reference"\r
+    @JavaName compile    \r
+    compileReference :: [ChildReference] -> ChildReference\r
+\r
+importJava "org.simantics.databoard.accessor.reference.IndexReference" where\r
+    """Get a reference to a child data object using an index (zero-based)\r
+* Element index of an array object\r
+* Field index of a record or union type\r
+* 0:\r
+  * Key component of a map type/binding\r
+  * Component of any single-component type/binding (optional, array)\r
+  * Contained value/type of any single-element object (optional, union, variant)\r
+* 1:\r
+  * Value component of a map type/binding\r
+    """\r
+    @JavaName "<init>"\r
+    indexReference :: Integer -> ChildReference\r
+\r
+importJava "org.simantics.databoard.accessor.reference.KeyReference" where\r
+    """Get a reference to a MapType child data object using a given key value\r
+* Contained value of a map object for a given key value\r
+    """\r
+    @JavaName "<init>"\r
+    keyReference :: Variant -> ChildReference\r
+\r
+importJava "org.simantics.databoard.accessor.reference.NameReference" where\r
+    """Get a reference to a child data object using a field name\r
+* A component name of a record or union data type/binding\r
+* "key": The key component of a map data type/binding\r
+* "value": The value component of a map data type/binding\r
+    """\r
+    @JavaName "<init>"\r
+    nameReference :: String -> ChildReference\r
+    \r
+importJava "org.simantics.databoard.accessor.reference.LabelReference" where\r
+    """Get a reference to a child data object using a label\r
+* A component name of a record or union data type/binding\r
+* A string representation of the index of a record or union data type/binding component\r
+* "v": The component type of an array/optional data type/binding\r
+* "0"/"key": The key component of a map data type/binding\r
+* "1"/"value": The value component of a map data type/binding\r
+    """\r
+    @JavaName "<init>"\r
+    labelReference :: String -> ChildReference\r
+\r
+importJava "org.simantics.databoard.accessor.reference.ComponentReference" where\r
+    """Get a reference to a component child data object\r
+* Component of an array/optional data type/binding\r
+* Contained value of an optional/variant/union object\r
+    """\r
+    @JavaName "<init>"\r
+    componentReference :: ChildReference\r
index 4c20c99b52dfe03528542ab582934a9fe7185ec3..6966b4489d0652c61b8cde57fc7d185b75a2dd08 100644 (file)
@@ -558,6 +558,43 @@ importJava "java.lang.Math" where
 
 /// Integer ///
 
+@private
+importJava "java.lang.Byte" where
+    @JavaName toString
+    showByte :: Byte -> String
+    
+    @JavaName parseByte
+    readByte :: String -> Byte
+
+instance Eq Byte where
+    (==) = Java.bcmpeq
+    (!=) = Java.bcmpne
+
+instance Ord Byte where
+    (<) = Java.bcmplt
+    (<=) = Java.bcmple
+    (>) = Java.bcmpgt
+    (>=) = Java.bcmpge
+    
+instance Additive Byte where
+    zero = Java.i2b Java.iconst_0
+    (+) = Java.badd
+    
+instance Ring Byte where
+    neg = Java.bneg
+    (-) = Java.bsub
+    one = Java.i2b Java.iconst_1
+    (*) = Java.bmul
+    fromInteger = Java.i2b
+
+instance Show Byte where
+    show = showByte
+    precedence v = if v >= 0 then 0 else 100
+
+instance Read Byte where
+    read = readByte
+
+
 @private
 importJava "java.lang.Short" where
     @JavaName toString
@@ -2229,45 +2266,7 @@ instance Show TypeRep where
         isSpecialType (TCon "Builtin" "(,,,)") = True
         isSpecialType (TApply a _) = isSpecialType a
 */
-// Serializable
-
-importJava "org.simantics.databoard.serialization.Serializer" where
-    data Serializer a
-
-    @private
-    @JavaName "serialize"    
-    serialize_ :: Serializer a -> a -> ByteArray
-    
-    @private
-    @JavaName "deserialize"
-    deserialize_ :: Serializer a -> ByteArray -> a
-
-importJava "org.simantics.databoard.Bindings" where
-    @private
-    @JavaName "getSerializer"
-    serializerOf :: Binding a -> Serializer a
-    
-    @private
-    @JavaName toString
-    bindingToString :: Binding a -> String
-    
-    @JavaName adapt
-    adapt_ :: a -> Binding a -> Binding b -> b
-    
-adapt :: Serializable a => Serializable b => a -> b
-adapt x = adapt_ x binding binding
-    
-instance Show (Binding a) where
-    show = bindingToString
-
-"Serializes a value to a byte array."
-serialize :: Serializable a => a -> ByteArray
-serialize v = serialize_ (serializerOf binding) v
 
-"Deserializes a value from a byte array."
-deserialize :: Serializable a => ByteArray -> a
-deserialize ba = deserialize_ (serializerOf binding) ba
-    
 // ByteArray
 
 importJava "java.util.Arrays" where
@@ -2278,56 +2277,6 @@ importJava "java.util.Arrays" where
 instance Show ByteArray where
     show = byteArrayToString
 
-importJava "org.simantics.databoard.binding.mutable.Variant" where
-    // data Variant (in Builtins)
-    @JavaName getValue
-    rawVariantValue :: Variant -> a
-    @JavaName ofInstance
-    variantOf :: a -> Variant\r
-    @JavaName "<init>"
-    variantOfWithBinding :: Binding a -> a -> Variant\r
-    @JavaName getValue
-    variantValue_ :: Variant -> Binding a -> a
-    @JavaName toString
-    showVariant :: Variant -> String
-    
-    @JavaName getComponent
-    variantComponent :: Variant -> ChildReference -> Variant
-
-variant :: Serializable a => a -> Variant
-variant v = variantOfWithBinding binding v
-
-variantValue :: Serializable a => Variant -> a
-variantValue v = variantValue_ v binding
-
-instance Show Variant where
-    show = showVariant
-
-variantElement :: Serializable a => Variant -> Integer -> a
-variantElement v i = variantValue (variantComponent v (indexReference i))
-
-importJava "org.simantics.databoard.accessor.reference.ChildReference" where
-    data ChildReference
-
-    @JavaName compile    
-    compileReference :: [ChildReference] -> ChildReference
-
-importJava "org.simantics.databoard.accessor.reference.IndexReference" where
-    @JavaName "<init>"
-    indexReference :: Integer -> ChildReference
-
-importJava "org.simantics.databoard.accessor.reference.KeyReference" where
-    @JavaName "<init>"
-    keyReference :: Variant -> ChildReference
-
-importJava "org.simantics.databoard.accessor.reference.NameReference" where
-    @JavaName "<init>"
-    nameReference :: String -> ChildReference
-    
-importJava "org.simantics.databoard.accessor.reference.LabelReference" where
-    @JavaName "<init>"
-    labelReference :: String -> ChildReference
-    
 // Type
 
 @private
index 76ecece9c5b3e59ce39c63d766d16b0836bcccb2..122fcd02b99dc8e943f72c08776c955890e45454 100644 (file)
@@ -4,6 +4,7 @@ include "BigInteger"
 include "ArrayList" as ArrayList
 include "String" as String
 include "Vector"
+include "Databoard"
 include "Debug" as Debug
 include "Lazy" as Lazy
 include "File" as File
index a45edf0eef1c1e2f2fa2a28ec1a5449f76c71530..c79602c1bde88010b6a9f5706bab6e1425aac46c 100644 (file)
@@ -199,6 +199,8 @@ public class StandardModelingRules extends AbstractModelingRules {
                boolean legal = true;\r
                for (Resource constraint : g.getObjects(connectionType, STR.HasConnectionConstraint)) {\r
                        IConnectionConstraint cc = g.adapt(constraint, IConnectionConstraint.class);\r
+                       if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+                               System.out.println("Checking " + cc.getClass().getSimpleName());\r
                        switch(cc.isLegal(g, terminals)) {\r
                        case ILLEGAL:\r
                                if(Policy.DEBUG_STANDARD_MODELING_RULES)\r