-package org.simantics.modeling.ui.componentTypeEditor;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-\r
-import org.eclipse.jface.dialogs.IDialogSettings;\r
-import org.eclipse.jface.layout.GridDataFactory;\r
-import org.eclipse.jface.layout.GridLayoutFactory;\r
-import org.eclipse.jface.layout.TableColumnLayout;\r
-import org.eclipse.jface.resource.ImageDescriptor;\r
-import org.eclipse.jface.viewers.ColumnWeightData;\r
-import org.eclipse.jface.window.Window;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.custom.TableEditor;\r
-import org.eclipse.swt.events.DisposeEvent;\r
-import org.eclipse.swt.events.DisposeListener;\r
-import org.eclipse.swt.events.MouseAdapter;\r
-import org.eclipse.swt.events.MouseEvent;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.graphics.Rectangle;\r
-import org.eclipse.swt.layout.FillLayout;\r
-import org.eclipse.swt.widgets.Button;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.swt.widgets.Table;\r
-import org.eclipse.swt.widgets.TableColumn;\r
-import org.eclipse.swt.widgets.TableItem;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.eclipse.ui.forms.widgets.Form;\r
-import org.eclipse.ui.forms.widgets.FormToolkit;\r
-import org.eclipse.ui.forms.widgets.Section;\r
-import org.simantics.Simantics;\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.common.CommentMetadata;\r
-import org.simantics.db.common.request.ObjectsWithType;\r
-import org.simantics.db.common.request.PossibleIndexRoot;\r
-import org.simantics.db.common.request.UniqueRead;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.adapter.CopyHandler2;\r
-import org.simantics.db.layer0.adapter.Instances;\r
-import org.simantics.db.layer0.util.Layer0Utils;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.db.layer0.variable.Variables;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.modeling.ui.Activator;\r
-import org.simantics.modeling.ui.componentTypeEditor.LiftPropertiesDialog.LiftedProperty;\r
-import org.simantics.modeling.userComponent.ComponentTypeCommands;\r
-import org.simantics.selectionview.SelectionViewResources;\r
-import org.simantics.structural.stubs.StructuralResource2;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-public class ConfigurationPropertiesSection implements ComponentTypeViewerSection {\r
-\r
- private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationPropertiesSection.class);\r
- \r
- private static final String[] COLUMN_NAMES = \r
- new String[] {"Name", "Type", "Default Value", "Unit", "Range", "Label", "Description"};\r
- private static final int[] COLUMN_LENGTHS =\r
- new int[] { 120, 100, 100, 50, 100, 100, 100 };\r
- private static final int[] COLUMN_WEIGHTS =\r
- new int[] { 0, 0, 0, 0, 0, 50, 100 };\r
-\r
- /**\r
- * Configuration property table column indexes that are to be considered\r
- * immutable when the property relation is immutable. Note that relation\r
- * immutability does not make the asserted default value immutable.\r
- */\r
- private static final int[] IMMUTABLE_COLUMNS_WITH_IMMUTABLE_RELATION =\r
- { 0, 1, 3, 4, 5, 6 };\r
- \r
- ComponentTypeViewerData data;\r
- Table table;\r
- TableColumn[] columns;\r
- TableEditor editor;\r
- Button newProperty;\r
- Button removeProperty;\r
- Button liftProperties;\r
-\r
- boolean hasTypes = false;\r
- Button setTypes;\r
- \r
- Section section;\r
- \r
- public ConfigurationPropertiesSection(ComponentTypeViewerData data) {\r
- this.data = data;\r
- FormToolkit tk = data.tk;\r
- Form form = data.form;\r
- \r
- section = tk.createSection(form.getBody(), Section.TITLE_BAR | Section.EXPANDED);\r
- section.setLayout(new FillLayout());\r
- section.setText("Configuration properties");\r
-\r
- Composite sectionBody = tk.createComposite(section);\r
- GridLayoutFactory.fillDefaults().numColumns(2).applyTo(sectionBody);\r
- section.setClient(sectionBody);\r
-\r
- Composite tableComposite = tk.createComposite(sectionBody);\r
- GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tableComposite);\r
- TableColumnLayout tcl = new TableColumnLayout();\r
- tableComposite.setLayout(tcl);\r
-\r
- table = tk.createTable(tableComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);\r
- table.setLinesVisible(true);\r
- table.setHeaderVisible(true);\r
-\r
- columns = new TableColumn[COLUMN_NAMES.length];\r
- for(int i=0;i<COLUMN_NAMES.length;++i) {\r
- TableColumn column = new TableColumn(table, SWT.NONE);\r
- columns[i] = column;\r
- tcl.setColumnData(column, new ColumnWeightData(COLUMN_WEIGHTS[i], COLUMN_LENGTHS[i], true));\r
- column.setText(COLUMN_NAMES[i]);\r
- }\r
-\r
- // Table editor\r
- editor = new TableEditor(table);\r
- editor.grabHorizontal = true;\r
- editor.grabVertical = true;\r
- editor.horizontalAlignment = SWT.LEFT;\r
- table.addMouseListener(new MouseAdapter() {\r
- @Override\r
- public void mouseDown(MouseEvent e) {\r
- // Clean up any previous editor control\r
- Control oldEditor = editor.getEditor();\r
- if (oldEditor != null) oldEditor.dispose();\r
-\r
- if (data.readOnly)\r
- return;\r
-\r
- // Relative position\r
- Rectangle tableBounds = table.getClientArea();\r
- int rx = e.x - tableBounds.x;\r
- int ry = e.y - tableBounds.y;\r
-\r
- // Find cell\r
- TableItem selectedItem = null;\r
- int selectedColumn = -1;\r
- Rectangle selectedItemBounds = null;\r
- for(TableItem item : table.getItems()) {\r
- for(int column = 0;column < COLUMN_NAMES.length;++column) {\r
- Rectangle bounds = item.getBounds(column);\r
- if(bounds.contains(rx, ry)) {\r
- selectedItemBounds = bounds;\r
- selectedItem = item;\r
- selectedColumn = column;\r
- break;\r
- }\r
- }\r
- }\r
- if(selectedItem == null) {\r
- return;\r
- }\r
-\r
- // Table editor\r
- final int column = selectedColumn; \r
- final ComponentTypeViewerPropertyInfo propertyInfo = (ComponentTypeViewerPropertyInfo)selectedItem.getData();\r
- final Resource resource = propertyInfo.resource;\r
- switch (column) {\r
- case 0:\r
- data.editName(table, editor, propertyInfo, selectedItem, column, ComponentTypeViewerData.PROPERTY_NAME_PATTERN);\r
- break;\r
-\r
- case 1:\r
- data.editType(table, editor, propertyInfo, selectedItem, column, true);\r
- break;\r
-\r
- case 2: {\r
- data.editValue(table, editor, propertyInfo, selectedItem, column, data.readOnly ? null : new StringWriter() {\r
- @Override\r
- public void perform(WriteGraph graph, String newValue) throws DatabaseException {\r
- graph.markUndoPoint();\r
- ComponentTypeCommands.setDefaultValue(graph, data.componentType, propertyInfo.resource, newValue);\r
- }\r
- }, null);\r
- } break;\r
-\r
- case 3:\r
- data.editUnit(table, editor, propertyInfo, selectedItem, column);\r
- break;\r
-\r
- case 4:\r
- data.editRange(table, editor, propertyInfo, selectedItem, selectedItemBounds, column);\r
- break;\r
-\r
- case 5:\r
- data.editValue(table, editor, propertyInfo, selectedItem, column, propertyInfo.immutable ? null : new StringWriter() {\r
- @Override\r
- public void perform(WriteGraph graph, String newValue) throws DatabaseException {\r
- graph.markUndoPoint();\r
- String value = newValue.isEmpty() ? null : newValue;\r
- ComponentTypeCommands.setLabel(graph, resource, value);\r
- }\r
- }, null);\r
- break;\r
-\r
- case 6:\r
- data.editMultilineText(table, editor, propertyInfo, selectedItem, selectedItemBounds, column, new StringWriter() {\r
- @Override\r
- public void perform(WriteGraph graph, String newValue) throws DatabaseException {\r
- graph.markUndoPoint();\r
- String value = newValue.isEmpty() ? null : newValue;\r
- ComponentTypeCommands.setDescription(graph, resource, value);\r
- }\r
- });\r
- break;\r
- }\r
- }\r
- });\r
-\r
- // Buttons\r
-\r
- Composite buttons = tk.createComposite(sectionBody);\r
- GridDataFactory.fillDefaults().applyTo(buttons);\r
- GridLayoutFactory.fillDefaults().applyTo(buttons);\r
-\r
- newProperty = tk.createButton(buttons, "New property", SWT.PUSH);\r
- GridDataFactory.fillDefaults().applyTo(newProperty);\r
- removeProperty = tk.createButton(buttons, "Remove property", SWT.PUSH);\r
- GridDataFactory.fillDefaults().applyTo(removeProperty);\r
-\r
- liftProperties = tk.createButton(buttons, "Lift Properties", SWT.PUSH);\r
- GridDataFactory.fillDefaults().applyTo(liftProperties);\r
-\r
- hasTypes = !getTypes().isEmpty();\r
- \r
- if(hasTypes) {\r
- setTypes = tk.createButton(buttons, "Assign Types", SWT.PUSH);\r
- GridDataFactory.fillDefaults().applyTo(setTypes);\r
- }\r
-\r
- // Actions\r
-\r
- table.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- TableItem[] sel = table.getSelection();\r
- for (TableItem item : sel) {\r
- ComponentTypeViewerPropertyInfo pi = (ComponentTypeViewerPropertyInfo) item.getData();\r
- if (pi.immutable) {\r
- removeProperty.setEnabled(false);\r
- return;\r
- }\r
- }\r
- removeProperty.setEnabled(true);\r
- }\r
- });\r
-\r
- newProperty.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- if(editor.getEditor() != null)\r
- editor.getEditor().dispose();\r
- Simantics.getSession().async(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph graph)\r
- throws DatabaseException {\r
- ComponentTypeCommands.createPropertyWithDefaults(graph, data.componentType);\r
- }\r
- });\r
- }\r
- });\r
-\r
- removeProperty.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- if(editor.getEditor() != null)\r
- editor.getEditor().dispose();\r
- final List<Resource> propertiesToBeRemoved = \r
- new ArrayList<>();\r
- for(TableItem item : table.getSelection()) {\r
- ComponentTypeViewerPropertyInfo info = (ComponentTypeViewerPropertyInfo) item.getData();\r
- if (!info.immutable)\r
- propertiesToBeRemoved.add(info.resource);\r
- }\r
- System.out.println("remove " + propertiesToBeRemoved.size() + " resources");\r
- if(!propertiesToBeRemoved.isEmpty())\r
- Simantics.getSession().async(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph graph)\r
- throws DatabaseException {\r
- graph.markUndoPoint();\r
- for(Resource property : propertiesToBeRemoved)\r
- ComponentTypeCommands.removeProperty(graph, data.componentType, property);\r
- }\r
- });\r
- }\r
- });\r
- \r
- liftProperties.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- \r
- if(editor.getEditor() != null)\r
- editor.getEditor().dispose();\r
-\r
- try {\r
- \r
- Map<LiftedProperty, Pair<String, ImageDescriptor>> map = Simantics.sync(new UniqueRead<Map<LiftedProperty,Pair<String,ImageDescriptor>>>() {\r
- \r
- @Override\r
- public Map<LiftedProperty, Pair<String, ImageDescriptor>> perform(ReadGraph graph) throws DatabaseException {\r
- \r
- Map<LiftedProperty, Pair<String,ImageDescriptor>> map = new HashMap<>(); \r
- \r
- Layer0 L0 = Layer0.getInstance(graph);\r
- StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
- SelectionViewResources SEL = SelectionViewResources.getInstance(graph);\r
- \r
- Resource composite = graph.getPossibleObject(data.componentType, STR.IsDefinedBy);\r
- if(composite == null) return map;\r
-\r
-\r
- Set<String> existing = new HashSet<>();\r
- for(Resource predicate : graph.getObjects(data.componentType, L0.DomainOf)) {\r
- if(graph.isSubrelationOf(predicate, L0.HasProperty)) {\r
- existing.add(NameUtils.getSafeName(graph, predicate));\r
- }\r
- }\r
- \r
- for(Resource component : graph.syncRequest(new ObjectsWithType(composite, L0.ConsistsOf, STR.Component))) {\r
- \r
- Resource type = graph.getPossibleType(component, STR.Component);\r
- if(type == null) continue;\r
- \r
- String componentName = NameUtils.getSafeName(graph, component);\r
- \r
- for(Resource predicate : graph.getPredicates(component)) {\r
- if(graph.isSubrelationOf(predicate, L0.HasProperty)) {\r
- \r
- // Do not list properties shown under other properties\r
- if(graph.hasStatement(predicate, SEL.IsShownUnder)) continue;\r
- \r
- // Do not list properties that are not visible in selection view\r
- if(!graph.hasStatement(predicate, SEL.HasStandardPropertyInfo)) continue;\r
- \r
- // Some properties are explicitly marked as non-liftable\r
- Boolean canBeLifted = graph.getPossibleRelatedValue(predicate, SEL.canBeLifted, Bindings.BOOLEAN);\r
- if(canBeLifted != null && !canBeLifted) continue;\r
- \r
- String predicateName = NameUtils.getSafeName(graph, predicate);\r
- if(existing.contains(predicateName)) continue;\r
- \r
- String name = componentName + " " + predicateName;\r
- map.put(new LiftedProperty(component, type, predicate), new Pair<String, ImageDescriptor>(name, null));\r
- \r
- }\r
- }\r
- \r
- }\r
- \r
- return map;\r
- \r
- }\r
- \r
- });\r
- \r
- Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();\r
- LiftPropertiesDialog dialog = new LiftPropertiesDialog(shell, map, "Select properties to lift") {\r
- @Override\r
- protected IDialogSettings getBaseDialogSettings() {\r
- return Activator.getDefault().getDialogSettings();\r
- }\r
- };\r
- if (dialog.open() == Window.OK) {\r
- final Collection<LiftedProperty> _result = dialog.getResultT();\r
- final boolean mapProperties = dialog.getMapProperties();\r
- if (!_result.isEmpty()) {\r
- Simantics.getSession().async(new WriteRequest() {\r
- public Resource findAssertion(ReadGraph graph, Resource sourceType, Resource predicate) throws DatabaseException {\r
- Collection<Resource> ass = graph.getAssertedObjects(sourceType, predicate);\r
- if(ass.size() == 1) return ass.iterator().next();\r
- return null;\r
- }\r
- \r
- public void processSubs(ReadGraph graph, Resource predicate, Resource component, Resource componentType, List<LiftedProperty> result, List<Resource> properties, List<Resource> assertions) throws DatabaseException {\r
- SelectionViewResources SEL = SelectionViewResources.getInstance(graph);\r
- for(Resource sub : graph.getObjects(predicate, SEL.UnderOf)) {\r
- Resource ass = findAssertion(graph, componentType, sub);\r
- if(ass == null) continue;\r
- result.add(new LiftedProperty(component, componentType, sub));\r
- properties.add(sub);\r
- assertions.add(ass);\r
- processSubs(graph, sub, component, componentType, result, properties, assertions);\r
- }\r
- }\r
- \r
- @Override\r
- public void perform(WriteGraph graph) throws DatabaseException {\r
- \r
- Layer0 L0 = Layer0.getInstance(graph);\r
- graph.markUndoPoint();\r
- List<Resource> properties = new ArrayList<>();\r
- List<Resource> assertions = new ArrayList<>();\r
- \r
- List<LiftedProperty> result = new ArrayList<>(); \r
- for(LiftedProperty p : _result) {\r
- Resource ass = findAssertion(graph, p.getComponentType(), p.getPredicate());\r
- if(ass == null) continue;\r
- result.add(p);\r
- properties.add(p.getPredicate());\r
- assertions.add(ass);\r
- processSubs(graph, p.getPredicate(), p.getComponent(), p.getComponentType(), result, properties, assertions);\r
- }\r
- \r
- CopyHandler2 ch = Layer0Utils.getPossibleCopyHandler(graph, properties);\r
- Collection<Resource> copies = Layer0Utils.copyTo(graph, data.componentType, null, ch, null);\r
- int index = 0;\r
- for(Resource copy : copies) {\r
- Resource ass = assertions.get(index);\r
- LiftedProperty p = result.get(index);\r
- Collection<Resource> copyAss = Layer0Utils.copyTo(graph, null, ass);\r
- if(copyAss.size() == 1) {\r
- graph.claim(data.componentType, L0.DomainOf, copy);\r
- Layer0Utils.assert_(graph, data.componentType, copy, copyAss.iterator().next());\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Lifted property " + NameUtils.getSafeName(graph, copy) + " into "+ NameUtils.getSafeName(graph, data.componentType)));\r
- }\r
- if(mapProperties) {\r
- Variable v = Variables.getVariable(graph, p.getComponent());\r
- Variable property = v.getProperty(graph, p.getPredicate());\r
- Variable displayValue = property.getProperty(graph, Variables.DISPLAY_VALUE);\r
- displayValue.setValue(graph, "=" + NameUtils.getSafeName(graph, p.getPredicate()), Bindings.STRING);\r
- }\r
- index++;\r
- }\r
- \r
- }\r
- });\r
- }\r
- }\r
-\r
- } catch (DatabaseException e1) {\r
- \r
- LOGGER.error("Lifting properties failed", e1);\r
- return;\r
- \r
- }\r
- \r
- }\r
- });\r
-\r
- if(hasTypes) {\r
- \r
- setTypes.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- if(editor.getEditor() != null)\r
- editor.getEditor().dispose();\r
- final List<Resource> propertiesToSet = \r
- new ArrayList<>();\r
- for(TableItem item : table.getSelection())\r
- propertiesToSet.add(((ComponentTypeViewerPropertyInfo)item.getData()).resource);\r
- \r
- if(propertiesToSet.size() != 1) return;\r
-\r
- Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();\r
- SetTypesDialog page = new SetTypesDialog(shell, getTypes(), "Select user types for property");\r
- if (page.open() == Window.OK) {\r
- final Object[] result = page.getResult();\r
- if (result != null && result.length > 0) {\r
- Simantics.getSession().async(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph graph)\r
- throws DatabaseException {\r
- for(Object type : result) {\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- graph.claim(propertiesToSet.get(0), L0.InstanceOf, null, (Resource)type);\r
- }\r
- }\r
- });\r
- }\r
- }\r
- \r
- }\r
- });\r
- \r
- }\r
-\r
- table.addDisposeListener(new DisposeListener() {\r
- @Override\r
- public void widgetDisposed(DisposeEvent e) {\r
- tk.dispose();\r
- }\r
- });\r
- }\r
-\r
- public void update(ComponentTypePropertiesResult result) {\r
- if (table.isDisposed())\r
- return;\r
- \r
- // Save old selection\r
- Set<ComponentTypeViewerPropertyInfo> selected = new HashSet<>();\r
- List<TableItem> selectedItems = new ArrayList<>(selected.size());\r
- for (int i : table.getSelectionIndices()) {\r
- TableItem item = table.getItem(i);\r
- selected.add((ComponentTypeViewerPropertyInfo) item.getData());\r
- }\r
-\r
- int topIndex = table.getTopIndex();\r
-\r
- table.removeAll();\r
-\r
- if(editor.getEditor() != null)\r
- editor.getEditor().dispose();\r
-\r
- for(ComponentTypeViewerPropertyInfo info : result.getProperties()) {\r
- boolean immutable = result.isImmutable() || info.immutable;\r
- Color fg = immutable ? table.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY) : null;\r
- if(info.sectionSpecificData != null)\r
- continue;\r
-\r
- TableItem item = new TableItem(table, SWT.NONE);\r
-\r
- item.setText(0, info.name);\r
- item.setText(1, info.type);\r
- item.setText(2, info.defaultValue);\r
- item.setText(3, unitStr(info));\r
- item.setText(4, rangeStr(info));\r
- item.setText(5, info.label);\r
- item.setText(6, info.description);\r
-\r
- for (int columnIndex : IMMUTABLE_COLUMNS_WITH_IMMUTABLE_RELATION)\r
- item.setForeground(columnIndex, fg);\r
-\r
- item.setData(info);\r
-\r
- if (selected.contains(info))\r
- selectedItems.add(item);\r
- }\r
-\r
- // Restore old selection\r
- table.setTopIndex(topIndex);\r
- table.setSelection(selectedItems.toArray(new TableItem[selectedItems.size()]));\r
- table.redraw();\r
- }\r
- \r
- private Map<Resource, Pair<String, ImageDescriptor>> getTypes() {\r
- try {\r
- return Simantics.getSession().syncRequest(new UniqueRead<Map<Resource, Pair<String, ImageDescriptor>>>() {\r
- @Override\r
- public Map<Resource, Pair<String, ImageDescriptor>> perform(ReadGraph graph)\r
- throws DatabaseException {\r
- StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
- Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(data.componentType));\r
- Instances query = graph.adapt(STR.UserDefinedProperty, Instances.class);\r
- Collection<Resource> types = query.find(graph, indexRoot);\r
- Map<Resource, Pair<String, ImageDescriptor>> result = new HashMap<>();\r
- for(Resource type : types) {\r
- String name = NameUtils.getSafeLabel(graph, type);\r
- result.put(type, new Pair<String, ImageDescriptor>(name, null));\r
- }\r
- return result;\r
- }\r
- });\r
- } catch (DatabaseException e) {\r
- LOGGER.error("Finding UserDefinedProperties failed.", e);\r
- return Collections.emptyMap();\r
- }\r
- }\r
-\r
- private String unitStr(ComponentTypeViewerPropertyInfo info) {\r
- String unit = info.numberType == null ? null : info.numberType.getUnit();\r
- if (unit == null)\r
- unit = info.unit;\r
- return unit != null ? unit : "";\r
- }\r
-\r
- private String rangeStr(ComponentTypeViewerPropertyInfo info) {\r
- String range = info.numberType == null ? null : info.numberType.getRangeStr();\r
- return range != null ? range : "";\r
- }\r
- \r
- @Override\r
- public void setReadOnly(boolean readOnly) {\r
- boolean e = !readOnly;\r
- newProperty.setEnabled(e);\r
- removeProperty.setEnabled(e);\r
- liftProperties.setEnabled(e);\r
- }\r
- \r
- @Override\r
- public Section getSection() {\r
- return section;\r
- }\r
-\r
- @Override\r
- public double getPriority() {\r
- return 0;\r
- }\r
-\r
- @Override\r
- public Object getSectionSpecificData(ReadGraph graph,\r
- ComponentTypeViewerPropertyInfo info) throws DatabaseException {\r
- return null;\r
- }\r
-\r
- @Override\r
- public double getDataPriority() {\r
- return 0.0;\r
- }\r
-}\r
+package org.simantics.modeling.ui.componentTypeEditor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.widgets.Form;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Section;
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.CommentMetadata;
+import org.simantics.db.common.request.ObjectsWithType;
+import org.simantics.db.common.request.PossibleIndexRoot;
+import org.simantics.db.common.request.UniqueRead;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.adapter.CopyHandler2;
+import org.simantics.db.layer0.adapter.Instances;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.ui.Activator;
+import org.simantics.modeling.ui.componentTypeEditor.LiftPropertiesDialog.LiftedProperty;
+import org.simantics.modeling.userComponent.ComponentTypeCommands;
+import org.simantics.selectionview.SelectionViewResources;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.utils.datastructures.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigurationPropertiesSection implements ComponentTypeViewerSection {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationPropertiesSection.class);
+
+ private static final String[] COLUMN_NAMES =
+ new String[] {"Name", "Type", "Default Value", "Unit", "Range", "Label", "Description"};
+ private static final int[] COLUMN_LENGTHS =
+ new int[] { 120, 100, 100, 50, 100, 100, 100 };
+ private static final int[] COLUMN_WEIGHTS =
+ new int[] { 0, 0, 0, 0, 0, 50, 100 };
+
+ /**
+ * Configuration property table column indexes that are to be considered
+ * immutable when the property relation is immutable. Note that relation
+ * immutability does not make the asserted default value immutable.
+ */
+ private static final int[] IMMUTABLE_COLUMNS_WITH_IMMUTABLE_RELATION =
+ { 0, 1, 3, 4, 5, 6 };
+
+ ComponentTypeViewerData data;
+ Table table;
+ TableColumn[] columns;
+ TableEditor editor;
+ Button newProperty;
+ Button removeProperty;
+ Button liftProperties;
+
+ boolean hasTypes = false;
+ Button setTypes;
+
+ Section section;
+
+ public ConfigurationPropertiesSection(ComponentTypeViewerData data) {
+ this.data = data;
+ FormToolkit tk = data.tk;
+ Form form = data.form;
+
+ section = tk.createSection(form.getBody(), Section.TITLE_BAR | Section.EXPANDED);
+ section.setLayout(new FillLayout());
+ section.setText("Configuration properties");
+
+ Composite sectionBody = tk.createComposite(section);
+ GridLayoutFactory.fillDefaults().numColumns(2).applyTo(sectionBody);
+ section.setClient(sectionBody);
+
+ Composite tableComposite = tk.createComposite(sectionBody);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tableComposite);
+ TableColumnLayout tcl = new TableColumnLayout();
+ tableComposite.setLayout(tcl);
+
+ table = tk.createTable(tableComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);
+ table.setLinesVisible(true);
+ table.setHeaderVisible(true);
+
+ columns = new TableColumn[COLUMN_NAMES.length];
+ for(int i=0;i<COLUMN_NAMES.length;++i) {
+ TableColumn column = new TableColumn(table, SWT.NONE);
+ columns[i] = column;
+ tcl.setColumnData(column, new ColumnWeightData(COLUMN_WEIGHTS[i], COLUMN_LENGTHS[i], true));
+ column.setText(COLUMN_NAMES[i]);
+ }
+
+ // Table editor
+ editor = new TableEditor(table);
+ editor.grabHorizontal = true;
+ editor.grabVertical = true;
+ editor.horizontalAlignment = SWT.LEFT;
+ table.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent e) {
+ // Clean up any previous editor control
+ Control oldEditor = editor.getEditor();
+ if (oldEditor != null) oldEditor.dispose();
+
+ if (data.readOnly)
+ return;
+
+ // Relative position
+ Rectangle tableBounds = table.getClientArea();
+ int rx = e.x - tableBounds.x;
+ int ry = e.y - tableBounds.y;
+
+ // Find cell
+ TableItem selectedItem = null;
+ int selectedColumn = -1;
+ Rectangle selectedItemBounds = null;
+ for(TableItem item : table.getItems()) {
+ for(int column = 0;column < COLUMN_NAMES.length;++column) {
+ Rectangle bounds = item.getBounds(column);
+ if(bounds.contains(rx, ry)) {
+ selectedItemBounds = bounds;
+ selectedItem = item;
+ selectedColumn = column;
+ break;
+ }
+ }
+ }
+ if(selectedItem == null) {
+ return;
+ }
+
+ // Table editor
+ final int column = selectedColumn;
+ final ComponentTypeViewerPropertyInfo propertyInfo = (ComponentTypeViewerPropertyInfo)selectedItem.getData();
+ final Resource resource = propertyInfo.resource;
+ switch (column) {
+ case 0:
+ data.editName(table, editor, propertyInfo, selectedItem, column, ComponentTypeViewerData.PROPERTY_NAME_PATTERN);
+ break;
+
+ case 1:
+ data.editType(table, editor, propertyInfo, selectedItem, column, true);
+ break;
+
+ case 2: {
+ data.editValue(table, editor, propertyInfo, selectedItem, column, data.readOnly ? null : new StringWriter() {
+ @Override
+ public void perform(WriteGraph graph, String newValue) throws DatabaseException {
+ graph.markUndoPoint();
+ ComponentTypeCommands.setDefaultValue(graph, data.componentType, propertyInfo.resource, newValue);
+ }
+ }, null);
+ } break;
+
+ case 3:
+ data.editUnit(table, editor, propertyInfo, selectedItem, column);
+ break;
+
+ case 4:
+ data.editRange(table, editor, propertyInfo, selectedItem, selectedItemBounds, column);
+ break;
+
+ case 5:
+ data.editValue(table, editor, propertyInfo, selectedItem, column, propertyInfo.immutable ? null : new StringWriter() {
+ @Override
+ public void perform(WriteGraph graph, String newValue) throws DatabaseException {
+ graph.markUndoPoint();
+ String value = newValue.isEmpty() ? null : newValue;
+ ComponentTypeCommands.setLabel(graph, resource, value);
+ }
+ }, null);
+ break;
+
+ case 6:
+ data.editMultilineText(table, editor, propertyInfo, selectedItem, selectedItemBounds, column, new StringWriter() {
+ @Override
+ public void perform(WriteGraph graph, String newValue) throws DatabaseException {
+ graph.markUndoPoint();
+ String value = newValue.isEmpty() ? null : newValue;
+ ComponentTypeCommands.setDescription(graph, resource, value);
+ }
+ });
+ break;
+ }
+ }
+ });
+
+ // Buttons
+
+ Composite buttons = tk.createComposite(sectionBody);
+ GridDataFactory.fillDefaults().applyTo(buttons);
+ GridLayoutFactory.fillDefaults().applyTo(buttons);
+
+ newProperty = tk.createButton(buttons, "New property", SWT.PUSH);
+ GridDataFactory.fillDefaults().applyTo(newProperty);
+ removeProperty = tk.createButton(buttons, "Remove property", SWT.PUSH);
+ GridDataFactory.fillDefaults().applyTo(removeProperty);
+
+ liftProperties = tk.createButton(buttons, "Lift Properties", SWT.PUSH);
+ GridDataFactory.fillDefaults().applyTo(liftProperties);
+
+ hasTypes = !getTypes().isEmpty();
+
+ if(hasTypes) {
+ setTypes = tk.createButton(buttons, "Assign Types", SWT.PUSH);
+ GridDataFactory.fillDefaults().applyTo(setTypes);
+ }
+
+ // Actions
+
+ table.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ TableItem[] sel = table.getSelection();
+ for (TableItem item : sel) {
+ ComponentTypeViewerPropertyInfo pi = (ComponentTypeViewerPropertyInfo) item.getData();
+ if (pi.immutable) {
+ removeProperty.setEnabled(false);
+ return;
+ }
+ }
+ removeProperty.setEnabled(true);
+ }
+ });
+
+ newProperty.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if(editor.getEditor() != null)
+ editor.getEditor().dispose();
+ Simantics.getSession().async(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph)
+ throws DatabaseException {
+ ComponentTypeCommands.createPropertyWithDefaults(graph, data.componentType);
+ }
+ });
+ }
+ });
+
+ removeProperty.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if(editor.getEditor() != null)
+ editor.getEditor().dispose();
+ final List<Resource> propertiesToBeRemoved =
+ new ArrayList<>();
+ for(TableItem item : table.getSelection()) {
+ ComponentTypeViewerPropertyInfo info = (ComponentTypeViewerPropertyInfo) item.getData();
+ if (!info.immutable)
+ propertiesToBeRemoved.add(info.resource);
+ }
+ System.out.println("remove " + propertiesToBeRemoved.size() + " resources");
+ if(!propertiesToBeRemoved.isEmpty())
+ Simantics.getSession().async(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph)
+ throws DatabaseException {
+ graph.markUndoPoint();
+ for(Resource property : propertiesToBeRemoved)
+ ComponentTypeCommands.removeProperty(graph, data.componentType, property);
+ }
+ });
+ }
+ });
+
+ liftProperties.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+
+ if(editor.getEditor() != null)
+ editor.getEditor().dispose();
+
+ try {
+
+ Map<LiftedProperty, Pair<String, ImageDescriptor>> map = Simantics.sync(new UniqueRead<Map<LiftedProperty,Pair<String,ImageDescriptor>>>() {
+
+ @Override
+ public Map<LiftedProperty, Pair<String, ImageDescriptor>> perform(ReadGraph graph) throws DatabaseException {
+
+ Map<LiftedProperty, Pair<String,ImageDescriptor>> map = new HashMap<>();
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+ SelectionViewResources SEL = SelectionViewResources.getInstance(graph);
+
+ Resource composite = graph.getPossibleObject(data.componentType, STR.IsDefinedBy);
+ if(composite == null) return map;
+
+
+ Set<String> existing = new HashSet<>();
+ for(Resource predicate : graph.getObjects(data.componentType, L0.DomainOf)) {
+ if(graph.isSubrelationOf(predicate, L0.HasProperty)) {
+ existing.add(NameUtils.getSafeName(graph, predicate));
+ }
+ }
+
+ for(Resource component : graph.syncRequest(new ObjectsWithType(composite, L0.ConsistsOf, STR.Component))) {
+
+ Resource type = graph.getPossibleType(component, STR.Component);
+ if(type == null) continue;
+
+ String componentName = NameUtils.getSafeName(graph, component);
+
+ for(Resource predicate : graph.getPredicates(component)) {
+ if(graph.isSubrelationOf(predicate, L0.HasProperty)) {
+
+ // Do not list properties shown under other properties
+ if(graph.hasStatement(predicate, SEL.IsShownUnder)) continue;
+
+ // Do not list properties that are not visible in selection view
+ if(!graph.hasStatement(predicate, SEL.HasStandardPropertyInfo)) continue;
+
+ // Some properties are explicitly marked as non-liftable
+ Boolean canBeLifted = graph.getPossibleRelatedValue(predicate, SEL.canBeLifted, Bindings.BOOLEAN);
+ if(canBeLifted != null && !canBeLifted) continue;
+
+ String predicateName = NameUtils.getSafeName(graph, predicate);
+ if(existing.contains(predicateName)) continue;
+
+ String name = componentName + " " + predicateName;
+ map.put(new LiftedProperty(component, type, predicate), new Pair<String, ImageDescriptor>(name, null));
+
+ }
+ }
+
+ }
+
+ return map;
+
+ }
+
+ });
+
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ LiftPropertiesDialog dialog = new LiftPropertiesDialog(shell, map, "Select properties to lift") {
+ @Override
+ protected IDialogSettings getBaseDialogSettings() {
+ return Activator.getDefault().getDialogSettings();
+ }
+ };
+ if (dialog.open() == Window.OK) {
+ final Collection<LiftedProperty> _result = dialog.getResultT();
+ final boolean mapProperties = dialog.getMapProperties();
+ if (!_result.isEmpty()) {
+ Simantics.getSession().async(new WriteRequest() {
+ public Resource findAssertion(ReadGraph graph, Resource sourceType, Resource predicate) throws DatabaseException {
+ Collection<Resource> ass = graph.getAssertedObjects(sourceType, predicate);
+ if(ass.size() == 1) return ass.iterator().next();
+ return null;
+ }
+
+ public void processSubs(ReadGraph graph, Resource predicate, Resource component, Resource componentType, List<LiftedProperty> result, List<Resource> properties, List<Resource> assertions) throws DatabaseException {
+ SelectionViewResources SEL = SelectionViewResources.getInstance(graph);
+ for(Resource sub : graph.getObjects(predicate, SEL.UnderOf)) {
+ Resource ass = findAssertion(graph, componentType, sub);
+ if(ass == null) continue;
+ result.add(new LiftedProperty(component, componentType, sub));
+ properties.add(sub);
+ assertions.add(ass);
+ processSubs(graph, sub, component, componentType, result, properties, assertions);
+ }
+ }
+
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ graph.markUndoPoint();
+ List<Resource> properties = new ArrayList<>();
+ List<Resource> assertions = new ArrayList<>();
+
+ List<LiftedProperty> result = new ArrayList<>();
+ for(LiftedProperty p : _result) {
+ Resource ass = findAssertion(graph, p.getComponentType(), p.getPredicate());
+ if(ass == null) continue;
+ result.add(p);
+ properties.add(p.getPredicate());
+ assertions.add(ass);
+ processSubs(graph, p.getPredicate(), p.getComponent(), p.getComponentType(), result, properties, assertions);
+ }
+
+ CopyHandler2 ch = Layer0Utils.getPossibleCopyHandler(graph, properties);
+ Collection<Resource> copies = Layer0Utils.copyTo(graph, data.componentType, null, ch, null);
+ int index = 0;
+ for(Resource copy : copies) {
+ Resource ass = assertions.get(index);
+ LiftedProperty p = result.get(index);
+ Collection<Resource> copyAss = Layer0Utils.copyTo(graph, null, ass);
+ if(copyAss.size() == 1) {
+ graph.deny(copy, L0.HasDomain);
+ graph.claim(data.componentType, L0.DomainOf, copy);
+ Layer0Utils.assert_(graph, data.componentType, copy, copyAss.iterator().next());
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Lifted property " + NameUtils.getSafeName(graph, copy) + " into "+ NameUtils.getSafeName(graph, data.componentType)));
+ }
+ if(mapProperties) {
+ Variable v = Variables.getVariable(graph, p.getComponent());
+ Variable property = v.getProperty(graph, p.getPredicate());
+ Variable displayValue = property.getProperty(graph, Variables.DISPLAY_VALUE);
+ displayValue.setValue(graph, "=" + NameUtils.getSafeName(graph, p.getPredicate()), Bindings.STRING);
+ }
+ index++;
+ }
+
+ }
+ });
+ }
+ }
+
+ } catch (DatabaseException e1) {
+
+ LOGGER.error("Lifting properties failed", e1);
+ return;
+
+ }
+
+ }
+ });
+
+ if(hasTypes) {
+
+ setTypes.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if(editor.getEditor() != null)
+ editor.getEditor().dispose();
+ final List<Resource> propertiesToSet =
+ new ArrayList<>();
+ for(TableItem item : table.getSelection())
+ propertiesToSet.add(((ComponentTypeViewerPropertyInfo)item.getData()).resource);
+
+ if(propertiesToSet.size() != 1) return;
+
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ SetTypesDialog page = new SetTypesDialog(shell, getTypes(), "Select user types for property");
+ if (page.open() == Window.OK) {
+ final Object[] result = page.getResult();
+ if (result != null && result.length > 0) {
+ Simantics.getSession().async(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph)
+ throws DatabaseException {
+ for(Object type : result) {
+ Layer0 L0 = Layer0.getInstance(graph);
+ graph.claim(propertiesToSet.get(0), L0.InstanceOf, null, (Resource)type);
+ }
+ }
+ });
+ }
+ }
+
+ }
+ });
+
+ }
+
+ table.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ tk.dispose();
+ }
+ });
+ }
+
+ public void update(ComponentTypePropertiesResult result) {
+ if (table.isDisposed())
+ return;
+
+ // Save old selection
+ Set<ComponentTypeViewerPropertyInfo> selected = new HashSet<>();
+ List<TableItem> selectedItems = new ArrayList<>(selected.size());
+ for (int i : table.getSelectionIndices()) {
+ TableItem item = table.getItem(i);
+ selected.add((ComponentTypeViewerPropertyInfo) item.getData());
+ }
+
+ int topIndex = table.getTopIndex();
+
+ table.removeAll();
+
+ if(editor.getEditor() != null)
+ editor.getEditor().dispose();
+
+ for(ComponentTypeViewerPropertyInfo info : result.getProperties()) {
+ boolean immutable = result.isImmutable() || info.immutable;
+ Color fg = immutable ? table.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY) : null;
+ if(info.sectionSpecificData != null)
+ continue;
+
+ TableItem item = new TableItem(table, SWT.NONE);
+
+ item.setText(0, info.name);
+ item.setText(1, info.type);
+ item.setText(2, info.defaultValue);
+ item.setText(3, unitStr(info));
+ item.setText(4, rangeStr(info));
+ item.setText(5, info.label);
+ item.setText(6, info.description);
+
+ for (int columnIndex : IMMUTABLE_COLUMNS_WITH_IMMUTABLE_RELATION)
+ item.setForeground(columnIndex, fg);
+
+ item.setData(info);
+
+ if (selected.contains(info))
+ selectedItems.add(item);
+ }
+
+ // Restore old selection
+ table.setTopIndex(topIndex);
+ table.setSelection(selectedItems.toArray(new TableItem[selectedItems.size()]));
+ table.redraw();
+ }
+
+ private Map<Resource, Pair<String, ImageDescriptor>> getTypes() {
+ try {
+ return Simantics.getSession().syncRequest(new UniqueRead<Map<Resource, Pair<String, ImageDescriptor>>>() {
+ @Override
+ public Map<Resource, Pair<String, ImageDescriptor>> perform(ReadGraph graph)
+ throws DatabaseException {
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+ Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(data.componentType));
+ Instances query = graph.adapt(STR.UserDefinedProperty, Instances.class);
+ Collection<Resource> types = query.find(graph, indexRoot);
+ Map<Resource, Pair<String, ImageDescriptor>> result = new HashMap<>();
+ for(Resource type : types) {
+ String name = NameUtils.getSafeLabel(graph, type);
+ result.put(type, new Pair<String, ImageDescriptor>(name, null));
+ }
+ return result;
+ }
+ });
+ } catch (DatabaseException e) {
+ LOGGER.error("Finding UserDefinedProperties failed.", e);
+ return Collections.emptyMap();
+ }
+ }
+
+ private String unitStr(ComponentTypeViewerPropertyInfo info) {
+ String unit = info.numberType == null ? null : info.numberType.getUnit();
+ if (unit == null)
+ unit = info.unit;
+ return unit != null ? unit : "";
+ }
+
+ private String rangeStr(ComponentTypeViewerPropertyInfo info) {
+ String range = info.numberType == null ? null : info.numberType.getRangeStr();
+ return range != null ? range : "";
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ boolean e = !readOnly;
+ newProperty.setEnabled(e);
+ removeProperty.setEnabled(e);
+ liftProperties.setEnabled(e);
+ }
+
+ @Override
+ public Section getSection() {
+ return section;
+ }
+
+ @Override
+ public double getPriority() {
+ return 0;
+ }
+
+ @Override
+ public Object getSectionSpecificData(ReadGraph graph,
+ ComponentTypeViewerPropertyInfo info) throws DatabaseException {
+ return null;
+ }
+
+ @Override
+ public double getDataPriority() {
+ return 0.0;
+ }
+}