From: Jani Simomaa Date: Mon, 17 Oct 2016 07:41:11 +0000 (+0300) Subject: Merge "InputStream returns -1 on EOF instead of throwing IOException" X-Git-Tag: v1.25.0~68 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=80d69fc3f7a2e14c5b9e44a601ba15b0434454a8;hp=fc38c8c23e78b366b534e7230b67d0dd683cba66 Merge "InputStream returns -1 on EOF instead of throwing IOException" --- 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 index 000000000..e9cd02b02 Binary files /dev/null and b/bundles/org.simantics.browsing.ui.nattable/images/transparent.png differ diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GENatTableThemeConfiguration.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GENatTableThemeConfiguration.java index bcb8bba53..41d5f2e46 100644 --- a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GENatTableThemeConfiguration.java +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GENatTableThemeConfiguration.java @@ -1,13 +1,19 @@ package org.simantics.browsing.ui.nattable; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.nebula.widgets.nattable.painter.cell.BackgroundPainter; import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter; import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.PaddingDecorator; import org.eclipse.nebula.widgets.nattable.style.theme.ModernNatTableThemeConfiguration; +import org.eclipse.nebula.widgets.nattable.tree.painter.IndentedTreeImagePainter; +import org.eclipse.nebula.widgets.nattable.tree.painter.TreeImagePainter; +import org.eclipse.nebula.widgets.nattable.ui.util.CellEdgeEnum; import org.eclipse.nebula.widgets.nattable.util.GUIHelper; public class GENatTableThemeConfiguration extends ModernNatTableThemeConfiguration{ - public GENatTableThemeConfiguration(GETreeData treeData) { + public GENatTableThemeConfiguration(GETreeData treeData, int style) { super(); this.oddRowBgColor = GUIHelper.getColor(250, 250, 250); this.defaultCellPainter = @@ -20,6 +26,55 @@ public class GENatTableThemeConfiguration extends ModernNatTableThemeConfigurati 0, 5, false))); + + TreeImagePainter treeImagePainter = + new TreeImagePainter( + false, + GUIHelper.getImage("right"), //$NON-NLS-1$ + GUIHelper.getImage("right_down"), //$NON-NLS-1$ + GUIHelper.getImageByURL("transparent", + FileLocator.find(Activator.getDefault().getBundle(), + new Path("images/transparent.png"), null))); //$NON-NLS-1$ + this.treeStructurePainter = + new BackgroundPainter( + new PaddingDecorator( + new IndentedTreeImagePainter( + 10, + null, + CellEdgeEnum.LEFT, + treeImagePainter, + false, + 2, + true), + 0, + 5, + 0, + 5, + false)); + TreeImagePainter treeSelectionImagePainter = + new TreeImagePainter( + false, + GUIHelper.getImage("right_inv"), //$NON-NLS-1$ + GUIHelper.getImage("right_down_inv"), //$NON-NLS-1$ + GUIHelper.getImageByURL("transparent", + FileLocator.find(Activator.getDefault().getBundle(), + new Path("images/transparent.png"), null))); //$NON-NLS-1$ + this.treeStructureSelectionPainter = + new BackgroundPainter( + new PaddingDecorator( + new IndentedTreeImagePainter( + 10, + null, + CellEdgeEnum.LEFT, + treeSelectionImagePainter, + false, + 2, + true), + 0, + 5, + 0, + 5, + false)); } } diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeLayer.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeLayer.java index dbc30050a..309e4daa8 100644 --- a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeLayer.java +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeLayer.java @@ -1,9 +1,9 @@ package org.simantics.browsing.ui.nattable; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -31,7 +31,7 @@ import it.unimi.dsi.fastutil.ints.IntRBTreeSet; public class GETreeLayer extends TreeLayer2 { //Set collapsed = new HashSet(); - Set collapsed = new IdentityHashSet(); + Set expanded = new IdentityHashSet(); GETreeData treeData; Comparator comparator = new FirstElementComparator(); @@ -51,7 +51,7 @@ public class GETreeLayer extends TreeLayer2 { @Override public void collapseTreeRow(int parentIndex) { TreeNode task = treeData.getDataAtIndex(parentIndex); - collapsed.add(task); + expanded.remove(task); task.setExpanded(false); super.collapseTreeRow(parentIndex); } @@ -73,7 +73,7 @@ public class GETreeLayer extends TreeLayer2 { @Override public void expandTreeRow(int parentIndex) { TreeNode task = treeData.getDataAtIndex(parentIndex); - collapsed.remove(task); + expanded.add(task); task.setExpanded(true); super.expandTreeRow(parentIndex); } @@ -117,7 +117,7 @@ public class GETreeLayer extends TreeLayer2 { TreeNode task = treeData.getDataAtIndex(parentIndex); if (task != null) { task.setExpanded(false); - collapsed.add(task); + expanded.remove(task); } rowIndexes.addAll(getModel().collapse(parentIndex)); } @@ -145,7 +145,7 @@ public class GETreeLayer extends TreeLayer2 { if (parentIndex >= 0) { TreeNode task = treeData.getDataAtIndex(parentIndex); task.setExpanded(false); - collapsed.add(task); + expanded.remove(task); rowIndexes.addAll(getModel().collapse(parentIndex)); } } @@ -175,7 +175,7 @@ public class GETreeLayer extends TreeLayer2 { } t.setExpanded(false); - collapsed.add(t); + expanded.remove(t); getModel().collapse(i); } @@ -189,8 +189,9 @@ public class GETreeLayer extends TreeLayer2 { for (int parentIndex : parentIndices) { TreeNode task = treeData.getDataAtIndex(parentIndex); task.setExpanded(true); - collapsed.remove(task); + expanded.add(task); rowIndexes.addAll(getModel().expand(parentIndex)); + rowIndexes.add(parentIndex); } //Implementation uses tree set, so removing in reverse order is faster. @@ -207,7 +208,7 @@ public class GETreeLayer extends TreeLayer2 { for (int parentIndex : parentIndices) { TreeNode task = treeData.getDataAtIndex(parentIndex); task.setExpanded(true); - collapsed.remove(task); + expanded.add(task); rowIndexes.addAll(getModel().expand(parentIndex)); } @@ -220,20 +221,20 @@ public class GETreeLayer extends TreeLayer2 { fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes)); } - public void expandAllRows() { - Collection parentIndices = getHiddenRowIndexes(); - List rowIndexes = new ArrayList(); - for (int parentIndex : parentIndices) { - rowIndexes.addAll(getModel().expand(parentIndex)); - } - for (TreeNode t : collapsed) - t.setExpanded(true); - collapsed.clear(); - getHiddenRowIndexes().clear(); - ((GETreeRowModel)getModel()).clear(); - invalidateCache(); - fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes)); - } +// public void expandAllRows() { +// Collection parentIndices = getHiddenRowIndexes(); +// List rowIndexes = new ArrayList(); +// for (int parentIndex : parentIndices) { +// rowIndexes.addAll(getModel().expand(parentIndex)); +// } +// for (TreeNode t : collapsed) +// t.setExpanded(true); +// collapsed.clear(); +// getHiddenRowIndexes().clear(); +// ((GETreeRowModel)getModel()).clear(); +// invalidateCache(); +// fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes)); +// } @Override protected void invalidateCache() { @@ -242,6 +243,23 @@ public class GETreeLayer extends TreeLayer2 { hiddenPos.add(new int[]{0,0}); } + private void _collapseAllRows() { + int count = treeData.getElementCount(); + List rowIndexes = new ArrayList(count); + for (int i = 0; i < count; i++) { + TreeNode t = treeData.getDataAtIndex(i); + // we don't want to hide the roots of the tree + if (!treeData.isRoot(t)) { + rowIndexes.add(i); + + } + getModel().collapse(i); + + } + this.getHiddenRowIndexes().addAll(rowIndexes); + invalidateCache(); + } + @Override public void handleLayerEvent(ILayerEvent event) { // Currently sorting is implemented by sorting the underlaying list. @@ -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 // sorting layer would map the row indexes to sorted row positions. - // preserve collapsed nodes + // preserve expanded nodes Set coll = null; +// int hiddenCount = 0; if (event instanceof IStructuralChangeEvent) { IStructuralChangeEvent structuralChangeEvent = (IStructuralChangeEvent) event; if (structuralChangeEvent.isVerticalStructureChanged()) { - // expand old indices - ((GETreeRowModel)getModel()).clear(); + // store old indices + internalRefresh = true; + ((GETreeRowModel)getModel()).clear(); +// hiddenCount = getHiddenRowIndexes().size(); getHiddenRowIndexes().clear(); - coll = collapsed; + // store expanded nodes and clear disposed nodes. + coll = new HashSet<>(); + for (TreeNode n : expanded) + if (!n.isDisposed()) + coll.add(n); + expanded.clear(); + expanded.addAll(coll); + // filter hidden nodes (nodes that have collapsed ancestors) + coll.clear(); + for (TreeNode n : expanded) + if (!n.isHidden()) + coll.add(n); } } super.handleLayerEvent(event); if (coll != null) { - // collapse new indices + _collapseAllRows(); + // expand new indices int ind[] = new int[coll.size()]; Iterator iter = coll.iterator(); for (int i = 0; i < ind.length; i++) { ind[i] = treeData.indexOf(iter.next()); } - collapseTreeRow(ind); + expandTreeRow(ind); +// if (getHiddenRowIndexes().size() != hiddenCount) { +// System.out.println(getHiddenRowIndexes().size() + " != " + hiddenCount); +// ((GETreeRowModel)getModel()).clear(); +// getHiddenRowIndexes().clear(); +// _collapseAllRows(); +// //collapseAll(); +// // expand new indices +// iter = coll.iterator(); +// for (int i = 0; i < ind.length; i++) { +// ind[i] = treeData.indexOf(iter.next()); +// } +// expandTreeRow(ind); +// } + internalRefresh = false; } } - public Set getCollapsed() { - return collapsed; + private boolean internalRefresh = false; + + public void fireLayerEvent(ILayerEvent event) { + if (!internalRefresh) + super.fireLayerEvent(event); + + } + + public Set getExpanded() { + return expanded; } List hiddenPos; diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeRowModel.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeRowModel.java index ebfb962db..762b47ce0 100644 --- a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeRowModel.java +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/GETreeRowModel.java @@ -22,7 +22,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet; public class GETreeRowModel implements ITreeRowModel{ //private final HashSet parentIndexes = new HashSet(); //private final TIntHashSet parentIndexes = new TIntHashSet(1000, 0.8f); - private final IntOpenHashSet parentIndexes = new IntOpenHashSet(); + private final IntOpenHashSet expandedIndexes = new IntOpenHashSet(); private final Collection listeners = new HashSet(); @@ -59,11 +59,11 @@ public class GETreeRowModel implements ITreeRowModel{ } public boolean isCollapsed(int index) { - return this.parentIndexes.contains(index); + return !this.expandedIndexes.contains(index); } public void clear() { - this.parentIndexes.clear(); + this.expandedIndexes.clear(); } @Override @@ -73,16 +73,18 @@ public class GETreeRowModel implements ITreeRowModel{ @Override public List collapse(int index) { - this.parentIndexes.add(index); + this.expandedIndexes.remove(index); notifyListeners(); - return getChildIndexes(index); + List list = getChildIndexes(index); + //this.parentIndexes.addAll(list); + return list; } @Override public List expand(int index) { - this.parentIndexes.remove(index); + this.expandedIndexes.add(index); notifyListeners(); List children = getExpandedChildIndexes(index); return children; @@ -90,7 +92,6 @@ public class GETreeRowModel implements ITreeRowModel{ @Override public List collapseAll() { - // TODO Auto-generated method stub return null; } @@ -195,7 +196,7 @@ public class GETreeRowModel implements ITreeRowModel{ int index = this.treeData.indexOf(child); if (index >= 0) { result.add(index); - if (!parentIndexes.contains(index)) + if (expandedIndexes.contains(index)) result.addAll(getExpandedChildIndexes(index)); } else { result.addAll(getExpandedChildIndexes(child)); @@ -211,7 +212,7 @@ public class GETreeRowModel implements ITreeRowModel{ int index = this.treeData.indexOf(child); if (index >= 0) { result.add(index); - if (!parentIndexes.contains(index)) + if (expandedIndexes.contains(index)) result.addAll(getExpandedChildIndexes(index)); } else { result.addAll(getExpandedChildIndexes(child)); 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 index 000000000..9d43c351f --- /dev/null +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/KeyToSelectionAdapter.java @@ -0,0 +1,163 @@ +package org.simantics.browsing.ui.nattable; + +import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.simantics.browsing.ui.GraphExplorer; +import org.simantics.utils.ui.AdaptionUtils; + +/** + * Selects tree items based on pressed key events.

+ * + * The default implementation of SWT.Tree (Windows?) uses only the the first column when matching the items.

+ * + * This implementation checks all columns. Override

matches(), matchesColumn()
for customized behavior.

+ * + * @author Marko Luukkainen + * + */ +public class KeyToSelectionAdapter extends KeyAdapter { + + private static final int KEY_INPUT_DELAY = 500; + + private final NatTableGraphExplorer explorer; + + private String matcher = ""; + private int prevEvent = 0; + private int columns = 0; + + protected Pattern alphaNum; + + /** + * @param contextProvider + * @param explorer + */ + public KeyToSelectionAdapter(GraphExplorer explorer) { + assert explorer != null; + + this.explorer = (NatTableGraphExplorer)explorer; + this.alphaNum = Pattern.compile("\\p{Alnum}"); + } + + @Override + public void keyPressed(KeyEvent e) { + if (explorer.isDisposed()) + return; + + + if (!alphaNum.matcher(Character.toString(e.character)).matches()) + return; + // concatenate / replace matcher. + if ((e.time - prevEvent) > KEY_INPUT_DELAY ) + matcher = ""; + prevEvent = e.time; + matcher = matcher += Character.toString(e.character); + + + //TreeItem item = null; + NatTable tree = explorer.getControl(); + columns = explorer.getColumns().length; + + IStructuredSelection sel = (IStructuredSelection)explorer.getWidgetSelection(); + Collection selected = AdaptionUtils.adaptToCollection(sel, RowSelectionItem.class); + + + TreeNode item = find(tree, selected); + + if (item == null && matcher.length() > 1) { + matcher = matcher.substring(matcher.length()-1); + item = find(tree, selected); + } + + if (item != null) { + explorer.select(item); + explorer.show(item); +// tree.select(item); +// tree.showItem(item); + + + } + // without this the default handling would take over. + e.doit = false; + } + + private TreeNode previous = null; + private boolean foundPrev = false; + + private TreeNode find(NatTable tree, Collection selected) { + TreeNode item = null; + + List items = explorer.getItems(); + + if (selected.size() == 0) { + previous = null; + foundPrev = true; + item = findItem(items); + + } else { + previous = selected.iterator().next().item; + foundPrev = false; + item = findItem(items); + if (item == null) { + previous = null; + foundPrev = true; + item = findItem(items); + } + } + return item; + } + + private TreeNode findItem(List items) { + for (int i = 0; i < items.size(); i++) { + TreeNode item = items.get(i); + if (item != previous) { + if (foundPrev && matches(item, columns, matcher)) + return item; + + } else { + foundPrev = true; + } + } + return null; + } + + + /** + * + * @param item + * @param depth Depth of the item in the tree. + * @param columns Number of columns. + * @param string Matching string. + * @return + */ + protected boolean matches(TreeNode item, int columns, String matcher) { + for (int c = 0; c < columns; c++) { + if (matchesColumn(item, c, matcher)) { + return true; + } + } + return false; + } + + /** + * + * @param item + * @param column + * @param matcher + * @return + */ + protected boolean matchesColumn(TreeNode item, int column, String matcher) { + String text = item.getValueString(column); + if (text.toLowerCase().startsWith(matcher)) { + return true; + } + return false; + } + + +} diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableGraphExplorer.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableGraphExplorer.java index aa2c5b21e..f38f5fd93 100644 --- a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableGraphExplorer.java +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableGraphExplorer.java @@ -28,8 +28,6 @@ import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.layout.GridDataFactory; -import org.eclipse.jface.layout.TreeColumnLayout; import org.eclipse.jface.resource.ColorDescriptor; import org.eclipse.jface.resource.DeviceResourceException; import org.eclipse.jface.resource.DeviceResourceManager; @@ -55,11 +53,13 @@ import org.eclipse.nebula.widgets.nattable.coordinate.Range; import org.eclipse.nebula.widgets.nattable.data.IDataProvider; import org.eclipse.nebula.widgets.nattable.data.ListDataProvider; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDisplayConverter; +import org.eclipse.nebula.widgets.nattable.data.validate.IDataValidator; +import org.eclipse.nebula.widgets.nattable.data.validate.ValidationFailedException; import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; import org.eclipse.nebula.widgets.nattable.edit.EditConfigHelper; import org.eclipse.nebula.widgets.nattable.edit.ICellEditHandler; -import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditBindings; import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditConfiguration; +import org.eclipse.nebula.widgets.nattable.edit.config.DialogErrorHandling; import org.eclipse.nebula.widgets.nattable.edit.editor.AbstractCellEditor; import org.eclipse.nebula.widgets.nattable.edit.editor.ComboBoxCellEditor; import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor; @@ -85,14 +85,18 @@ import org.eclipse.nebula.widgets.nattable.layer.LabelStack; import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnOverrideLabelAccumulator; import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent; -import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter; +import org.eclipse.nebula.widgets.nattable.painter.NatTableBorderOverlayPainter; import org.eclipse.nebula.widgets.nattable.reorder.ColumnReorderLayer; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; +import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand; import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration; +import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; import org.eclipse.nebula.widgets.nattable.style.DisplayMode; +import org.eclipse.nebula.widgets.nattable.style.Style; import org.eclipse.nebula.widgets.nattable.ui.menu.AbstractHeaderMenuConfiguration; import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder; +import org.eclipse.nebula.widgets.nattable.util.GUIHelper; import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer; import org.eclipse.nebula.widgets.nattable.widget.EditModeEnum; import org.eclipse.swt.SWT; @@ -106,7 +110,6 @@ import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; @@ -202,11 +205,13 @@ import gnu.trove.map.hash.THashMap; import gnu.trove.map.hash.TObjectIntHashMap; /** - * NatTable base GraphExplorer + * NatTable based GraphExplorer + * + * This GraphExplorer is not fully compatible with the other implementations, since it is not based on SWT.Tree. + * + * 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. * * - * FIXME : asynchronous node loading does not work properly + check expanded/collapsed sate handling - * TODO: InputValidators + input errors * TODO: ability to hide headers * TODO: code cleanup (copied from GraphExplorerImpl2) * @@ -214,7 +219,7 @@ import gnu.trove.map.hash.TObjectIntHashMap; * */ public class NatTableGraphExplorer extends GraphExplorerImplBase implements GraphExplorer{ - public static final int DEFAULT_MAX_CHILDREN = 1000; + public static final int DEFAULT_MAX_CHILDREN = 10000; private static final boolean DEBUG_SELECTION_LISTENERS = false; private static final boolean DEBUG = false; @@ -349,7 +354,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap originalFont = JFaceResources.getDefaultFontDescriptor(); columns = new Column[0]; - createNatTable(); + createNatTable(style); layout = new NatTableColumnLayout(natTable, columnHeaderDataProvider, rowHeaderDataLayer); this.composite.setLayout(layout); @@ -531,8 +536,6 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap //refreshColumnSizes(); rootNode = new TreeNode(rootContext, explorerContext); if (DEBUG) System.out.println("setRoot " + rootNode); - - // viewer.setInput(rootNode); // Delay content reading. @@ -545,8 +548,8 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap public void run() { if (rootNode != null) { rootNode.updateChildren(); + rootNode.setExpanded(true); listReIndex(); - natTable.refresh(true); } } }); @@ -554,9 +557,13 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } private synchronized void listReIndex() { + for (TreeNode n : list) { + n.setListIndex(-2); + } list.clear(); for (TreeNode c : rootNode.getChildren()) _insertToList(c); + natTable.refresh(); } private void _insertToList(TreeNode n) { @@ -567,6 +574,10 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } } + public List getItems() { + return Collections.unmodifiableList(list); + } + private void initializeState() { if (persistor == null) return; @@ -689,7 +700,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap if (natTable.isDisposed()) return; doSetColumns(columns, callback); - natTable.refresh(true); + natTable.refresh(); natTable.getParent().layout(); } }); @@ -1065,6 +1076,30 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } + public boolean select(TreeNode node) { + assertNotDisposed(); + + if (!list.contains(node)) { + StructuredSelection s = new StructuredSelection(); + selectionAdaptor.setSelection(s); + selectionProvider.setAndFireNonEqualSelection(s); + return true; + } + selectionAdaptor.setSelection(new StructuredSelection(node)); + return false; + } + + public void show(TreeNode node) { + int index = node.getListIndex(); + + int position = treeLayer.getRowPositionByIndex(index); + if (position < 0) { + treeLayer.expandToTreeRow(index); + position = treeLayer.getRowPositionByIndex(index); + } + viewportLayer.moveRowPositionIntoViewport(position); + } + @Override public boolean selectPath(Collection contexts) { @@ -1171,7 +1206,6 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap else treeLayer.collapseTreeRow(n.getListIndex()); } - //viewer.setExpandedState(context, expanded); } @@ -1179,7 +1213,6 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap public void setAutoExpandLevel(int level) { this.autoExpandLevel = level; treeLayer.expandAllToLevel(level); - //viewer.setAutoExpandLevel(level); } int maxChildren = DEFAULT_MAX_CHILDREN; @@ -1244,22 +1277,51 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap if (element.isDisposed()) { return; } - if (((TreeNode)element).updateChildren()) { + if (element.updateChildren()) { + if (DEBUG) { + System.out.println("Update Item updateChildren " + element.listIndex + " " + element); + printDebug(NatTableGraphExplorer.this); + } listReIndex(); - natTable.refresh(true); - //viewer.refresh(element,true); + if (!element.isHidden()) { + if (!element.isExpanded()) { + if (element.listIndex >= 0) + treeLayer.collapseTreeRow(element.listIndex); + if (DEBUG) { + System.out.println("Update Item collapse " + element.listIndex); + printDebug(NatTableGraphExplorer.this); + } + } else { + for (TreeNode c : element.getChildren()) + c.initData(); + } + } else { + TreeNode p = element.getCollapsedAncestor(); + if (p != null) { + if (element.listIndex >= 0) + treeLayer.collapseTreeRow(element.listIndex); + if (p.listIndex >= 0) + treeLayer.collapseTreeRow(p.listIndex); + if (DEBUG) { + System.out.println("Update Item ancetor collapse " + p.listIndex); + printDebug(NatTableGraphExplorer.this); + } + } + } } else { - if (columnIndex >= 0) { - natTable.redraw(); - //viewer.update(element, new String[]{columns[columnIndex].getKey()}); - } else { - natTable.redraw(); - //viewer.refresh(element,true); - } +// if (columnIndex >= 0) { +// viewer.update(element, new String[]{columns[columnIndex].getKey()}); +// } else { +// viewer.refresh(element,true); +// } + natTable.redraw(); } - if (!element.isDisposed() && autoExpandLevel > 1 && !element.isExpanded() && element.getDepth() <= autoExpandLevel) { + if (!element.autoExpanded && !element.isDisposed() && autoExpandLevel > 1 && !element.isExpanded() && element.getDepth() <= autoExpandLevel) { expand = true; + element.autoExpanded = true; + element.initData(); + if (DEBUG) System.out.println("Update Item expand " + element.listIndex); treeLayer.expandTreeRow(element.getListIndex()); //viewer.setExpandedState(element, true); expand = false; @@ -1267,8 +1329,6 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } else { if (rootNode.updateChildren()) { listReIndex(); - natTable.refresh(true); - //viewer.refresh(rootNode,true); } } } @@ -1296,11 +1356,13 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } private void update(final TreeNode element, final int columnIndex) { - if (DEBUG)System.out.println("update " + element + " " + columnIndex); if (natTable.isDisposed()) return; + if (element != null && element.isDisposed()) + return; + if (DEBUG) System.out.println("update " + element + " " + columnIndex); synchronized (pendingItems) { - pendingItems.add(new UpdateItem(element, columnIndex)); + pendingItems.add(new UpdateItem(element, columnIndex)); if (updating) return; updateCounter++; scheduleUpdater(); @@ -1308,14 +1370,14 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } private void update(final TreeNode element) { - if (DEBUG)System.out.println("update " + element); + if (natTable.isDisposed()) return; if (element != null && element.isDisposed()) return; + if (DEBUG) System.out.println("update " + element); synchronized (pendingItems) { - - pendingItems.add(new UpdateItem(element)); + pendingItems.add(new UpdateItem(element)); if (updating) return; updateCounter++; scheduleUpdater(); @@ -1449,7 +1511,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap return (double)dpi.x/96.0; } - private void createNatTable() { + private void createNatTable(int style) { GETreeData treeData = new GETreeData(list); GETreeRowModel treeRowModel = new GETreeRowModel(treeData); columnAccessor = new GEColumnAccessor(this); @@ -1529,7 +1591,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap natTable.addConfiguration(new SingleClickSortConfiguration()); //natTable.addLayerListener(this); - natTable.addConfiguration(new GENatTableThemeConfiguration(treeData)); + natTable.addConfiguration(new GENatTableThemeConfiguration(treeData, style)); natTable.addConfiguration(new NatTableHeaderMenuConfiguration(natTable)); natTable.addConfiguration(new AbstractRegistryConfiguration() { @@ -1559,13 +1621,25 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap }); configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new AdaptableCellEditor()); + configRegistry.registerConfigAttribute(EditConfigAttributes.CONVERSION_ERROR_HANDLER, new DialogErrorHandling(), DisplayMode.EDIT); + configRegistry.registerConfigAttribute(EditConfigAttributes.VALIDATION_ERROR_HANDLER, new DialogErrorHandling(), DisplayMode.EDIT); + configRegistry.registerConfigAttribute(EditConfigAttributes.DATA_VALIDATOR, new AdaptableDataValidator(),DisplayMode.EDIT); + + Style conversionErrorStyle = new Style(); + conversionErrorStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_RED); + conversionErrorStyle.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR, GUIHelper.COLOR_WHITE); + configRegistry.registerConfigAttribute(EditConfigAttributes.CONVERSION_ERROR_STYLE, conversionErrorStyle, DisplayMode.EDIT); + configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER, new DefaultDisplayConverter(),DisplayMode.EDIT); - // configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new GECellPainter(),DisplayMode.NORMAL); - - + + } }); + if ((style & SWT.BORDER) > 0) { + natTable.addOverlayPainter(new NatTableBorderOverlayPainter()); + } + natTable.configure(); // natTable.addListener(SWT.MenuDetect, new NatTableMenuListener()); @@ -1764,8 +1838,29 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap public Rectangle calculateControlBounds(Rectangle cellBounds) { return editor.calculateControlBounds(cellBounds); } + } + + private class AdaptableDataValidator implements IDataValidator { + @Override + public boolean validate(ILayerCell cell, IConfigRegistry configRegistry, Object newValue) { + int col = cell.getColumnIndex(); + int row = cell.getRowIndex(); + return validate(col, row, newValue); + } - + @Override + public boolean validate(int col, int row, Object newValue) { + TreeNode node = list.get(row); + Modifier modifier = getModifier(node, col); + if (modifier == null) + return false; + + String err = modifier.isValid(newValue.toString()); + if (err == null) + return true; + modifier.isValid(newValue.toString()); + throw new ValidationFailedException(err); + } } private class CustomCellEditor extends AbstractCellEditor { @@ -2079,7 +2174,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } if (DEBUG) System.out.println("UpdateRunner.doRun() " + items.size()); - ge.natTable.setRedraw(false); + //ge.natTable.setRedraw(false); for (UpdateItem item : items) { item.update(ge.natTable); } @@ -2091,7 +2186,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap ge.natTable.getParent().layout(); } - ge.natTable.setRedraw(true); + //ge.natTable.setRedraw(true); synchronized (ge.pendingItems) { if (!ge.scheduleUpdater()) { @@ -2100,13 +2195,36 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } if (DEBUG) { if (!ge.updating) { - ge.printTree(ge.rootNode, 0); + printDebug(ge); } } } } + private static void printDebug(NatTableGraphExplorer ge) { + ge.printTree(ge.rootNode, 0); + System.out.println("Expanded"); + for (TreeNode n : ge.treeLayer.expanded) + System.out.println(n); + System.out.println("Expanded end"); + System.out.println("Hidden "); + for (int i : ge.treeLayer.getHiddenRowIndexes()) { + System.out.print(i + " "); + } + System.out.println(); +// Display.getCurrent().timerExec(1000, new Runnable() { +// +// @Override +// public void run() { +// System.out.println("Hidden delayed "); +// for (int i : ge.treeLayer.getHiddenRowIndexes()) { +// System.out.print(i + " "); +// } +// System.out.println(); +// } +// }); + } public static class GeViewerContext extends AbstractDisposable implements IGraphExplorerContext { @@ -2348,23 +2466,22 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap @Override public void handleLayerEvent(ILayerEvent event) { - // TODO Auto-generated method stub if (event instanceof ShowRowPositionsEvent) { ShowRowPositionsEvent e = (ShowRowPositionsEvent)event; for (Range r : e.getRowPositionRanges()) { int expanded = viewportLayer.getRowIndexByPosition(r.start-2)+1; - //System.out.println("ex " + expanded); - if (expanded < 0) { + if (DEBUG)System.out.println("IsExpandedProcessor expand " + expanded); + if (expanded < 0 || expanded >= list.size()) { return; } - nodeStatusChanged(list.get(expanded).getContext(), false); + nodeStatusChanged(list.get(expanded).getContext(), true); } } else if (event instanceof HideRowPositionsEvent) { HideRowPositionsEvent e = (HideRowPositionsEvent)event; for (Range r : e.getRowPositionRanges()) { - int collapsed = viewportLayer.getRowIndexByPosition(r.start-2)+1; - //System.out.println("col " + collapsed); - if (collapsed < 0) { + int collapsed = viewportLayer.getRowIndexByPosition(r.start-2); + if (DEBUG)System.out.println("IsExpandedProcessor collapse " + collapsed); + if (collapsed < 0 || collapsed >= list.size()) { return; } nodeStatusChanged(list.get(collapsed).getContext(), false); @@ -2714,7 +2831,7 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap } } -private class NatTableHeaderMenuConfiguration extends AbstractHeaderMenuConfiguration { + private class NatTableHeaderMenuConfiguration extends AbstractHeaderMenuConfiguration { public NatTableHeaderMenuConfiguration(NatTable natTable) { @@ -2755,8 +2872,8 @@ private class NatTableHeaderMenuConfiguration extends AbstractHeaderMenuConfigur Point point = new Point(e.x, e.y); int y = natTable.getRowPositionByY(point.y); int x = natTable.getColumnPositionByX(point.x); - if (x < 0 | y < 0) + if (x < 0 | y <= 0) return null; - return list.get(y); + return list.get(y-1); } } diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableSelectionAdaptor.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableSelectionAdaptor.java index 4302cdeac..03588ae76 100644 --- a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableSelectionAdaptor.java +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableSelectionAdaptor.java @@ -1,6 +1,7 @@ package org.simantics.browsing.ui.nattable; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.eclipse.jface.viewers.IPostSelectionProvider; @@ -21,6 +22,7 @@ import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Event; import org.simantics.utils.datastructures.MapList; +import org.simantics.utils.ui.AdaptionUtils; public class NatTableSelectionAdaptor implements ISelectionProvider, IPostSelectionProvider, ILayerListener { NatTable natTable; @@ -76,9 +78,41 @@ public class NatTableSelectionAdaptor implements ISelectionProvider, IPostSelect public void setSelection(ISelection selection) { if (!(selection instanceof StructuredSelection)) throw new IllegalArgumentException("Selection must be structured selection"); + if (selection.isEmpty()) { + selectionLayer.clear(false); + natTable.redraw(); + return; + } + List rowItems = new ArrayList<>(AdaptionUtils.adaptToCollection(selection, RowSelectionItem.class)); + if (rowItems.size() > 0) { + + setSelectionExternal(rowItems); + return; + } + Collection nodes = AdaptionUtils.adaptToCollection(selection, TreeNode.class); + if (nodes.size() > 0) { + List selected = new ArrayList<>(); + int allCols[] = new int[selectionLayer.getColumnCount()]; + for (int i = 0; i < allCols.length; i++) + allCols[i] = i; + for (TreeNode n : nodes) { + selected.add(new RowSelectionItem(n, n.listIndex, allCols)); + } + setSelectionExternal(selected); + return; + } } + private void setSelectionExternal(List items) { + selectionLayer.clear(true); + for (RowSelectionItem item : items) { + for (int c : item.columnIndex) + selectionLayer.selectCell(c, item.rowIndex, false, true); + } + selection = new StructuredSelection(items); + fireEvents(); + } private List selectedCells = new ArrayList(); diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/TreeNode.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/TreeNode.java index 941c6f319..30a37e329 100644 --- a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/TreeNode.java +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/TreeNode.java @@ -38,6 +38,7 @@ public class TreeNode implements IAdaptable { TreeNode parent; List children = new ArrayList(); boolean expanded; + boolean autoExpanded = false; public TreeNode(NodeContext context, GeViewerContext explorerContext) { this.context = context; @@ -47,13 +48,13 @@ public class TreeNode implements IAdaptable { explorerContext.getContextToNodeMap().add(context, this); } - int getDepth() { + public int getDepth() { if (parent == null) return 0; return parent.getDepth() + 1; } - int listIndex; + int listIndex = -1; public int getListIndex() { return listIndex; @@ -79,6 +80,27 @@ public class TreeNode implements IAdaptable { return expanded; } + public boolean isHidden() { + TreeNode n = parent; + while (n != null) { + if (!n.isExpanded()) + return true; + n = n.getParent(); + } + return false; + } + + public TreeNode getCollapsedAncestor() { + TreeNode collapsed = null; + TreeNode n = parent; + while (n != null) { + if (!n.isExpanded()) + collapsed = n; + n = n.getParent(); + } + return collapsed; + } + public NodeContext getContext() { return context; } @@ -92,9 +114,8 @@ public class TreeNode implements IAdaptable { Map runtimeLabels; public String getValueString(int column) { - if (column == 0) { + if (column == 0) initData(); - } if (labeler != null) { String key = explorerContext.getGe().getColumns()[column].getKey(); String s = null; @@ -199,7 +220,7 @@ public class TreeNode implements IAdaptable { } - private void initData() { + public void initData() { labeler = manager.query(context, BuiltinKeys.SELECTED_LABELER); imager = manager.query(context, BuiltinKeys.SELECTED_IMAGER); labelDecorators = manager.query(context, BuiltinKeys.LABEL_DECORATORS); @@ -319,7 +340,13 @@ public class TreeNode implements IAdaptable { } for (int i = oldCount; i < childContexts.length; i++) { - addChild(childContexts[i], explorerContext); + Integer oldIndex = indexes.getLeft(i); + if (oldIndex == null) { + addChild(childContexts[i], explorerContext); + } else { + TreeNode n = oldChildren.get(oldIndex); + children.add(n); + } } } else { for (int i = 0; i < childContexts.length; i++) { @@ -363,5 +390,10 @@ public class TreeNode implements IAdaptable { return context.getAdapter(adapter); } + + @Override + public String toString() { + return "TreeNode: " + listIndex + " " + (expanded ? "(+)" : "(-)") + " " + context ; + } } diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/DefaultBindingFactory.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/DefaultBindingFactory.java index 54c1160c5..73f2d2f16 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/DefaultBindingFactory.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/DefaultBindingFactory.java @@ -20,6 +20,7 @@ import org.simantics.databoard.binding.impl.BooleanArrayBinding; import org.simantics.databoard.binding.impl.BooleanBindingDefault; import org.simantics.databoard.binding.impl.ByteArrayBinding; import org.simantics.databoard.binding.impl.ByteBindingDefault; +import org.simantics.databoard.binding.impl.DefaultMapBinding; import org.simantics.databoard.binding.impl.DoubleArrayBinding; import org.simantics.databoard.binding.impl.DoubleBindingDefault; import org.simantics.databoard.binding.impl.FloatArrayBinding; @@ -30,7 +31,6 @@ import org.simantics.databoard.binding.impl.LongArrayBinding; import org.simantics.databoard.binding.impl.LongBindingDefault; import org.simantics.databoard.binding.impl.ObjectArrayBinding; import org.simantics.databoard.binding.impl.StringBindingDefault; -import org.simantics.databoard.binding.impl.TreeMapBinding; import org.simantics.databoard.binding.mutable.ContainerOptionalBinding; import org.simantics.databoard.binding.mutable.UnionTaggedObjectBinding; import org.simantics.databoard.type.ArrayType; @@ -180,9 +180,9 @@ public class DefaultBindingFactory extends TypeBindingFactory { return binding; } - 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); binding.setKeyBinding( construct(mapType.keyType) ); binding.setValueBinding( construct(mapType.valueType) ); diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/JavaUtilBindingsProvider.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/JavaUtilBindingsProvider.java index e43b7bc73..b173cb6eb 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/JavaUtilBindingsProvider.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/JavaUtilBindingsProvider.java @@ -28,6 +28,8 @@ import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.impl.ArrayListBinding; import org.simantics.databoard.binding.impl.BooleanArrayBinding; import org.simantics.databoard.binding.impl.ByteArrayBinding; +import org.simantics.databoard.binding.impl.DefaultMapBinding; +import org.simantics.databoard.binding.impl.DefaultSetBinding; import org.simantics.databoard.binding.impl.DoubleArrayBinding; import org.simantics.databoard.binding.impl.FloatArrayBinding; import org.simantics.databoard.binding.impl.HashMapBinding; @@ -101,7 +103,7 @@ public class JavaUtilBindingsProvider implements BindingProvider { if (Set.class.isAssignableFrom(request.getClazz())) { MapType type = new MapType(); type.valueType = Datatypes.VOID; - return new TreeSetBinding(type, null); + return new DefaultSetBinding(type, null); } if (TreeMap.class.isAssignableFrom(request.getClazz())) { @@ -113,7 +115,7 @@ public class JavaUtilBindingsProvider implements BindingProvider { } if (Map.class.isAssignableFrom(request.getClazz())) { - return new HashMapBinding(new MapType(), null, null); + return new DefaultMapBinding(new MapType(), null, null); } return null; diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/TroveBindingsProvider.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/TroveBindingsProvider.java index e635e12a0..0f9a4dc76 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/TroveBindingsProvider.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/TroveBindingsProvider.java @@ -103,6 +103,9 @@ public class TroveBindingsProvider implements BindingProvider { @Override public Object create(Map initialMap) throws BindingException { + if (initialMap instanceof THashMap) + return initialMap; + // Replace with TreeMap. Create comparator from binding. THashMap result = new THashMap(); putAll(result, initialMap); @@ -134,10 +137,14 @@ public class TroveBindingsProvider implements BindingProvider { } public Object create(Set initialSet) throws BindingException { + if (initialSet instanceof THashSet) + return initialSet; + return new THashSet(initialSet); } - @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override public Object create(Map initialMap) throws BindingException { return new THashSet(initialMap.keySet()); } 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 index 000000000..43c1e97aa --- /dev/null +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/DefaultMapBinding.java @@ -0,0 +1,326 @@ +/******************************************************************************* + * Copyright (c) 2010 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.databoard.binding.impl; + +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; + +import org.simantics.databoard.binding.ArrayBinding; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.MapBinding; +import org.simantics.databoard.binding.error.BindingException; +import org.simantics.databoard.type.MapType; + +/** + * Binds java.util.Map to MapType + * + * This Binding type accepts all java.util.Map instances, but creates + * java.util.TreeMap instances by default. + * + * @author Reino Ruusu + */ +@SuppressWarnings("rawtypes") +public class DefaultMapBinding extends MapBinding { + + public DefaultMapBinding(Binding keyBinding, Binding valueBinding) { + super(keyBinding, valueBinding); + } + + public DefaultMapBinding(MapType mapType, Binding keyBinding, + Binding valueBinding) { + super(mapType, keyBinding, valueBinding); + } + + public void postConstruction() { + } + + @Override + public Object create() { + return new TreeMap( keyBinding ); + } + + @SuppressWarnings("unchecked") + @Override + public Object create(Object[] keys, Object[] values) { + if (keys.length != values.length) + throw new IllegalArgumentException("Equal length arrays expected"); + + int len = keys.length; + Map result = new TreeMap( keyBinding ); + + for (int i = 0; i < len; i++) { + Object key = keys[i]; + Object value = values[i]; + result.put(key, value); + } + + return result; + } + + + @SuppressWarnings("unchecked") + @Override + public Object create(List keys, List values) { + if (keys.size()!=values.size()) + throw new IllegalArgumentException("Equal length arrays expected"); + + int len = keys.size(); + Map result = new TreeMap( keyBinding ); + + for (int i=0; i map) { + return map; + } + + @Override + public void clear(Object map) { + ((Map) map).clear(); + } + + @Override + public boolean containsKey(Object map, Object key) { + Map m = ((Map) map); + return m.containsKey(key); + } + + @Override + public boolean containsValue(Object map, Object value) { + Map m = ((Map) map); + Binding vb = getValueBinding(); + for (Object v : m.values()) + { + if (vb.equals(v, value)) return true; + } + return false; + } + + @Override + public Object get(Object map, Object key) { + Map m = ((Map) map); + return m.get(key); + } + + @SuppressWarnings("unchecked") + @Override + public Object[] getKeys(Object map) { + Map m = ((Map) map); + return m.keySet().toArray(new Object[m.size()]); + } + + @SuppressWarnings("unchecked") + @Override + public void getKeys(Object map, Set keys) throws BindingException { + Map m = ((Map)map); + keys.addAll(m.keySet()); + } + + /** + * Count the number of entries between two keyes + * @param from + * @param fromInclusive + * @param end + * @param endInclusive + * @throws BindingException + */ + @SuppressWarnings("unchecked") + @Override + public int count(Object src, Object from, boolean fromInclusive, Object end, boolean endInclusive) throws BindingException { + // Assert end > from + if (keyBinding.compare(from, end)>0) return 0; + + if (src instanceof TreeMap) { + TreeMap m = (TreeMap) src; + Map sm = m.subMap(from, fromInclusive, end, endInclusive); + return sm.size(); + } + else { + int result = 0; + Map m = ((Map)src); + for (Object k : m.keySet()) { + int fk = keyBinding.compare(from, k); + int ek = keyBinding.compare(k, end); + boolean fromMatches = fromInclusive ? fk<=0 : fk<0; + boolean endMatches = endInclusive ? ek<=0 : ek <0; + if ( fromMatches && endMatches ) result++; + } + return result; + } + } + + /** + * Read a range of entries + * + * @param src + * @param from + * @param fromInclusive + * @param end + * @param endInclusive + * @param dstKeyArrayBinding + * @param dstKeyArray + * @param dstValueArrayBinding + * @param dstValueArray + * @throws BindingException + */ + 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 { + if (src instanceof TreeMap) { + return new TreeMapBinding(keyBinding, valueBinding).getEntries(src, from, fromInclusive, end, endInclusive, dstKeyArrayBinding, dstKeyArray, dstValueArrayBinding, dstValueArray, limit); + } + else { + return new HashMapBinding(keyBinding, valueBinding).getEntries(src, from, fromInclusive, end, endInclusive, dstKeyArrayBinding, dstKeyArray, dstValueArrayBinding, dstValueArray, limit); + } + } + + + @SuppressWarnings("unchecked") + @Override + public Object[] getValues(Object map) { + Map m = ((Map) map); + return m.values().toArray(new Object[m.size()]); + } + + @Override + public void put(Object map, K key, V value) { + @SuppressWarnings("unchecked") + Map m = ((Map) map); + m.put(key, value); + } + + @Override + public void putAll(Object dstMap, Map srcMap) { + @SuppressWarnings("unchecked") + Map dst = ((Map) dstMap); + dst.putAll(srcMap); + } + + @SuppressWarnings("unchecked") + @Override + public void getAll(Object mapFrom, Map to) { + Map m = ((Map) mapFrom); + to.putAll(m); + } + + @SuppressWarnings("unchecked") + @Override + public void getAll(Object mapFrom, Object[] keys, Object[] values) { + Map m = (Map) mapFrom; + int i = 0; + for (Entry e : (Set>) m.entrySet()) { + keys[i] = e.getKey(); + values[i] = e.getValue(); + i++; + } + } + + @Override + public Object remove(Object map, Object key) { + Map m = ((Map) map); + return m.remove(key); + } + + @Override + public int size(Object map) { + Map m = ((Map) map); + return m.size(); + } + + @Override + public boolean isInstance(Object obj) { + return obj instanceof Map; + } + + @Override + public int deepHashValue(Object map, IdentityHashMap hashedObjects) throws BindingException { + int result = 0; + Map m = ((Map) map); + @SuppressWarnings("unchecked") + Set s = m.entrySet(); + for (Entry e : s) { + int keyTree = getKeyBinding().deepHashValue(e.getKey(), hashedObjects); + int valueTree = getValueBinding().deepHashValue(e.getValue(), hashedObjects); + result += (keyTree ^ valueTree); + } + return result; + } + + @Override + public Object getCeilingKey(Object map, Object key) { + if (map instanceof TreeMap) { + return new TreeMapBinding(keyBinding, valueBinding).getCeilingKey(map, key); + } + else { + return new HashMapBinding(keyBinding, valueBinding).getCeilingKey(map, key); + } + } + + @Override + public Object getFirstKey(Object map) { + if (map instanceof TreeMap) { + return new TreeMapBinding(keyBinding, valueBinding).getFirstKey(map); + } + else { + return new HashMapBinding(keyBinding, valueBinding).getFirstKey(map); + } + } + + @Override + public Object getFloorKey(Object map, Object key) { + if (map instanceof TreeMap) { + return new TreeMapBinding(keyBinding, valueBinding).getFloorKey(map, key); + } + else { + return new HashMapBinding(keyBinding, valueBinding).getFloorKey(map, key); + } + } + + @Override + public Object getHigherKey(Object map, Object key) { + if (map instanceof TreeMap) { + return new TreeMapBinding(keyBinding, valueBinding).getHigherKey(map, key); + } + else { + return new HashMapBinding(keyBinding, valueBinding).getHigherKey(map, key); + } + } + + @Override + public Object getLastKey(Object map) { + if (map instanceof TreeMap) { + return new TreeMapBinding(keyBinding, valueBinding).getLastKey(map); + } + else { + return new HashMapBinding(keyBinding, valueBinding).getLastKey(map); + } + } + + @Override + public Object getLowerKey(Object map, Object key) { + if (map instanceof TreeMap) { + return new TreeMapBinding(keyBinding, valueBinding).getLowerKey(map, key); + } + else { + return new HashMapBinding(keyBinding, valueBinding).getLowerKey(map, key); + } + } +} 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 index 000000000..783f80b33 --- /dev/null +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/DefaultSetBinding.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright (c) 2010 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.databoard.binding.impl; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.simantics.databoard.binding.ArrayBinding; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.MapBinding; +import org.simantics.databoard.binding.error.BindingException; +import org.simantics.databoard.binding.reflection.VoidBinding; +import org.simantics.databoard.type.MapType; +import org.simantics.databoard.type.RecordType; + +/** + * Binds java.util.Set to Map(T, {}) + * + * This binding accepts all java.util.Set instances, but instantiates + * java.util.TreeSet objects. + * + * @author Reino Ruusu + */ +@SuppressWarnings("unchecked") +public class DefaultSetBinding extends MapBinding { + + public DefaultSetBinding(MapType mapType, Binding elementBinding) { + super(mapType, elementBinding, VoidBinding.VOID_BINDING); + } + + public DefaultSetBinding(Binding elementBinding) { + super(new MapType(elementBinding.type(), RecordType.VOID_TYPE), elementBinding, VoidBinding.VOID_BINDING); + } + + @Override + public void clear(Object set) throws BindingException { + Set _set = (Set) set; + _set.clear(); + } + + @Override + public boolean containsKey(Object set, Object key) throws BindingException { + Set _set = (Set) set; + return _set.contains(key); + } + + @Override + public boolean containsValue(Object set, Object value) + throws BindingException { + return false; + } + + @Override + public Object create() throws BindingException { + return new TreeSet( keyBinding ); + } + + public Object create(Set initialSet) throws BindingException { + return initialSet; + } + + @Override + public Object create(Map initialMap) throws BindingException { + Set result = new TreeSet( keyBinding ); + result.addAll(initialMap.keySet()); + return result; + } + + @Override + public Object create(Object[] keys, Object[] values) + throws BindingException { + Set result = new TreeSet( keyBinding ); + for (int i=0; i keys, List values) { + Set result = new TreeSet( keyBinding ); + for (int i=0; i void getAll(Object setFrom, Map to) throws BindingException { + Map _to = (Map) to; + Set _setFrom = (Set) setFrom; + for (K k : _setFrom) + _to.put(k, null); + } + + @Override + public void getAll(Object setFrom, Object[] keys, Object[] values) + throws BindingException { + Set _setFrom = (Set) setFrom; + int i=0; + for (Object k : _setFrom) { + keys[i] = k; + values[i] = null; + } + } + + @Override + public Object[] getKeys(Object set) throws BindingException { + Set _set = (Set) set; + return _set.toArray(new Object[_set.size()]); + } + + @Override + public void getKeys(Object set, Set keys) throws BindingException { + Set s = (Set) set; + keys.addAll(s); + } + + @Override + public Object[] getValues(Object set) throws BindingException { + Set _set = (Set) set; + return new Object[_set.size()]; + } + + @Override + public int count(Object src, Object from, boolean fromInclusive, Object end, boolean endInclusive) throws BindingException { + if (src instanceof TreeSet) + return new TreeSetBinding(keyBinding).count(src, from, fromInclusive, end, endInclusive); + else + return new HashSetBinding(keyBinding).count(src, from, fromInclusive, end, endInclusive); + } + + @Override + 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 { + return 0; + } + + @Override + public void put(Object set, Object key, Object value) + throws BindingException { + Set _set = (Set) set; + if (value!=null) throw new BindingException("Cannot put non-null to a Set"); + _set.add(key); + } + + public void putAll(Object setTo, Set from) { + Set _set = (Set) setTo; + _set.addAll(from); + } + + @Override + public void putAll(Object setTo, Map from) throws BindingException { + Set _set = (Set) setTo; + _set.addAll(from.keySet()); + } + + @Override + public Object remove(Object set, Object key) throws BindingException { + Set _set = (Set) set; + _set.remove(key); + return null; + } + + @Override + public int size(Object set) throws BindingException { + Set _set = (Set) set; + return _set.size(); + } + + @Override + public boolean isInstance(Object obj) { + return obj instanceof Set; + } + + @Override + public Object getCeilingKey(Object set, Object key) { + if (set instanceof TreeSet) + return new TreeSetBinding(keyBinding).getCeilingKey(set, key); + else + return new HashSetBinding(keyBinding).getCeilingKey(set, key); + } + + @Override + public Object getFirstKey(Object set) { + if (set instanceof TreeSet) + return new TreeSetBinding(keyBinding).getFirstKey(set); + else + return new HashSetBinding(keyBinding).getFirstKey(set); + } + + @Override + public Object getFloorKey(Object set, Object key) { + if (set instanceof TreeSet) + return new TreeSetBinding(keyBinding).getFloorKey(set, key); + else + return new HashSetBinding(keyBinding).getFloorKey(set, key); + } + + @Override + public Object getHigherKey(Object set, Object key) { + if (set instanceof TreeSet) + return new TreeSetBinding(keyBinding).getHigherKey(set, key); + else + return new HashSetBinding(keyBinding).getHigherKey(set, key); + } + + @Override + public Object getLastKey(Object set) { + if (set instanceof TreeSet) + return new TreeSetBinding(keyBinding).getLastKey(set); + else + return new HashSetBinding(keyBinding).getLastKey(set); + } + + @Override + public Object getLowerKey(Object set, Object key) { + if (set instanceof TreeSet) + return new TreeSetBinding(keyBinding).getLowerKey(set, key); + else + return new HashSetBinding(keyBinding).getLowerKey(set, key); + } + +} + diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashMapBinding.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashMapBinding.java index d3a9d8c75..76241a0c7 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashMapBinding.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashMapBinding.java @@ -53,13 +53,11 @@ public class HashMapBinding extends MapBinding { super(mapType, keyBinding, valueBinding); } - public void postConstruction() {} - - @Override - public Object create() { - return new HashMap(); - } - + @Override + public Object create() { + return new HashMap(); + } + @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 { + if (initialMap instanceof HashMap) + return initialMap; + // Replace with TreeMap. Create comparator from binding. HashMap result = new HashMap(); putAll(result, initialMap); diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashSetBinding.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashSetBinding.java index efeb38493..494b3d9e8 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashSetBinding.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/HashSetBinding.java @@ -32,7 +32,7 @@ import org.simantics.databoard.type.RecordType; * * @author Toni Kalajainen */ -@SuppressWarnings("all") +@SuppressWarnings({"rawtypes", "unchecked"}) 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); } - @SuppressWarnings("unchecked") @Override public int count(Object src, Object from, boolean fromInclusive, Object end, boolean endInclusive) throws BindingException { @@ -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 s = (Set) setTo; - Binding kb = getKeyBinding(); for (Entry e : (Set>) from.entrySet()) { Object k = getComparableKey(s, e.getKey()); s.remove(k); diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/TreeSetBinding.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/TreeSetBinding.java index 304b3cad4..50028b3a1 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/TreeSetBinding.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/TreeSetBinding.java @@ -58,12 +58,15 @@ public class TreeSetBinding extends MapBinding { return false; } - @Override - public Object create() throws BindingException { - return new TreeSet( getKeyBinding() ); - } - - public Object create(Set initialSet) throws BindingException { + @Override + public Object create() throws BindingException { + return new TreeSet( getKeyBinding() ); + } + + public Object create(Set initialSet) throws BindingException { + if (initialSet instanceof TreeSet && ((TreeSet) initialSet).comparator() == getKeyBinding()) + return initialSet; + TreeSet result = new TreeSet(getKeyBinding()); result.addAll(initialSet); return result; diff --git a/bundles/org.simantics.diagram.ontology/graph.tg b/bundles/org.simantics.diagram.ontology/graph.tg index eda90ce84..72053ec5b 100644 Binary files a/bundles/org.simantics.diagram.ontology/graph.tg and b/bundles/org.simantics.diagram.ontology/graph.tg differ diff --git a/bundles/org.simantics.diagram.ontology/graph/DiagramProfiles.pgraph b/bundles/org.simantics.diagram.ontology/graph/DiagramProfiles.pgraph index 652ea695b..072bf49d8 100644 --- a/bundles/org.simantics.diagram.ontology/graph/DiagramProfiles.pgraph +++ b/bundles/org.simantics.diagram.ontology/graph/DiagramProfiles.pgraph @@ -79,4 +79,8 @@ DIA.Profile.defaultEnabled DIA.ConfigurableProfile procedure) throws DatabaseException { + DiagramResource DIA = DiagramResource.getInstance(graph); + int count = 0; + for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { + for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) { + if (!flag.equals(otherFlag)) { + if (!procedure.apply(connectionJoin, otherFlag)) + return ++count; + ++count; + } + } + } + return count; + } + /** * Returns all flags that are joined with the given flag including the flag given as parameter. */ diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectTool2.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectTool2.java index 4aaa717d8..71a8d2829 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectTool2.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectTool2.java @@ -25,7 +25,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Deque; -import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -39,12 +38,15 @@ import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.diagram.connection.RouteGraph; import org.simantics.diagram.connection.RouteGraphConnectionClass; +import org.simantics.diagram.connection.RouteLine; import org.simantics.diagram.connection.RouteTerminal; +import org.simantics.diagram.connection.delta.RouteGraphDelta; import org.simantics.diagram.connection.rendering.arrows.PlainLineEndStyle; import org.simantics.diagram.content.ResourceTerminal; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.diagram.synchronization.ISynchronizationContext; import org.simantics.diagram.synchronization.SynchronizationHints; +import org.simantics.diagram.synchronization.graph.RouteGraphConnection; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; import org.simantics.g2d.canvas.impl.DependencyReflection.Reference; @@ -54,6 +56,7 @@ import org.simantics.g2d.connection.IConnectionAdvisor; import org.simantics.g2d.diagram.DiagramHints; import org.simantics.g2d.diagram.DiagramUtils; import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.diagram.handler.PickContext; import org.simantics.g2d.diagram.handler.Topology.Terminal; import org.simantics.g2d.diagram.participant.ElementPainter; import org.simantics.g2d.diagram.participant.TerminalPainter; @@ -70,6 +73,7 @@ import org.simantics.g2d.element.IElementClassProvider; import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd; import org.simantics.g2d.element.handler.SceneGraph; import org.simantics.g2d.element.handler.TerminalTopology; +import org.simantics.g2d.element.handler.impl.BranchPointTerminal; import org.simantics.g2d.element.impl.Element; import org.simantics.g2d.elementclass.BranchPoint; import org.simantics.g2d.elementclass.BranchPoint.Direction; @@ -77,8 +81,8 @@ import org.simantics.g2d.elementclass.FlagClass; import org.simantics.g2d.elementclass.FlagHandler; import org.simantics.g2d.participant.RenderingQualityInteractor; import org.simantics.g2d.participant.TransformUtil; +import org.simantics.g2d.utils.geom.DirectionSet; import org.simantics.modeling.ModelingResources; -import org.simantics.scenegraph.INode; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; import org.simantics.scenegraph.g2d.events.KeyEvent; @@ -101,6 +105,8 @@ import org.simantics.utils.logging.TimeLogger; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.ExceptionUtils; +import gnu.trove.map.hash.THashMap; + /** * A basic tool for making connection on diagrams. * @@ -141,6 +147,9 @@ public class ConnectTool2 extends AbstractMode { @Dependency protected PointerInteractor pi; + @Dependency + protected PickContext pickContext; + /** * Start element terminal of the connection. null if connection * was started from a flag or a branch point. @@ -269,6 +278,8 @@ public class ConnectTool2 extends AbstractMode { protected G2DParentNode endFlagNode; + private RouteGraphTarget lastRouteGraphTarget; + /** * @param startTerminal * @param mouseId @@ -387,9 +398,9 @@ public class ConnectTool2 extends AbstractMode { ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class); pathNode.setColor(new Color(160, 0, 0)); - pathNode.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, - new float[] { 5f, 2f }, 0)); - pathNode.setScaleStroke(true); + pathNode.setStroke(new BasicStroke(0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, + new float[] { 0.5f, 0.2f }, 0)); + pathNode.setScaleStroke(false); pathNode.setZIndex(0); G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class); @@ -443,105 +454,18 @@ public class ConnectTool2 extends AbstractMode { ControlPoint begin = controlPoints.getFirst(); ControlPoint end = controlPoints.getLast(); - + RouteGraph routeGraph = new RouteGraph(); RouteTerminal a = addControlPoint(routeGraph, begin); RouteTerminal b = addControlPoint(routeGraph, end); routeGraph.link(a, b); - - // Route connection segments separately - /*Router2 router = ElementUtils.getHintOrDefault(diagram, DiagramHints.ROUTE_ALGORITHM, TrivialRouter2.INSTANCE); - final List segments = toSegments(controlPoints); - //System.out.println("controlpoints: " + controlPoints); - //System.out.println("segments: " + segments); - router.route(new IConnection() { - @Override - public Collection getSegments() { - return segments; - } - - @Override - public Connector getBegin(Object seg) { - return getConnector(((Segment) seg).begin); - } - - @Override - public Connector getEnd(Object seg) { - return getConnector(((Segment) seg).end); - } - - private Connector getConnector(ControlPoint cp) { - Connector c = new Connector(); - c.x = cp.getPosition().getX(); - c.y = cp.getPosition().getY(); - - TerminalInfo ti = cp.getAttachedTerminal(); - if (ti != null && (ti == startFlag || ti != endFlag)) { - //System.out.println("CP1: " + cp); - c.parentObstacle = DiagramUtils.getObstacleShape(ti.e); - ConnectionDirectionUtil.determineAllowedDirections(c); - } else { - //System.out.println("CP2: " + cp); - c.parentObstacle = GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y), - BranchPointClass.DEFAULT_IMAGE2.getBounds()); - c.allowedDirections = toAllowedDirections(cp.getDirection()); - } - - return c; - } - @Override - public void setPath(Object seg, Path2D path) { - ((Segment) seg).path = (Path2D) path.clone(); - } - - private int toAllowedDirections(BranchPoint.Direction direction) { - switch (direction) { - case Any: - return 0xf; - case Horizontal: - return Constants.EAST_FLAG | Constants.WEST_FLAG; - case Vertical: - return Constants.NORTH_FLAG | Constants.SOUTH_FLAG; - default: - throw new IllegalArgumentException("unrecognized direction: " + direction); - } - } - }); - - // Combine the routed paths - Path2D path = new Path2D.Double(); - for (Segment seg : segments) { - //System.out.println("SEG: " + seg); - if (seg.path != null) - path.append(seg.path.getPathIterator(null), true); - }*/ - Path2D path = routeGraph.getPath2D(); // Create scene graph to visualize the connection. ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class); pathNode.setShape(path); - G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class); - HashSet unusedChildren = new HashSet(points.getNodes()); - int i = 0; - for (ControlPoint cp : controlPoints) { - if (cp.isAttachedToTerminal()) - continue; - - String id = String.valueOf(i); - BranchPointNode bpn = points.getOrCreateNode(id, BranchPointNode.class); - bpn.setDegree(2); - bpn.setDirection((byte) cp.getDirection().ordinal()); - bpn.setTransform(AffineTransform.getTranslateInstance(cp.getPosition().getX(), cp.getPosition().getY())); - - ++i; - unusedChildren.remove(bpn); - } - for (INode unusedChild : unusedChildren) - points.removeNode(unusedChild); - setDirty(); } @@ -668,12 +592,48 @@ public class ConnectTool2 extends AbstractMode { // Make sure that we are ending with a flag if ALT is pressed // and no end terminal is defined. - endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)); - - updateSG(); + if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me))) + updateSG(); return false; } } + } else { + RouteGraphTarget cp = RouteGraphConnectTool.pickRouteGraphConnection( + diagram, + pi.getCanvasPickShape(me.controlPosition), + pi.getPickDistance()); + if (cp != null) { + // Remove branch point highlight from previously picked route graph. + if (lastRouteGraphTarget != null && cp.getNode() != lastRouteGraphTarget.getNode()) + cp.getNode().showBranchPoint(null); + lastRouteGraphTarget = cp; + + // Validate connection before visualizing connectability + Point2D isectPos = cp.getIntersectionPosition(); + TerminalInfo ti = TerminalInfo.create( + isectPos, + cp.getElement(), + BranchPointTerminal.existingTerminal( + isectPos, + DirectionSet.ANY, + BranchPointNode.SHAPE), + BranchPointNode.SHAPE); + Pair canConnect = canConnect(ti.e, ti.t); + if (canConnect != null) { + connectionJudgment = canConnect.first; + controlPoints.getLast().setPosition(ti.posDia).setAttachedToTerminal(ti); + endTerminal = ti; + cp.getNode().showBranchPoint(isectPos); + if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me))) + updateSG(); + return false; + } + } else { + if (lastRouteGraphTarget != null) { + lastRouteGraphTarget.getNode().showBranchPoint(null); + lastRouteGraphTarget = null; + } + } } connectionJudgment = null; @@ -705,9 +665,8 @@ public class ConnectTool2 extends AbstractMode { // Make sure that we are ending with a flag if ALT is pressed and no end // terminal is defined. - endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)); - - updateSG(); + if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me))) + updateSG(); return false; } @@ -729,8 +688,13 @@ public class ConnectTool2 extends AbstractMode { if (snapAdvisor != null) snapAdvisor.snap(mouseCanvasPos); - // Clicked on an allowed end terminal. End connection & end mode. - if (isEndTerminalDefined()) { + if (lastRouteGraphTarget != null) { + lastRouteGraphTarget.getNode().showBranchPoint(null); + attachToConnection(); + remove(); + return true; + } else if (isEndTerminalDefined()) { + // Clicked on an allowed end terminal. End connection & end mode. createConnection(); remove(); return true; @@ -772,6 +736,53 @@ public class ConnectTool2 extends AbstractMode { return false; } + private void attachToConnection() { + ConnectionJudgement judgment = this.connectionJudgment; + if (judgment == null) { + ErrorLogger.defaultLogError("Cannot attach to connection, no judgment available on connection validity", null); + return; + } + + ConnectionBuilder builder = new ConnectionBuilder(this.diagram); + RouteGraph before = lastRouteGraphTarget.getNode().getRouteGraph(); + THashMap copyMap = new THashMap<>(); + RouteGraph after = before.copy(copyMap); + + RouteLine attachTo = (RouteLine) copyMap.get(lastRouteGraphTarget.getLine()); + after.makePersistent(attachTo); + for (RouteLine line : after.getAllLines()) { + if (!line.isTransient() && line.isHorizontal() == attachTo.isHorizontal() + && line.getPosition() == attachTo.getPosition()) { + attachTo = line; + break; + } + } + RouteLine attachToLine = attachTo; + RouteGraphDelta delta = new RouteGraphDelta(before, after); + + Simantics.getSession().asyncRequest(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + graph.markUndoPoint(); + Resource connection = ElementUtils.getObject(endTerminal.e); + if (!delta.isEmpty()) { + new RouteGraphConnection(graph, connection).synchronize(graph, before, after, delta); + } + Resource line = RouteGraphConnection.deserialize(graph, attachToLine.getData()); + Deque cps = new ArrayDeque<>(); + for (Iterator iterator = controlPoints.descendingIterator(); iterator.hasNext();) + cps.add(iterator.next()); + builder.attachToRouteGraph(graph, judgment, connection, line, cps, startTerminal, FlagClass.Type.In); + } + }, new Callback() { + @Override + public void run(DatabaseException parameter) { + if (parameter != null) + ExceptionUtils.logAndShowError(parameter); + } + }); + } + protected boolean cancelPreviousBend() { if (!routePointsAllowed()) return false; @@ -912,10 +923,16 @@ public class ConnectTool2 extends AbstractMode { return endFlag != null; } - protected void endWithoutTerminal(Point2D mousePos, boolean altDown) { + /** + * @param mousePos + * @param altDown + * @return true if updateSG was executed, false + * otherwise + */ + protected boolean endWithoutTerminal(Point2D mousePos, boolean altDown) { // Just go with branch points if flags are not allowed. if (!createFlags) - return; + return false; boolean endTerminalDefined = isEndTerminalDefined(); @@ -931,6 +948,7 @@ public class ConnectTool2 extends AbstractMode { setHint(TerminalPainter.TERMINAL_HOVER_STRATEGY, terminalHoverStrategy); updateSG(); + return true; } } else { if (isEndingInFlag()) { @@ -954,8 +972,10 @@ public class ConnectTool2 extends AbstractMode { setHint(TerminalPainter.TERMINAL_HOVER_STRATEGY, terminalHoverStrategy); updateSG(); + return true; } } + return false; } protected void createConnection() { diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionBuilder.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionBuilder.java index 1fcf074cd..b36961f87 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionBuilder.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionBuilder.java @@ -475,7 +475,8 @@ public class ConnectionBuilder { Resource attachToConnection, Resource attachToLine, Deque controlPoints, - TerminalInfo endTerminal) + TerminalInfo endTerminal, + FlagClass.Type flagType) throws DatabaseException { initializeResources(graph); @@ -502,9 +503,10 @@ public class ConnectionBuilder { if (endTerminal != null) { endConnector = createConnectorForNode(graph, attachToConnection, endTerminal, EdgeEnd.End, judgment); } else if (createFlags) { - IElement endFlag = createFlag(graph, attachToConnection, EdgeEnd.End, controlPoints.getLast(), FlagClass.Type.Out, null); + EdgeEnd end = flagType == FlagClass.Type.In ? EdgeEnd.Begin : EdgeEnd.End; + IElement endFlag = createFlag(graph, attachToConnection, end, controlPoints.getLast(), flagType, null); endConnector = createConnectorForNode(graph, attachToConnection, (Resource) ElementUtils.getObject(endFlag), - ElementUtils.getSingleTerminal(endFlag), EdgeEnd.End, judgment); + ElementUtils.getSingleTerminal(endFlag), end, judgment); } cu.connect(attachToLine, endConnector.getConnector()); diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java index af1f48f5d..57f5cd490 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java @@ -763,7 +763,7 @@ public class RouteGraphConnectTool extends AbstractMode { new RouteGraphConnection(graph, connection).synchronize(graph, rgs.first, rgs.second, rgs.third); } Resource attachToLine = RouteGraphConnection.deserialize(graph, attachedToRouteLine.getData()); - builder.attachToRouteGraph(graph, judgment, connection, attachToLine, controlPoints, endTerminal); + builder.attachToRouteGraph(graph, judgment, connection, attachToLine, controlPoints, endTerminal, FlagClass.Type.Out); } }, new Callback() { @Override diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/Profiles.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/Profiles.java index 9baa067f7..0246143d2 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/Profiles.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/Profiles.java @@ -15,17 +15,28 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; +import org.simantics.db.WriteOnlyGraph; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.common.utils.ListUtils; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.impl.DefaultCopyHandler; +import org.simantics.db.layer0.adapter.impl.DefaultPasteImportAdvisor; +import org.simantics.db.layer0.util.ClipboardUtils; +import org.simantics.db.layer0.util.SimanticsClipboard; +import org.simantics.db.layer0.util.SimanticsClipboardImpl; +import org.simantics.db.layer0.util.SimanticsKeys; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.service.VirtualGraphSupport; import org.simantics.diagram.stubs.DiagramResource; +import org.simantics.graph.db.TransferableGraphs; +import org.simantics.graph.representation.Root; +import org.simantics.graph.representation.TransferableGraph1; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.simulation.ontology.SimulationResource; @@ -201,7 +212,6 @@ public class Profiles { for (Resource r : enabled) { graph.claim(p, SIM.IsActive, r); } - } }); } @@ -255,6 +265,35 @@ public class Profiles { Double priority = graph.getPossibleRelatedValue(entry, DIA.ProfileEntry_HasPriority, Bindings.DOUBLE); if (priority != null) { graph.claimLiteral(instance, DIA.ProfileEntry_HasPriority, priority, Bindings.DOUBLE); + } + for (Resource template : graph.getObjects(entry, DIA.HasTemplate)) { + SimanticsClipboardImpl builder = new SimanticsClipboardImpl(); + DefaultCopyHandler handler = new DefaultCopyHandler(template); + DefaultPasteImportAdvisor advisor = new DefaultPasteImportAdvisor(instance) { + @Override + public Resource createRoot(WriteOnlyGraph graph, Root root, Resource resource) + throws DatabaseException { + Layer0 l0 = graph.getService(Layer0.class); + DiagramResource DIA = graph.getService(DiagramResource.class); + + if(resource == null) resource = graph.newResource(); + + graph.claim(library, DIA.HasTemplate, DIA.HasTemplate_Inverse, resource); + + String newName = getName(root); + graph.addLiteral(resource, l0.HasName, l0.NameOf, l0.String, newName, Bindings.STRING); + + addRootInfo(root, newName, resource); + + return resource; + } + }; + handler.copyToClipboard(graph, builder); + for(Set object : builder.getContents()) { + TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH); + TransferableGraphs.importGraph1(graph, tg, advisor); + } + } return instance; } diff --git a/bundles/org.simantics.document.server.io/src/org/simantics/document/server/io/Content.java b/bundles/org.simantics.document.server.io/src/org/simantics/document/server/io/Content.java index ba933d71c..eb957c8f6 100644 --- a/bundles/org.simantics.document.server.io/src/org/simantics/document/server/io/Content.java +++ b/bundles/org.simantics.document.server.io/src/org/simantics/document/server/io/Content.java @@ -12,23 +12,27 @@ *******************************************************************************/ package org.simantics.document.server.io; +import java.io.InputStream; + public class Content { - private byte[] data; + private InputStream input; private String mimeType; private long lastModified; + private int length; - public Content(byte[] data, String mimeType, long lastModified) { - this.data = data; + public Content(InputStream input, String mimeType, long lastModified, int length) { + this.input = input; this.mimeType = mimeType; this.lastModified = lastModified; + this.length = length; } - public byte[] getData() { - return data; + public InputStream getInputStream() { + return input; } - public void setData(byte[] data) { - this.data = data; + public void setInputStream(InputStream input) { + this.input = input; } public String getMimeType() { @@ -46,4 +50,12 @@ public class Content { public void setLastModified(long lastModified) { this.lastModified = lastModified; } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } } diff --git a/bundles/org.simantics.event/src/org/simantics/event/util/EventUtils.java b/bundles/org.simantics.event/src/org/simantics/event/util/EventUtils.java index bb85be21f..c4b83aa99 100644 --- a/bundles/org.simantics.event/src/org/simantics/event/util/EventUtils.java +++ b/bundles/org.simantics.event/src/org/simantics/event/util/EventUtils.java @@ -1,10 +1,12 @@ package org.simantics.event.util; +import java.util.List; import java.util.UUID; import org.simantics.databoard.Bindings; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.PossibleTypedParent; import org.simantics.db.exception.DatabaseException; import org.simantics.event.ontology.EventResource; import org.simantics.layer0.Layer0; @@ -25,5 +27,46 @@ public class EventUtils { graph.claimLiteral(log, EVENT.HasModificationCounter, 0, Bindings.INTEGER); return log; } - + + /** + * Bumps the modification counter value of the event log of the specified + * events using {@link #bumpModificationCounter(WriteGraph, Resource)}. + *

+ * The code assumes that all events are from the same log. + * + * @param graph + * @param forLogOfEvents + * @throws DatabaseException + */ + public static void bumpModificationCounter(WriteGraph graph, List forLogOfEvents) throws DatabaseException { + EventResource EVENT = EventResource.getInstance(graph); + for (Resource event : forLogOfEvents) { + Resource log = graph.syncRequest(new PossibleTypedParent(event, EVENT.EventLog)); + if (log != null) { + bumpModificationCounter(graph, log); + return; + } + } + } + + /** + * Bumps the modification counter of the specified event log by 1. + * + * @param graph + * @param eventLog + * @return new modification counter value + * @throws DatabaseException + */ + public static int bumpModificationCounter(WriteGraph graph, Resource eventLog) throws DatabaseException { + EventResource EVENT = EventResource.getInstance(graph); + Resource counter = graph.getPossibleObject(eventLog, EVENT.HasModificationCounter); + if (counter != null) { + Integer c = graph.getValue(counter, Bindings.INTEGER); + c = c == null ? 1 : c+1; + graph.claimValue(counter, c, Bindings.INTEGER); + return c; + } + return 0; + } + } diff --git a/bundles/org.simantics.event/src/org/simantics/event/view/contribution/ProjectEventsRule.java b/bundles/org.simantics.event/src/org/simantics/event/view/contribution/ProjectEventsRule.java index e6e59966c..9b9ea8bfe 100644 --- a/bundles/org.simantics.event/src/org/simantics/event/view/contribution/ProjectEventsRule.java +++ b/bundles/org.simantics.event/src/org/simantics/event/view/contribution/ProjectEventsRule.java @@ -116,20 +116,25 @@ public enum ProjectEventsRule implements ChildRule { if (!showHiddenEvents && graph.hasStatement(event, EVENT.Hidden)) continue; + boolean isReturnEvent = hideReturnEvents || showOnlyActiveEvents + ? graph.hasStatement(event, EVENT.ReturnEvent) : false; + + // Skip all return events if thus preferred. + if (hideReturnEvents && isReturnEvent) { + continue; + } + + // Skip all return events and starting events that have been returned, + // if thus preferred. Also skip events that are defined non-returnable. if (showOnlyActiveEvents - && (graph.hasStatement(event, EVENT.Returns) + && (isReturnEvent + || graph.hasStatement(event, EVENT.Returns) || graph.hasStatement(event, EVENT.ReturnedBy) || graph.hasStatement(event, EVENT.NoReturn))) { continue; } - // Skip return events if thus preferred. - if (hideReturnEvents && graph.hasStatement(event, EVENT.ReturnEvent)) { - if (graph.getPossibleObject(event, EVENT.Returns) != null) - continue; - } - // Filter by event type severity Resource eventType = graph.getPossibleObject(event, EVENT.Event_type); if (eventType != null) { 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 index 778c5fb1a..000000000 --- a/bundles/org.simantics.event/src/org/simantics/event/view/handler/Hide.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.event.view.handler; - -import org.simantics.event.ontology.EventResource; - - -/** - * @author Tuukka Lehtonen - */ -public class Hide extends PreferenceHandler { - - public Hide() { - super("experiments", EventResource.URIs.Hidden, true); - } - -} diff --git a/bundles/org.simantics.event/src/org/simantics/event/view/handler/MenuActions.java b/bundles/org.simantics.event/src/org/simantics/event/view/handler/MenuActions.java index ddd70fb7f..9b125ed44 100644 --- a/bundles/org.simantics.event/src/org/simantics/event/view/handler/MenuActions.java +++ b/bundles/org.simantics.event/src/org/simantics/event/view/handler/MenuActions.java @@ -24,6 +24,7 @@ import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.SelectionHints; import org.simantics.event.Activator; import org.simantics.event.ontology.EventResource; +import org.simantics.event.util.EventUtils; import org.simantics.ui.contribution.DynamicMenuContribution; import org.simantics.ui.workbench.action.PerformDefaultAction; import org.simantics.utils.ui.ISelectionUtils; @@ -147,13 +148,17 @@ public class MenuActions extends DynamicMenuContribution { } private IAction hideAction(List input) { - return tagAction("Hide", Activator.HIDE_ICON, EventResource.URIs.Hidden, true, input); + return contentChangingTagAction("Hide", Activator.HIDE_ICON, EventResource.URIs.Hidden, true, input); } private IAction tagAction(String label, ImageDescriptor image, String tagURI, boolean tag, List input) { return new TagAction(label, image, VG_EXPERIMENTS, tagURI, tag, input); } + private IAction contentChangingTagAction(String label, ImageDescriptor image, String tagURI, boolean tag, List input) { + return new ContentChangingTagAction(label, image, VG_EXPERIMENTS, tagURI, tag, input); + } + private IAction setBaseline(Resource eventLog, Resource event) { return new SetBaseline(VG_EXPERIMENTS, eventLog, event); } @@ -169,6 +174,17 @@ public class MenuActions extends DynamicMenuContribution { return new PerformDefaultAction(title, null, input); } + private static class ContentChangingTagAction extends TagAction { + public ContentChangingTagAction(String label, ImageDescriptor image, String virtualGraphId, String tagURI, boolean tag, List input) { + super(label, image, virtualGraphId, tagURI, tag, input); + } + + @Override + public void postTagWrite(WriteGraph graph) throws DatabaseException { + EventUtils.bumpModificationCounter(graph, resources); + } + } + private static class ToClipboardAction extends Action { private String text; diff --git a/bundles/org.simantics.event/src/org/simantics/event/view/handler/TagAction.java b/bundles/org.simantics.event/src/org/simantics/event/view/handler/TagAction.java index 0de441539..3491e29f0 100644 --- a/bundles/org.simantics.event/src/org/simantics/event/view/handler/TagAction.java +++ b/bundles/org.simantics.event/src/org/simantics/event/view/handler/TagAction.java @@ -22,7 +22,7 @@ public class TagAction extends Action { private final String virtualGraphId; private final String tagURI; private final boolean tag; - private final List resources; + protected final List resources; /** * @param label diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/pointertool/TerminalUtil.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/pointertool/TerminalUtil.java index a28cfa563..409af79d6 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/pointertool/TerminalUtil.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/pointertool/TerminalUtil.java @@ -78,6 +78,17 @@ public class TerminalUtil { .append(']'); return sb.toString(); } + + public static TerminalInfo create(Point2D p, IElement e, Terminal t, Shape terminalShape) { + AffineTransform at = AffineTransform.getTranslateInstance(p.getX(), p.getY()); + TerminalInfo ti = new TerminalInfo(); + ti.e = e; + ti.t = t; + ti.posElem = at; + ti.posDia = at; + ti.shape = terminalShape; + return ti; + } } private static final Rectangle2D POINT_PICK_SHAPE = new Rectangle2D.Double(0, 0, 0.001, 0.001); diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/BranchPointTerminal.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/BranchPointTerminal.java index bce157dd5..3ad4a9f75 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/BranchPointTerminal.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/BranchPointTerminal.java @@ -13,6 +13,7 @@ package org.simantics.g2d.element.handler.impl; import java.awt.Shape; import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; import org.simantics.g2d.utils.geom.DirectionSet; @@ -39,4 +40,8 @@ public class BranchPointTerminal extends ObjectTerminal { return new BranchPointTerminal(EXISTING_BRANCH_POINT_DATA, transform, ds, shape); } + public static BranchPointTerminal existingTerminal(Point2D p, DirectionSet ds, Shape shape) { + return existingTerminal(AffineTransform.getTranslateInstance(p.getX(), p.getY()), ds, shape); + } + } \ No newline at end of file diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncActiveModelTypicals.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncActiveModelTypicals.java index bbe8111e5..882e04f0d 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncActiveModelTypicals.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncActiveModelTypicals.java @@ -80,6 +80,7 @@ public class SyncActiveModelTypicals { RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, msg.toString(), activeModelTypicalTemplates); if(result == null) return; + session.markUndoPoint(); SyncTypicalTemplatesToInstances req = new SyncTypicalTemplatesToInstances(result.selectedRules, activeModelTypicalTemplates).logging(result.logging); session.syncRequest(req); if (result.logging) { diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java index 86bfdc0bb..b0d52e355 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalInstanceWithTemplate.java @@ -79,6 +79,7 @@ public class SyncCurrentTypicalInstanceWithTemplate { RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, "Synchronizing typical instance with its template.", new Resource[] { input.getResource() }); if(result == null) return; + session.markUndoPoint(); SyncTypicalTemplatesToInstances req = SyncTypicalTemplatesToInstances.syncSingleInstance(result.selectedRules, input.getResource()).logging(result.logging); session.syncRequest(req); if (result.logging) { diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java index f262cd56e..d3d1de389 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/handlers/e4/SyncCurrentTypicalTemplateToInstances.java @@ -77,6 +77,7 @@ public class SyncCurrentTypicalTemplateToInstances { RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, "Synchronizing typical template to all its instances.", new Resource[] { input.getResource() }); if(result == null) return; + session.markUndoPoint(); SyncTypicalTemplatesToInstances req = new SyncTypicalTemplatesToInstances(result.selectedRules, input.getResource()).logging(result.logging); session.syncRequest(req); if (result.logging) { diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncActiveModelTypicals.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncActiveModelTypicals.java index 5ba8b9f2d..441702dd5 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncActiveModelTypicals.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncActiveModelTypicals.java @@ -80,6 +80,7 @@ public class SyncActiveModelTypicals extends AbstractHandler { RuleChooserDialog.RuleResult result = RuleChooserDialog.choose(shell, msg.toString(), activeModelTypicalTemplates); if(result == null) return null; + session.markUndoPoint(); SyncTypicalTemplatesToInstances req = new SyncTypicalTemplatesToInstances(result.selectedRules, activeModelTypicalTemplates).logging(result.logging); session.syncRequest(req); if (result.logging) { diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalInstanceWithTemplate.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalInstanceWithTemplate.java index df049a671..3b1455f37 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalInstanceWithTemplate.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalInstanceWithTemplate.java @@ -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() }); if(result == null) return null; + session.markUndoPoint(); SyncTypicalTemplatesToInstances req = SyncTypicalTemplatesToInstances.syncSingleInstance(result.selectedRules, input.getResource()).logging(result.logging); session.syncRequest(req); if (result.logging) { diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalTemplateToInstances.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalTemplateToInstances.java index 931e3f7fa..c4454831e 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalTemplateToInstances.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/typicals/SyncCurrentTypicalTemplateToInstances.java @@ -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() }); if(result == null) return null; + session.markUndoPoint(); SyncTypicalTemplatesToInstances req = new SyncTypicalTemplatesToInstances(result.selectedRules, input.getResource()).logging(result.logging); session.syncRequest(req); if (result.logging) { diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java index e1494cf32..709e981bc 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java @@ -2312,6 +2312,7 @@ public class ModelingUtils { String extension = (String)t.get(1); filterNames[index] = filterName; extensions[index] = extension; + index++; } dialog.setFilterExtensions(extensions); diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java index 96a33393a..44b2abcfe 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/SyncTypicalTemplatesToInstances.java @@ -49,6 +49,7 @@ import org.simantics.diagram.handler.CopyPasteStrategy; import org.simantics.diagram.handler.ElementObjectAssortment; import org.simantics.diagram.handler.PasteOperation; import org.simantics.diagram.handler.Paster; +import org.simantics.diagram.handler.Paster.RouteLine; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.diagram.synchronization.CollectingModificationQueue; import org.simantics.diagram.synchronization.CopyAdvisor; @@ -206,9 +207,9 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { */ protected Map copyMap; - final private Map> messageLogs = new HashMap>(); + final private Map> messageLogs = new HashMap<>(); - public List logs = new ArrayList(); + public List logs = new ArrayList<>(); private boolean writeLog; @@ -295,7 +296,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { if(indexRoot == null) throw new DatabaseException("FATAL: Diagram is not under any index root."); List log = messageLogs.get(indexRoot); if(log == null) { - log = new ArrayList(); + log = new ArrayList<>(); messageLogs.put(indexRoot, log); } return log; @@ -331,7 +332,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { this.syncCtx.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph)); this.metadata = new TypicalSynchronizationMetadata(); - this.metadata.synchronizedTypicals = new ArrayList(); + this.metadata.synchronizedTypicals = new ArrayList<>(); this.temporaryDiagram = Diagram.spawnNew(DiagramClass.DEFAULT); this.temporaryDiagram.setHint(SynchronizationHints.CONTEXT, syncCtx); @@ -365,7 +366,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { Collection libs = graph.syncRequest(new ObjectsWithType(indexRoot, L0.ConsistsOf, DOC.DocumentLibrary)); if(libs.isEmpty()) continue; - List nrs = new ArrayList(); + List nrs = new ArrayList<>(); for(Resource lib : libs) nrs.add(new NamedResource(NameUtils.getSafeName(graph, lib), lib)); Collections.sort(nrs, AlphanumComparator.CASE_INSENSITIVE_COMPARATOR); Resource library = nrs.iterator().next().getResource(); @@ -416,7 +417,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { if (instances.isEmpty()) return; - Set templateElements = new THashSet( graph.syncRequest( + Set templateElements = new THashSet<>( graph.syncRequest( new ObjectsWithType(template, L0.ConsistsOf, DIA.Element) ) ); try { @@ -436,7 +437,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { if (template == null) return; - Set templateElements = new THashSet( graph.syncRequest( + Set templateElements = new THashSet<>( graph.syncRequest( new ObjectsWithType(template, L0.ConsistsOf, DIA.Element) ) ); try { @@ -499,7 +500,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { // therefore clone the query result. typicalInfoBean = (TypicalInfoBean) typicalInfoBean.clone(); typicalInfoBean.templateElements = currentTemplateElements; - typicalInfoBean.auxiliary = new HashMap(1); + typicalInfoBean.auxiliary = new HashMap<>(1); TypicalInfo info = new TypicalInfo(); info.monitor = monitor; @@ -523,12 +524,12 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { // instance elements that do not have a MOD.HasElementSource // relation but have a MOD.IsTemplatized tag. Set instanceElementsRemovedFromTemplate = findInstanceElementsRemovedFromTemplate( - graph, info, new THashSet(dSizeAbs)); + graph, info, new THashSet<>(dSizeAbs)); // Find elements in template that do not yet exist in the instance Set templateElementsAddedToTemplate = findTemplateElementsMissingFromInstance( graph, currentTemplateElements, info, - new THashSet(dSizeAbs)); + new THashSet<>(dSizeAbs)); Set changedTemplateElements = changedElementsByDiagram.removeValues(template); @@ -625,7 +626,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { ElementObjectAssortment assortment = new ElementObjectAssortment(graph, elementsAddedToTemplate); if (copyMap == null) - copyMap = new THashMap(); + copyMap = new THashMap<>(); else copyMap.clear(); @@ -666,7 +667,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { ModelingResources MOD = ModelingResources.getInstance(graph); Resource instanceComposite = graph.getPossibleObject(instance, MOD.DiagramToComposite); - List instanceComponents = new ArrayList(elementsAddedToTemplate.size()); + List instanceComponents = new ArrayList<>(elementsAddedToTemplate.size()); // Post-process added elements after typicalInfo has been updated and // template mapping statements are in place. @@ -872,6 +873,17 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { return changed; } + private static class Connector { + public final Resource attachmentRelation; + public final Resource connector; + public RouteLine attachedTo; + + public Connector(Resource attachmentRelation, Resource connector) { + this.attachmentRelation = attachmentRelation; + this.connector = connector; + } + } + /** * Synchronizes two route graph connection topologies if and only if the * destination connection is not attached to any node elements besides @@ -902,19 +914,28 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { cu = new ConnectionUtil(graph); // 0.1. find mappings between source and target connection connectors - Collection targetConnectors = graph.getObjects(targetConnection, DIA.HasConnector); - for (Resource targetConnector : targetConnectors) { + Collection toTargetConnectors = graph.getStatements(targetConnection, DIA.HasConnector); + Map targetConnectors = new THashMap<>(toTargetConnectors.size()); + for (Statement toTargetConnector : toTargetConnectors) { + Resource targetConnector = toTargetConnector.getObject(); + targetConnectors.put(targetConnector, new Connector(toTargetConnector.getPredicate(), targetConnector)); Statement toNode = cu.getConnectedComponentStatement(targetConnection, targetConnector); if (toNode == null) { // Corrupted target connection! - 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")); + ErrorLogger.defaultLogError("Encountered corrupted typical template connection " + + NameUtils.getSafeName(graph, targetConnection, true) + " with a stray DIA.Connector instance " + + NameUtils.getSafeName(graph, targetConnector, true) + " that is not attached to any element.", + new Exception("trace")); return false; } - - // Check that the target connections does not connect to - // non-templatized elements before syncing. - if (!graph.hasStatement(toNode.getObject(), MOD.IsTemplatized)) + if (!graph.hasStatement(targetConnector, DIA.AreConnected)) { + // Corrupted target connection! + ErrorLogger.defaultLogError("Encountered corrupted typical template connection " + + NameUtils.getSafeName(graph, targetConnection, true) + " with a stray DIA.Connector instance " + + NameUtils.getSafeName(graph, targetConnector, true) + " that is not connected to any other route node.", + new Exception("trace")); return false; + } //Resource templateNode = typicalInfo.instanceToTemplate.get(toNode.getObject()); Resource templateNode = graph.getPossibleObject(toNode.getObject(), MOD.HasElementSource); @@ -929,7 +950,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { t2s.put(targetConnector, templateConnector); if (DEBUG) - System.out.println("Mapping connector " + debug(typicalInfo, "Mapping connector " + NameUtils.getSafeName(graph, templateConnector, true) + " to " + NameUtils.getSafeName(graph, targetConnector, true)); } @@ -941,14 +962,17 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { // 0.2. find mapping between source and target route lines Collection sourceInteriorRouteNodes = graph.getObjects(sourceConnection, DIA.HasInteriorRouteNode); Collection targetInteriorRouteNodes = graph.getObjects(targetConnection, DIA.HasInteriorRouteNode); - Map sourceToRouteLine = new THashMap(); - Map targetToRouteLine = new THashMap(); + Map sourceToRouteLine = new THashMap<>(); + Map targetToRouteLine = new THashMap<>(); for (Resource source : sourceInteriorRouteNodes) sourceToRouteLine.put(source, Paster.readRouteLine(graph, source)); for (Resource target : targetInteriorRouteNodes) targetToRouteLine.put(target, Paster.readRouteLine(graph, target)); + Map originalSourceToRouteLine = new THashMap<>(sourceToRouteLine); + Map originalTargetToRouteLine = new THashMap<>(targetToRouteLine); + nextSourceLine: for (Iterator> sourceIt = sourceToRouteLine.entrySet().iterator(); !targetToRouteLine.isEmpty() && sourceIt.hasNext();) { Map.Entry sourceEntry = sourceIt.next(); @@ -962,7 +986,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { targetIt.remove(); if (DEBUG) - System.out.println("Mapping routeline " + debug(typicalInfo, "Mapping routeline " + NameUtils.getSafeName(graph, sourceEntry.getKey(), true) + " - " + sourceEntry.getValue() + " to " + NameUtils.getSafeName(graph, targetEntry.getKey(), true) @@ -974,20 +998,40 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { } if (DEBUG) { - System.out.println("Take 1: Source to target route nodes map : " + s2t); - System.out.println("Take 1: Target to source route nodes map : " + t2s); + debug(typicalInfo, "Take 1: Source to target route nodes map : " + s2t); + debug(typicalInfo, "Take 1: Target to source route nodes map : " + t2s); } - // 1.1 remove excess connectors - for (Resource targetConnector : targetConnectors) { - if (!t2s.containsKey(targetConnector)) { - typicalInfo.messageLog.add("\t\t\tremove excess connector from target connection: " + NameUtils.getSafeName(graph, targetConnector)); - cu.removeConnectionPart(targetConnector); - changed = true; + // 1.1. Temporarily disconnect instance-specific connectors from the the connection . + // They will be added back to the connection after the templatized parts of the + // connection have been synchronized. + + // Stores diagram connectors that are customizations in the synchronized instance. + List instanceOnlyConnectors = null; + + for (Connector connector : targetConnectors.values()) { + if (!t2s.containsKey(connector.connector)) { + typicalInfo.messageLog.add("\t\tencountered instance-specific diagram connector in target connection: " + NameUtils.getSafeName(graph, connector.connector)); + + // Find the RouteLine this connectors is connected to. + for (Resource rl : graph.getObjects(connector.connector, DIA.AreConnected)) { + connector.attachedTo = originalTargetToRouteLine.get(rl); + if (connector.attachedTo != null) + break; + } + + // Disconnect connector from connection + graph.deny(targetConnection, connector.attachmentRelation, connector.connector); + graph.deny(connector.connector, DIA.AreConnected); + + // Keep track of the disconnected connector + if (instanceOnlyConnectors == null) + instanceOnlyConnectors = new ArrayList<>(targetConnectors.size()); + instanceOnlyConnectors.add(connector); } } - // 1.2 add missing connectors to target + // 1.2. add missing connectors to target Collection sourceConnectors = graph.getObjects(sourceConnection, DIA.HasConnector); for (Resource sourceConnector : sourceConnectors) { if (!s2t.containsKey(sourceConnector)) { @@ -1017,7 +1061,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { // 2. sync route lines and their connectivity: // 2.1. assign correspondences in target for each source route line - // by reusing excess routelines in target and by creating new + // by reusing excess route lines in target and by creating new // route lines. Resource[] targetRouteLines = targetToRouteLine.keySet().toArray(Resource.NONE); @@ -1028,7 +1072,7 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { Resource source = sourceEntry.getKey(); Paster.RouteLine sourceLine = sourceEntry.getValue(); - typicalInfo.messageLog.add("\t\t\tassign an instance-side routeline complement for " + NameUtils.getSafeName(graph, source, true) + " - " + sourceLine); + typicalInfo.messageLog.add("\t\t\tassign an instance-side routeline counterpart for " + NameUtils.getSafeName(graph, source, true) + " - " + sourceLine); // Assign target route line for source Resource target = null; @@ -1052,16 +1096,16 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { } if (targetRouteLine >= 0) { - typicalInfo.messageLog.add("\t\t\tremove excess route lines (" + (targetRouteLine + 1) + ") from target connection"); + typicalInfo.messageLog.add("\t\t\tremove excess route lines (" + (targetRouteLine + 1) + ") from target connection"); for (; targetRouteLine >= 0; targetRouteLine--) { - typicalInfo.messageLog.add("\t\t\t\tremove excess route line: " + NameUtils.getSafeName(graph, targetRouteLines[targetRouteLine], true)); + typicalInfo.messageLog.add("\t\t\t\tremove excess route line: " + NameUtils.getSafeName(graph, targetRouteLines[targetRouteLine], true)); cu.removeConnectionPart(targetRouteLines[targetRouteLine]); } } if (DEBUG) { - System.out.println("Take 2: Source to target route nodes map : " + s2t); - System.out.println("Take 2: Target to source route nodes map : " + t2s); + debug(typicalInfo, "Take 2: Source to target route nodes map : " + s2t); + debug(typicalInfo, "Take 2: Target to source route nodes map : " + t2s); } // 2.2. Synchronize target connection topology (DIA.AreConnected) @@ -1072,9 +1116,100 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { changed |= cu.removeExtraInteriorRouteNodes(targetConnection) > 0; changed |= cu.removeUnusedConnectors(targetConnection) > 0; + // 3.1. Ensure that all mapped route nodes in the target connection + // are tagged with MOD.IsTemplatized. Future synchronization + // can then take advantage of this information to more easily + // decide which parts of the connection are originated from + // the template and which are not. + changed |= markMappedRouteNodesTemplatized(graph, s2t.values()); + + // 4. Add temporarily disconnected instance-specific connectors + // back to the synchronized connection. The route line to attach + // to is based on a simple heuristic. + if (instanceOnlyConnectors != null) { + if (originalSourceToRouteLine.isEmpty()) { + // If there are 0 route lines in the template connection, + // then one must be added to the instance connection. + // This can only happen if the template connection is + // simple, i.e. just between two terminals without any + // custom routing. + + // Attach all target connection connectors to the newly created route line + Resource rl = cu.newRouteLine(targetConnection, null, null); + for (Resource sourceConnector : sourceConnectors) { + Resource targetConnector = s2t.get(sourceConnector); + graph.deny(targetConnector, DIA.AreConnected); + graph.claim(targetConnector, DIA.AreConnected, DIA.AreConnected, rl); + } + + // Copy orientation and position for new route line from original target route lines. + // This is a simplification that will attach any amount of route lines in the original + // target connection into just one route line. There is room for improvement here + // but it will require a more elaborate algorithm to find and cut the non-templatized + // route lines as well as connectors out of the connection before synchronizing it. + // + // TODO: This implementation chooses the added route line position at random if + // there are multiple route lines in the target connection. + if (!originalTargetToRouteLine.isEmpty()) { + RouteLine originalRl = originalTargetToRouteLine.values().iterator().next(); + setRouteLine(graph, rl, originalRl); + } + + // Attach the instance specific connectors also to the only route line + for (Connector connector : instanceOnlyConnectors) { + graph.claim(targetConnection, connector.attachmentRelation, connector.connector); + graph.claim(connector.connector, DIA.AreConnected, DIA.AreConnected, rl); + } + + changed = true; + } else { + for (Connector connector : instanceOnlyConnectors) { + // Find the route line that most closely matches the original + // route line that the connector was connected to. + Resource closestMatch = null; + double closestDistance = Double.MAX_VALUE; + if (connector.attachedTo != null) { + for (Map.Entry sourceLine : originalSourceToRouteLine.entrySet()) { + double dist = distance(sourceLine.getValue(), connector.attachedTo); + if (dist < closestDistance) { + closestMatch = s2t.get(sourceLine.getKey()); + closestDistance = dist; + } + } + } else { + closestMatch = originalSourceToRouteLine.keySet().iterator().next(); + } + graph.claim(targetConnection, connector.attachmentRelation, connector.connector); + graph.claim(connector.connector, DIA.AreConnected, DIA.AreConnected, closestMatch); + if (closestDistance > 0) + changed = true; + typicalInfo.messageLog.add("\t\t\treattached instance-specific connector " + + NameUtils.getSafeName(graph, connector.connector) + " to nearest existing route line " + + NameUtils.getSafeName(graph, closestMatch) + " with distance " + closestDistance); + } + } + } + return changed; } + private boolean markMappedRouteNodesTemplatized(WriteGraph graph, Iterable routeNodes) throws DatabaseException { + boolean changed = false; + for (Resource rn : routeNodes) { + if (!graph.hasStatement(rn, MOD.IsTemplatized)) { + graph.claim(rn, MOD.IsTemplatized, MOD.IsTemplatized, rn); + changed = true; + } + } + return changed; + } + + private static double distance(RouteLine l1, RouteLine l2) { + double dist = Math.abs(l2.getPosition() - l1.getPosition()); + dist *= l2.isHorizontal() == l1.isHorizontal() ? 1 : 1000; + return dist; + } + private boolean connectRouteNodes(WriteGraph graph, TypicalInfo typicalInfo, Collection sourceRouteNodes) throws DatabaseException { boolean changed = false; for (Resource src : sourceRouteNodes) { @@ -1115,6 +1250,15 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { return changed; } + private void setRouteLine(WriteGraph graph, Resource line, double position, boolean horizontal) throws DatabaseException { + graph.claimLiteral(line, DIA.HasPosition, L0.Double, position, Bindings.DOUBLE); + graph.claimLiteral(line, DIA.IsHorizontal, L0.Boolean, horizontal, Bindings.BOOLEAN); + } + + private void setRouteLine(WriteGraph graph, Resource line, RouteLine rl) throws DatabaseException { + setRouteLine(graph, line, rl.getPosition(), rl.isHorizontal()); + } + private void copyRouteLine(WriteGraph graph, Resource src, Resource tgt) throws DatabaseException { Double pos = graph.getPossibleRelatedValue(src, DIA.HasPosition, Bindings.DOUBLE); Boolean hor = graph.getPossibleRelatedValue(src, DIA.IsHorizontal, Bindings.BOOLEAN); @@ -1143,9 +1287,16 @@ public class SyncTypicalTemplatesToInstances extends WriteRequest { private static Map newOrClear(Map current) { if (current == null) - return new THashMap(); + return new THashMap<>(); current.clear(); return current; } + private void debug(TypicalInfo typicalInfo, String message) { + if (DEBUG) { + System.out.println(message); + typicalInfo.messageLog.add(message); + } + } + } \ No newline at end of file diff --git a/bundles/org.simantics.scenegraph/.classpath b/bundles/org.simantics.scenegraph/.classpath index de670af55..47085403c 100644 --- a/bundles/org.simantics.scenegraph/.classpath +++ b/bundles/org.simantics.scenegraph/.classpath @@ -1,5 +1,8 @@ + + + diff --git a/bundles/org.simantics.scenegraph/META-INF/MANIFEST.MF b/bundles/org.simantics.scenegraph/META-INF/MANIFEST.MF index 80ef76d7c..dad71c00d 100644 --- a/bundles/org.simantics.scenegraph/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.scenegraph/META-INF/MANIFEST.MF @@ -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, diff --git a/bundles/org.simantics.scenegraph/build.properties b/bundles/org.simantics.scenegraph/build.properties index 03f349f6c..3dca05bdf 100644 --- a/bundles/org.simantics.scenegraph/build.properties +++ b/bundles/org.simantics.scenegraph/build.properties @@ -17,4 +17,8 @@ bin.includes = META-INF/,\ TROVE-README-license.txt,\ TROVE-LICENSE.txt,\ README.txt,\ - JSI-LICENSE.txt \ No newline at end of file + JSI-LICENSE.txt,\ + lib/batik-parser-1.8.jar,\ + lib/batik-awt-util-1.8.jar,\ + lib/batik-util-1.8.jar + 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 index 000000000..ce0be3cd0 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 index 000000000..01108ad7c 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 index 000000000..cb1c63f19 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 index 000000000..cc44d372a --- /dev/null +++ b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/ActionShapes.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2016 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.scenegraph.g2d.nodes.connection; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.StringReader; + +import org.apache.batik.parser.AWTPathProducer; +import org.apache.batik.parser.ParseException; + +/** + * @author Tuukka Lehtonen + * @since 1.22.2, 1.25.0 + */ +class ActionShapes { + + 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"; + + 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"; + + static Shape parsePath(String path, AffineTransform xform) { + try { + Shape s = AWTPathProducer.createShape(new StringReader(path), PathIterator.WIND_EVEN_ODD); + return xform != null ? xform.createTransformedShape(s) : s; + } catch (ParseException | IOException e) { + // Should not happen + throw new Error(e); + } + } + + static Shape transformShape(Shape shape, double scaleX, double scaleY, double offsetX, double offsetY, double rotate) { + AffineTransform tr = new AffineTransform(); + tr.translate(offsetX, offsetY); + tr.scale(scaleX, scaleY); + if (rotate != 0) + tr.rotate(rotate); + return tr.createTransformedShape(shape); + } + + public static final Shape SCISSOR_SHAPE = parsePath(SCISSOR_PATH, null); + public static final Shape CROSS_SHAPE = parsePath(CROSS_PATH, null); + + private static final Rectangle2D SCISSOR_BOUNDS = SCISSOR_SHAPE.getBounds2D(); + private static final Rectangle2D CROSS_BOUNDS = CROSS_SHAPE.getBounds2D(); + + public static final double SCISSOR_WIDTH = SCISSOR_BOUNDS.getWidth(); + public static final double SCISSOR_HEIGHT = SCISSOR_BOUNDS.getHeight(); + + public static final double CROSS_WIDTH = CROSS_BOUNDS.getWidth(); + public static final double CROSS_HEIGHT = CROSS_BOUNDS.getHeight(); + +} diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java index 04d08e3ec..7f7bd3cd9 100644 --- a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java +++ b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java @@ -13,23 +13,23 @@ package org.simantics.scenegraph.g2d.nodes.connection; import java.awt.AlphaComposite; import java.awt.BasicStroke; +import java.awt.Color; import java.awt.Composite; import java.awt.Graphics2D; +import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.net.URL; import java.util.ArrayList; import java.util.Collection; -import javax.imageio.ImageIO; - import org.simantics.diagram.connection.RouteGraph; import org.simantics.diagram.connection.RouteLineHalf; import org.simantics.diagram.connection.actions.IAction; import org.simantics.diagram.connection.rendering.IRouteGraphRenderer; +import org.simantics.scenegraph.utils.Quality; +import org.simantics.scenegraph.utils.QualityHints; /** * @author Tuukka Lehtonen @@ -67,26 +67,25 @@ public class HighlightActionPointsAction implements IAction { } } - static BufferedImage cross; - static BufferedImage cut; + private static final Shape CROSS_SHAPE = ActionShapes.CROSS_SHAPE; + private static final Shape SCISSOR_SHAPE = ActionShapes.transformShape(ActionShapes.SCISSOR_SHAPE, 1, 1, 0, 0, -Math.PI/2); - static { - cross = safeReadImage("cross.png"); - cut = safeReadImage("cut.png"); - } + private static final Color CROSS_COLOR = new Color(0xe4, 0x40, 0x61); + private static final Color SCISSOR_COLOR = new Color(20, 20, 20); public static final Stroke STROKE = new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); - public static final AlphaComposite COMPOSITE = AlphaComposite.SrcOver.derive(0.6f); + public static final AlphaComposite NO_HIT_COMPOSITE = AlphaComposite.SrcOver.derive(0.8f); + public static final AlphaComposite HIT_COMPOSITE = AlphaComposite.SrcOver.derive(0.2f); public static final double DEGENERATED_LINE_LENGTH = 1; - public static final double CUT_DIST_FROM_END = 0.5; + public static final double CUT_DIST_FROM_END = 0.75; RouteGraph rg; transient Collection lhs = new ArrayList(); transient AffineTransform transform = new AffineTransform(); - transient AffineTransform transform2 = new AffineTransform(); transient Rectangle2D rect = new Rectangle2D.Double(); + transient Point2D point = new Point2D.Double(); public HighlightActionPointsAction(RouteGraph rg) { this.rg = rg; @@ -98,94 +97,73 @@ public class HighlightActionPointsAction implements IAction { @Override public void render(Graphics2D g, IRouteGraphRenderer renderer, double mouseX, double mouseY) { - // Cannot perform cut or delete segment actions on connections between 2 - // terminals. + // Cannot perform cut or delete segment actions + // on connections between 2 terminals. boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2); boolean branchedConnection = rg.getTerminals().size() > 2; + if (!branchedConnection || simpleConnection) + return; + + AffineTransform preTr = g.getTransform(); + double realViewScale = 1.0 / getScale(preTr); + //System.out.println(realViewScale); + // Don't render any of the actions if they could not be seen anyway. + if (realViewScale > 0.7) + return; lhs.clear(); rg.getLineHalves(lhs); - AffineTransform preTr = g.getTransform(); - double viewScale = 1.0 / getScale(preTr); - transform2.setToScale(viewScale, viewScale); + Pick pick = pickAction(rg, lhs, preTr, mouseX, mouseY); + Composite originalComposite = g.getComposite(); - g.setComposite(COMPOSITE); + Composite basicComposite = pick.action != null ? HIT_COMPOSITE : NO_HIT_COMPOSITE; + g.setComposite(basicComposite); - Pick pick = pickAction(rg, lhs, preTr, mouseX, mouseY); + // Always render these in high quality because otherwise the shapes + // will render with ugly artifacts when zoom level is a bit higher. + QualityHints origQualityHints = QualityHints.getQuality(g); + QualityHints.getHints(Quality.HIGH).setQuality(g); + // Render line removal markers if (!simpleConnection) { - double crossW = cross.getWidth()*viewScale*.5; - double crossH = cross.getHeight()*viewScale*.5; - - // Render line removal markers + g.setPaint(CROSS_COLOR); for (RouteLineHalf lh : lhs) { -// if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH) -// continue; -// if (!lh.getLine().isTransient()) -// continue; - if (lh.getLine().getTerminal() == null) + if (removeLocation(lh, point) == null) continue; - double x = lh.getLink().getX(); - double y = lh.getLink().getY(); - if (lh.getLine().isHorizontal()) { - x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5; - } else { - y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5; - } - boolean hit = pick.matches(Action.REMOVE, lh); - if (hit) g.setComposite(originalComposite); - transform.setToTranslation(x-crossW, y-crossH); - g.transform(transform); - g.drawImage(cross, transform2, null); + g.translate(point.getX(), point.getY()); + g.fill(CROSS_SHAPE); g.setTransform(preTr); if (hit) - g.setComposite(COMPOSITE); + g.setComposite(basicComposite); } } // Render reconnection markers if the connection is branched. if (branchedConnection) { - double cutW = cut.getWidth()*viewScale*.5; - double cutH = cut.getHeight()*viewScale*.5; - - final double dist = CUT_DIST_FROM_END; + g.setPaint(SCISSOR_COLOR); for (RouteLineHalf lh : lhs) { - if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3) + if (reconnectLocation(lh, point) == null) continue; - double x = lh.getLink().getX(); - double y = lh.getLink().getY(); - if (lh.getLine().isHorizontal()) { - if (lh.getLink() == lh.getLine().getBegin()) - x += dist*2; - else - x -= dist*2; - } else { - if (lh.getLink() == lh.getLine().getBegin()) - y += dist*2; - else - y -= dist*2; - } - boolean hit = pick.matches(Action.RECONNECT, lh); - if (hit) g.setComposite(originalComposite); - transform.setToTranslation(x-cutW, y-cutH); - if (!lh.getLine().isHorizontal()) { - transform.rotate(Math.PI/2, cutW, cutH); - } + transform.setToTranslation(point.getX(), point.getY()); + if (!lh.getLine().isHorizontal()) + transform.rotate(Math.PI/2); + transform.translate(0, 0.35); g.transform(transform); - g.drawImage(cut, transform2, null); + g.fill(SCISSOR_SHAPE); g.setTransform(preTr); if (hit) - g.setComposite(COMPOSITE); + g.setComposite(basicComposite); } } + origQualityHints.setQuality(g); g.setComposite(originalComposite); } @@ -205,35 +183,23 @@ public class HighlightActionPointsAction implements IAction { if (!branchedConnection || simpleConnection || viewTr == null) return Pick.MISS; - lhs.clear(); - rg.getLineHalves(lhs); + double viewScale = 1.0 / getScale(viewTr); + if (viewScale > 0.7) + return Pick.MISS; + double nearest = Double.MAX_VALUE; RouteLineHalf selected = null; Action selectedAction = null; - double nearest = Double.MAX_VALUE; - double viewScale = 1.0 / getScale(viewTr); + // Pick line removal markers if (!simpleConnection) { - double crossW = cross.getWidth()*viewScale*.5; - double crossH = cross.getHeight()*viewScale*.5; - - // Render line removal markers + double s = ActionShapes.CROSS_WIDTH * 0.25; for (RouteLineHalf lh : lhs) { -// if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH) -// continue; -// if (!lh.getLine().isTransient()) -// continue; - if (lh.getLine().getTerminal() == null) + if (removeLocation(lh, point) == null) continue; - double x = lh.getLink().getX(); - double y = lh.getLink().getY(); - if (lh.getLine().isHorizontal()) { - x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5; - } else { - y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5; - } - - rect.setFrameFromCenter(x, y, x-crossW, y-crossH); + double x = point.getX(); + double y = point.getY(); + rect.setFrameFromCenter(x, y, x-s, y-s); boolean hit = rect.contains(mouseX, mouseY); if (hit) { double distSq = distSq(x, y, mouseX, mouseY); @@ -246,35 +212,21 @@ public class HighlightActionPointsAction implements IAction { } } - // Render reconnection markers if the connection is branched. + // Pick reconnection markers if the connection is branched. if (branchedConnection) { - double cutW = cut.getWidth()*viewScale*.5; - double cutH = cut.getHeight()*viewScale*.5; - - final double dist = CUT_DIST_FROM_END; + double w = ActionShapes.SCISSOR_HEIGHT * 0.4; + double h = ActionShapes.SCISSOR_WIDTH * 0.3; for (RouteLineHalf lh : lhs) { - if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3) + if (reconnectLocation(lh, point) == null) continue; - double x = lh.getLink().getX(); - double y = lh.getLink().getY(); - if (lh.getLine().isHorizontal()) { - if (lh.getLink() == lh.getLine().getBegin()) - x += dist*2; - else - x -= dist*2; - } else { - if (lh.getLink() == lh.getLine().getBegin()) - y += dist*2; - else - y -= dist*2; - } - - rect.setFrameFromCenter(x, y, x-cutW, y-cutH); + double x = point.getX(); + double y = point.getY(); + rect.setFrameFromCenter(x, y, x-w, y-h); boolean hit = rect.contains(mouseX, mouseY); if (hit) { double distSq = distSq(x, y, mouseX, mouseY); if (distSq < nearest) { - nearest = dist; + nearest = distSq; selected = lh; selectedAction = Action.RECONNECT; } @@ -285,6 +237,43 @@ public class HighlightActionPointsAction implements IAction { return selected == null ? Pick.MISS : new Pick(selectedAction, selected); } + private static Point2D removeLocation(RouteLineHalf lh, Point2D p) { + if (lh.getLine().getTerminal() == null) + return null; + + double x = lh.getLink().getX(); + double y = lh.getLink().getY(); + if (lh.getLine().isHorizontal()) { + x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5; + } else { + y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5; + } + p.setLocation(x, y); + return p; + } + + private static Point2D reconnectLocation(RouteLineHalf lh, Point2D p) { + if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3) + return null; + + final double dist = CUT_DIST_FROM_END; + double x = lh.getLink().getX(); + double y = lh.getLink().getY(); + if (lh.getLine().isHorizontal()) { + if (lh.getLink() == lh.getLine().getBegin()) + x += dist*2; + else + x -= dist*2; + } else { + if (lh.getLink() == lh.getLine().getBegin()) + y += dist*2; + else + y -= dist*2; + } + p.setLocation(x, y); + return p; + } + private static double distSq(double x1, double y1, double x2, double y2) { double dx = x2 - x1; double dy = y2 - y1; @@ -301,13 +290,4 @@ public class HighlightActionPointsAction implements IAction { return Math.sqrt(Math.abs(m00*m11 - m10*m01)); } - private static BufferedImage safeReadImage(String name) { - try { - URL url = HighlightActionPointsAction.class.getResource(name); - return ImageIO.read(url); - } catch (IOException e) { - return null; - } - } - } diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/RouteGraphNode.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/RouteGraphNode.java index 34b1a635d..e231476ac 100644 --- a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/RouteGraphNode.java +++ b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/RouteGraphNode.java @@ -11,8 +11,6 @@ *******************************************************************************/ package org.simantics.scenegraph.g2d.nodes.connection; -import gnu.trove.map.hash.THashMap; - import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; @@ -31,7 +29,6 @@ import java.util.Map; import org.simantics.diagram.connection.RouteGraph; import org.simantics.diagram.connection.RouteLine; import org.simantics.diagram.connection.RouteLink; -import org.simantics.diagram.connection.RoutePoint; import org.simantics.diagram.connection.RouteTerminal; import org.simantics.diagram.connection.actions.IAction; import org.simantics.diagram.connection.actions.IReconnectAction; @@ -69,6 +66,8 @@ import org.simantics.scenegraph.utils.GeometryUtils; import org.simantics.scenegraph.utils.InitValueSupport; import org.simantics.scenegraph.utils.NodeUtil; +import gnu.trove.map.hash.THashMap; + /** * @author Tuukka Lehtonen */ @@ -312,6 +311,10 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In } } + public void showBranchPoint(Point2D p) { + newBranchPointPosition = p; + } + @Override public void init() { super.init(); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/JavaMathOperation.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/JavaMathOperation.java index e13c18563..caf212a61 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/JavaMathOperation.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/JavaMathOperation.java @@ -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); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/java/JavaModule.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/java/JavaModule.java index 39c2dbec6..cb39346e4 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/java/JavaModule.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/java/JavaModule.java @@ -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, diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/elaboration/constraints/ReduceSerializable.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/elaboration/constraints/ReduceSerializable.java index ea0276e35..3b7ef9d1c 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/elaboration/constraints/ReduceSerializable.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/elaboration/constraints/ReduceSerializable.java @@ -98,8 +98,8 @@ public class ReduceSerializable { private static final THashMap BINDING_CONSTANTS2 = new THashMap(); static { - 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))); - 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))); + 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))); + 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))); } public static Reduction reduceSerializable(Type parameter) { diff --git a/bundles/org.simantics.scl.db/scl/Simantics/DB.scl b/bundles/org.simantics.scl.db/scl/Simantics/DB.scl index 023960678..74bc42204 100644 --- a/bundles/org.simantics.scl.db/scl/Simantics/DB.scl +++ b/bundles/org.simantics.scl.db/scl/Simantics/DB.scl @@ -11,31 +11,6 @@ effect WriteGraph "graph" "org.simantics.db.WriteGraph" -importJava "org.simantics.databoard.type.Datatype" where - data Datatype - @JavaName toString - showDatatype :: Datatype -> String - -instance Show Datatype where - show = showDatatype - -importJava "org.simantics.databoard.Bindings" where - @JavaName getBinding - datatypeBinding :: Datatype -> Binding Dynamic - -importJava "org.simantics.databoard.binding.mutable.Variant" where - @JavaName "" - createVariant_ :: Binding Dynamic -> Dynamic -> Variant - @JavaName "type" - variantDatatype :: Variant -> Datatype - -createVariant :: Datatype -> Dynamic -> Variant -createVariant dt v = createVariant_ (datatypeBinding dt) v - -importJava "org.simantics.databoard.Datatypes" where - @JavaName translate - translateDatatype :: String -> Datatype - importJava "org.simantics.db.Resource" where "A resource is a node in a semantic graph." data Resource diff --git a/bundles/org.simantics.scl.runtime/scl/Databoard.scl b/bundles/org.simantics.scl.runtime/scl/Databoard.scl new file mode 100644 index 000000000..f81376621 --- /dev/null +++ b/bundles/org.simantics.scl.runtime/scl/Databoard.scl @@ -0,0 +1,279 @@ +import "Prelude" +import "Random" + +/// Datatype /// + +"A data type component with component name and data type" +@JavaType "org.simantics.databoard.type.Component" +@FieldNames [name, "type"] +data DatatypeComponent = DatatypeComponent String Datatype + +"""A data type that represents the data types supported by the Simantics +Databoard plugin.""" +@JavaType "org.simantics.databoard.type.Datatype" +data Datatype = + @JavaType "org.simantics.databoard.type.BooleanType" + BooleanType + | @JavaType "org.simantics.databoard.type.ByteType" + ByteType + | @JavaType "org.simantics.databoard.type.IntegerType" + IntegerType + | @JavaType "org.simantics.databoard.type.LongType" + LongType + | @JavaType "org.simantics.databoard.type.FloatType" + FloatType + | @JavaType "org.simantics.databoard.type.DoubleType" + DoubleType + | @JavaType "org.simantics.databoard.type.StringType" + StringType + | @JavaType "org.simantics.databoard.type.ArrayType" + @FieldNames [componentType] + ArrayType Datatype + | @JavaType "org.simantics.databoard.type.OptionalType" + @FieldNames [componentType] + OptionalType Datatype + | @JavaType "org.simantics.databoard.type.MapType" + @FieldNames [keyType, valueType] + MapType Datatype Datatype + | @JavaType "org.simantics.databoard.type.RecordType" + @FieldNames [components] + RecordType (Vector DatatypeComponent) + | @JavaType "org.simantics.databoard.type.UntionType" + @FieldNames [components] + UnionType (Vector DatatypeComponent) + | @JavaType "org.simantics.databoard.type.VariantType" + VariantType + +importJava "org.simantics.databoard.type.Datatype" where + @private + @JavaName toString + showDatatype :: Datatype -> String + + "Get the number of type components in an data type" + @JavaName getComponentCount + datatypeCompnentCount :: Datatype -> Integer + + "Get a component type of a composite data type" + @JavaName getComponentType + datatypeComponentType :: Datatype -> ChildReference -> Datatype + + @private + @JavaName equals + datatypeEquals :: Datatype -> Datatype -> Boolean + +instance Show Datatype where + show = showDatatype + +instance Eq Datatype where + (==) = datatypeEquals + +/// Binding /// + +importJava "org.simantics.databoard.binding.Binding" where + "Check whether a dynamic object is an instance of a given binding" + @JavaName isInstance + isBindingInstance :: Binding Dynamic -> Dynamic -> Boolean + + "Create a serializable object from a textual representation" + parseValueDefinition :: Serializable a => String -> a + + "Compare two serializable objects\n\nResult is -1, 0 or 1 depending the partial ordering of the objects." + @JavaName compare + compareObjects :: Serializable a => a -> a -> Integer + + "Return true, if two serializable values are equal" + @JavaName equals + serializableEq :: Serializable a => a -> a -> Boolean + + "The default value of a serializable type" + @JavaName createDefault + serializableDefaultValue :: Serializable a => a + + "Create a random value of a serializable type" + @JavaName createRandom + serializableRandomValue :: Serializable a => a + + "Get a textual representation of a serializable value" + @JavaName toString + showSerializable :: Serializable a => a -> String + + @private + @JavaName getComponent + getSerializableComponent_ :: Serializable a => a -> ChildReference -> Binding b -> b + + "Get a component binding" + @JavaName getComponentBinding + getComponentBinding :: Binding a -> ChildReference -> Binding b + + @private + @JavaName equals + bindingEquals :: Binding a -> Binding a -> Boolean + +instance Eq (Binding a) where + (==) = bindingEquals + +"Get a child data component of a composite serializable value" +getSerializableComponent :: Serializable a => Serializable b => a -> ChildReference -> b +getSerializableComponent object ref = getSerializableComponent_ object ref binding + +/// Serializer /// + +importJava "org.simantics.databoard.serialization.Serializer" where + "A data serializer for SCL type a" + 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 + + "Adapt between types using explicitly provided binding objects: `adapt_ value from to`" + @JavaName adapt + adapt_ :: a -> Binding a -> Binding b -> b + +"Adapt value from one serializable type to another" +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 using default serializer." +serialize :: Serializable a => a -> ByteArray +serialize v = serialize_ (serializerOf binding) v + +"Deserializes a value from a byte array using default serializer." +deserialize :: Serializable a => ByteArray -> a +deserialize ba = deserialize_ (serializerOf binding) ba + +importJava "org.simantics.databoard.Bindings" where + "Get a default binding for a given data type" + @JavaName getBinding + datatypeBinding :: Datatype -> Binding Dynamic + +importJava "org.simantics.databoard.Datatypes" where + "Get a data type from a string representation" + @JavaName translate + translateDatatype :: String -> Datatype + +importJava "org.simantics.databoard.binding.mutable.Variant" where + // data Variant (in Builtins) + "Create a variant using an explicitly provided binding value (unchecked cast)" + @JavaName "" + createVariant_ :: Binding Dynamic -> Dynamic -> Variant + + "Get the data type of a variant object" + @JavaName "type" + variantDatatype :: Variant -> Datatype + + "Get raw value contained by a variant (unchecked cast)" + @JavaName getValue + rawVariantValue :: Variant -> a + + "Create a variant from a raw object (based on Java class)" + @JavaName ofInstance + variantOf :: a -> Variant + + "Create a variant with explicitly provided binding and value" + @JavaName "" + variant_ :: Binding a -> a -> Variant + + "Get value from a variant using a given binding" + @JavaName getValue + variantValue_ :: Variant -> Binding a -> a + + @private + @JavaName toString + showVariant :: Variant -> String + + "Get a component of compound data value in a variant" + @JavaName getComponent + variantComponent :: Variant -> ChildReference -> Variant + +"Create a variant of a given data type from an object in the default binding (unchecked, use with extreme caution)" +createVariant :: Datatype -> Dynamic -> Variant +createVariant dt v = createVariant_ (datatypeBinding dt) v + +"Create a variant from a serializable value" +variant :: Serializable a => a -> Variant +variant v = variant_ binding v + +"Get the value of a variant in a serializable type" +variantValue :: Serializable a => Variant -> a +variantValue v = variantValue_ v binding + +instance Show Variant where + show = showVariant + +"Get an element of a compound variant value using an index reference" +variantElement :: Serializable a => Variant -> Integer -> a +variantElement v i = variantValue (variantComponent v (indexReference i)) + +importJava "org.simantics.databoard.accessor.reference.ChildReference" where + "A reference to a child element in a composite data type/binding or value" + data ChildReference + + "Combine a list of child data object references into a single path reference" + @JavaName compile + compileReference :: [ChildReference] -> ChildReference + +importJava "org.simantics.databoard.accessor.reference.IndexReference" where + """Get a reference to a child data object using an index (zero-based) +* Element index of an array object +* Field index of a record or union type +* 0: + * Key component of a map type/binding + * Component of any single-component type/binding (optional, array) + * Contained value/type of any single-element object (optional, union, variant) +* 1: + * Value component of a map type/binding + """ + @JavaName "" + indexReference :: Integer -> ChildReference + +importJava "org.simantics.databoard.accessor.reference.KeyReference" where + """Get a reference to a MapType child data object using a given key value +* Contained value of a map object for a given key value + """ + @JavaName "" + keyReference :: Variant -> ChildReference + +importJava "org.simantics.databoard.accessor.reference.NameReference" where + """Get a reference to a child data object using a field name +* A component name of a record or union data type/binding +* "key": The key component of a map data type/binding +* "value": The value component of a map data type/binding + """ + @JavaName "" + nameReference :: String -> ChildReference + +importJava "org.simantics.databoard.accessor.reference.LabelReference" where + """Get a reference to a child data object using a label +* A component name of a record or union data type/binding +* A string representation of the index of a record or union data type/binding component +* "v": The component type of an array/optional data type/binding +* "0"/"key": The key component of a map data type/binding +* "1"/"value": The value component of a map data type/binding + """ + @JavaName "" + labelReference :: String -> ChildReference + +importJava "org.simantics.databoard.accessor.reference.ComponentReference" where + """Get a reference to a component child data object +* Component of an array/optional data type/binding +* Contained value of an optional/variant/union object + """ + @JavaName "" + componentReference :: ChildReference diff --git a/bundles/org.simantics.scl.runtime/scl/Prelude.scl b/bundles/org.simantics.scl.runtime/scl/Prelude.scl index 4c20c99b5..6966b4489 100644 --- a/bundles/org.simantics.scl.runtime/scl/Prelude.scl +++ b/bundles/org.simantics.scl.runtime/scl/Prelude.scl @@ -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 - @JavaName "" - variantOfWithBinding :: Binding a -> a -> Variant - @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 "" - indexReference :: Integer -> ChildReference - -importJava "org.simantics.databoard.accessor.reference.KeyReference" where - @JavaName "" - keyReference :: Variant -> ChildReference - -importJava "org.simantics.databoard.accessor.reference.NameReference" where - @JavaName "" - nameReference :: String -> ChildReference - -importJava "org.simantics.databoard.accessor.reference.LabelReference" where - @JavaName "" - labelReference :: String -> ChildReference - // Type @private diff --git a/bundles/org.simantics.scl.runtime/scl/StandardLibrary.scl b/bundles/org.simantics.scl.runtime/scl/StandardLibrary.scl index 76ecece9c..122fcd02b 100644 --- a/bundles/org.simantics.scl.runtime/scl/StandardLibrary.scl +++ b/bundles/org.simantics.scl.runtime/scl/StandardLibrary.scl @@ -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 diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java index a45edf0ee..c79602c1b 100644 --- a/bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java @@ -199,6 +199,8 @@ public class StandardModelingRules extends AbstractModelingRules { boolean legal = true; for (Resource constraint : g.getObjects(connectionType, STR.HasConnectionConstraint)) { IConnectionConstraint cc = g.adapt(constraint, IConnectionConstraint.class); + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println("Checking " + cc.getClass().getSimpleName()); switch(cc.isLegal(g, terminals)) { case ILLEGAL: if(Policy.DEBUG_STANDARD_MODELING_RULES)