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