X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.selectionview%2Fsrc%2Forg%2Fsimantics%2Fselectionview%2FPropertyTable.java;fp=bundles%2Forg.simantics.selectionview%2Fsrc%2Forg%2Fsimantics%2Fselectionview%2FPropertyTable.java;h=4bb45be716b3723ee1a3bc707d7902f5a059dee8;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.selectionview/src/org/simantics/selectionview/PropertyTable.java b/bundles/org.simantics.selectionview/src/org/simantics/selectionview/PropertyTable.java new file mode 100644 index 000000000..4bb45be71 --- /dev/null +++ b/bundles/org.simantics.selectionview/src/org/simantics/selectionview/PropertyTable.java @@ -0,0 +1,449 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.selectionview; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; + +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.resource.LocalResourceManager; +import org.eclipse.jface.viewers.IPostSelectionProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.GraphExplorer; +import org.simantics.browsing.ui.common.ColumnKeys; +import org.simantics.browsing.ui.common.EvaluatorData; +import org.simantics.browsing.ui.common.EvaluatorData.Evaluator; +import org.simantics.browsing.ui.common.EvaluatorDataImpl; +import org.simantics.browsing.ui.common.comparators.AlphanumericComparatorFactory; +import org.simantics.browsing.ui.common.processors.ComparableFactoryResolver; +import org.simantics.browsing.ui.common.processors.ComparableSelectorQueryProcessor; +import org.simantics.browsing.ui.common.processors.FilterSelectionRequestQueryProcessor; +import org.simantics.browsing.ui.common.processors.ImageDecoratorFactoryResolver; +import org.simantics.browsing.ui.common.processors.ImagerFactoryResolver; +import org.simantics.browsing.ui.common.processors.LabelDecoratorFactoryResolver; +import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver; +import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor; +import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor; +import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver; +import org.simantics.browsing.ui.common.views.IFilterArea; +import org.simantics.browsing.ui.common.views.IFilterAreaProvider; +import org.simantics.browsing.ui.common.views.PropertyTableConstants; +import org.simantics.browsing.ui.graph.impl.ArrayPropertyLabelerFactory; +import org.simantics.browsing.ui.graph.impl.ArrayPropertyValueViewpointFactory; +import org.simantics.browsing.ui.graph.impl.AsyncReadGraphDataSource; +import org.simantics.browsing.ui.graph.impl.PropertyViewpointFactory; +import org.simantics.browsing.ui.graph.impl.ReadGraphDataSource; +import org.simantics.browsing.ui.graph.impl.RelationContextLabelerFactory; +import org.simantics.browsing.ui.graph.impl.ResourceProperty; +import org.simantics.browsing.ui.graph.impl.StringRepresentationLabelerFactory; +import org.simantics.browsing.ui.swt.ArrayPropertyImagerFactory; +import org.simantics.browsing.ui.swt.ComparatorSelector; +import org.simantics.browsing.ui.swt.ContextMenuInitializer; +import org.simantics.browsing.ui.swt.GraphExplorerFactory; +import org.simantics.browsing.ui.swt.PropertyTableUtil; +import org.simantics.browsing.ui.swt.RootFilterArea; +import org.simantics.browsing.ui.swt.TypesQueryProcessor; +import org.simantics.browsing.ui.swt.ViewpointSelector; +import org.simantics.db.AsyncReadGraph; +import org.simantics.db.ReadGraph; +import org.simantics.db.RelationContext; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.Statement; +import org.simantics.db.common.ResourceArray; +import org.simantics.db.management.ISessionContext; +import org.simantics.ui.dnd.BasicDragSource; +import org.simantics.ui.dnd.SessionContainer; +import org.simantics.ui.utils.ResourceAdaptionUtils; +import org.simantics.utils.ObjectUtils; +import org.simantics.utils.ui.LayoutUtils; + + +/** + *

+ * Subclasses may extend or reimplement the following methods as required: + *

+ *

+ * + * @author Tuukka Lehtonen + */ +public class PropertyTable extends Composite implements IFilterAreaProvider, IPropertyTab2 { + + protected IWorkbenchSite site; + protected GraphExplorer explorer; + protected Object dragSource; + protected ISessionContext sessionContext; + protected ISelection currentInput; + + protected UserSelectedComparableFactoryQueryProcessor userSelectedComparableFactoryQueryProcessor; + protected UserSelectedViewpointFactoryQueryProcessor userSelectedViewpointFactoryQueryProcessor; + protected FilterSelectionRequestQueryProcessor filterSelectionRequestQueryProcessor; + + protected LocalResourceManager resourceManager; + + private RootFilterArea filterArea; + private IContributionItem filterAreaContribution; + private IActionBars actionBars; + + public PropertyTable(IWorkbenchSite site, Composite parent, int style) { + super(parent, style); + this.site = site; + //System.out.println("created " + this + " " + System.identityHashCode(this)); + resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay())); + + addListener(SWT.Dispose, new Listener() { + @Override + public void handleEvent(Event event) { + //System.out.println("DISPOSING " + this + " " + System.identityHashCode(PropertyTable.this)); + tableDisposed(); + + PropertyTableUtil.setupDragSource(dragSource, null); + + PropertyTable.this.site = null; + explorer = null; + dragSource = null; + sessionContext = null; + currentInput = null; + + userSelectedComparableFactoryQueryProcessor = null; + userSelectedViewpointFactoryQueryProcessor = null; + filterSelectionRequestQueryProcessor = null; + + resourceManager.dispose(); + } + }); + } + + /** + * Override to perform actions when this property table is disposed. + * Remember to call super. + */ + protected void tableDisposed() { + getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (filterAreaContribution != null) { + actionBars.getToolBarManager().remove(filterAreaContribution); + filterAreaContribution.dispose(); + filterAreaContribution = null; + actionBars.updateActionBars(); + } + } + }); + } + + @Override + public Control getControl() { + return this; + } + + @Override + public void createControl(final Composite parent, ISessionContext context) { + explorer = createExplorerControl(parent); + dragSource = createDragSource(explorer); + + Control control = explorer.getControl(); + + userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor(); + userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor(); + filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor(); + + parent.setLayout(LayoutUtils.createNoBorderGridLayout(2, false)); + GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control); + + addControls(parent); + setSessionContext(context); + } + + protected void addControls(Composite parent) { + //createSelectors(parent); + //createFilterArea(parent); + } + + protected void createSelectors(Composite parent) { + Control control = explorer.getControl(); + ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, parent, SWT.READ_ONLY); + comparatorSelector.moveAbove(control); + ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, parent, SWT.READ_ONLY); + viewpointSelector.moveAbove(control); + } + + protected void createFilterArea(IActionBars actionBars) { + this.filterAreaContribution = new ContributionItem("filterArea") { + ToolItem item; + @Override + public boolean isDynamic() { + return true; + } + @Override + public final void fill(ToolBar parent, int index) { + Control control = createControl(parent); + item = new ToolItem(parent, SWT.SEPARATOR, index); + item.setControl(control); + item.setWidth(computeWidth(control)); + } + protected Control createControl(Composite parent) { + filterArea = new RootFilterArea(explorer, filterSelectionRequestQueryProcessor, parent, SWT.NONE); + return filterArea; + } + protected int computeWidth(Control control) { + // FIXME: better size control? + return control.computeSize(150, SWT.DEFAULT, true).x; + } + @Override + public void dispose() { + if (filterArea != null) { + filterArea.dispose(); + filterArea = null; + } + if (item != null) { + item.dispose(); + item = null; + } + } + }; + this.actionBars = actionBars; + actionBars.getToolBarManager().add(filterAreaContribution); + } + + protected void createFilterArea(Composite parent) { + Control control = explorer.getControl(); + filterArea = new RootFilterArea(explorer, filterSelectionRequestQueryProcessor, parent, SWT.NONE); + filterArea.moveAbove(control); + } + + protected GraphExplorer createExplorerControl(Composite parent) { + GraphExplorer e = GraphExplorerFactory.getInstance().create(parent, SWT.FULL_SELECTION); + Control c = e.getControl(); + ISelectionProvider selectionProvider = (ISelectionProvider)e.getAdapter(ISelectionProvider.class); + new ContextMenuInitializer("#PropertiesPopup").createContextMenu(c, selectionProvider, site); + if (c instanceof Tree) + ((Tree) c).setLinesVisible(true); + e.setColumns(PropertyTableConstants.NORMAL_COLUMNS); + return e; + } + + /** + * Override to customize drag source initialization. This default + * implementation creates a {@link BasicDragSource}. The drag source is + * initialized when the active database session is set. + * + * @param explorer + * @return the object representing the drag source. If the object implements + * {@link SessionContainer}, its + * {@link SessionContainer#setSession(Session)} will be invoked + * every time the active database session changes. + */ + protected Object createDragSource(GraphExplorer explorer) { + Control c = explorer.getControl(); + DragSource existingSource = (DragSource) c.getData(DND.DRAG_SOURCE_KEY); + if (existingSource != null) + return existingSource; + return PropertyTableUtil.createResourceDragSource(explorer); + } + + protected void setupDragSource(ISessionContext sessionContext) { + PropertyTableUtil.setupDragSource(dragSource, sessionContext); + } + + @Override + public ISelectionProvider getSelectionProvider() { + GraphExplorer e = explorer; + if (e != null) { + IPostSelectionProvider selectionProvider = (IPostSelectionProvider)e.getAdapter(IPostSelectionProvider.class); + return selectionProvider; + } + return null; + } + + @Override + public void requestFocus() { + GraphExplorer e = explorer; + if (e != null) + e.setFocus(); + } + + @Override + public IFilterArea getFilterArea() { + return filterArea; + } + + protected ISessionContext getSessionContext() { + return sessionContext; + } + + protected Session getSession() { + return sessionContext != null ? sessionContext.getSession() : null; + } + + @Override + public void setInput(ISessionContext context, ISelection selection, boolean force) { + if (isDisposed()) + return; + if (sessionContext == null) + return; + + // Check if this is a duplicate of the previous selection to reduce unnecessary flicker. + if (!force && ObjectUtils.objectEquals(currentInput, selection)) + return; + + //Resource[] rs = ResourceAdaptionUtils.toResources(selection); + Object[] rs = toObjects(selection); +// System.out.println("resources: " + Arrays.toString(rs)); + + if (rs.length == 0) { + explorer.setRoot(GraphExplorer.EMPTY_INPUT); + } else { + if (rs.length == 1) { + explorer.setRoot(rs[0]); + } else { + explorer.setRoot(rs); + } + } + + currentInput = selection; + } + + protected Object[] toObjects(ISelection s) { + ResourceArray[] ras = ResourceAdaptionUtils.toResourceArrays(s); + if (ras.length > 0) + return ras; + Resource[] rs = ResourceAdaptionUtils.toResources(s); + if (rs.length > 0) + return rs; + + if (!(s instanceof IStructuredSelection)) + return new Object[0]; + IStructuredSelection ss = (IStructuredSelection) s; + List result = new ArrayList(); + for (Iterator iterator = ss.iterator(); iterator.hasNext();) + result.add(iterator.next()); + return result.toArray(); + } + + public void setSessionContext(ISessionContext sessionContext) { + if (isDisposed()) + return; + +// System.out.println("setSessionContext: " + sessionContext + " (" + this + ")"); + if (this.sessionContext == sessionContext) + return; + this.sessionContext = sessionContext; + Session session = sessionContext != null ? sessionContext.getSession() : null; + reinitializeExplorer(explorer, sessionContext, session); + } + + protected void reinitializeExplorer(GraphExplorer explorer, ISessionContext sessionContext, Session session) { + if (isDisposed()) + return; + + setupDragSource(sessionContext); + + // TODO: synchronize the explorer somehow to make sure nothing running in its background is trying to modify the explorer during this process + + EvaluatorData data = new EvaluatorDataImpl(); + + if (session != null) { + explorer.setDataSource(new AsyncReadGraphDataSource(session)); + explorer.setDataSource(new ReadGraphDataSource(session)); + + Evaluator resourceEvaluator = data.newEvaluator() + .addViewpoint(new PropertyViewpointFactory(), 1.0) + .addComparator(new AlphanumericComparatorFactory(ColumnKeys.PROPERTY), 2.0) + .addComparator(new AlphanumericComparatorFactory(ColumnKeys.PROPERTY, true), 1.0) + .addLabeler(new StringRepresentationLabelerFactory(ColumnKeys.PROPERTY), 1.0); + + Evaluator statementEvaluator = data.newEvaluator() + .addViewpoint(new PropertyViewpointFactory(), 1.0) + .addComparator(new AlphanumericComparatorFactory(ColumnKeys.PROPERTY), 2.0) + .addComparator(new AlphanumericComparatorFactory(ColumnKeys.PROPERTY, true), 1.0); + + Evaluator relationContextEvaluator = data.newEvaluator() + .addLabeler(new RelationContextLabelerFactory(), 1.0); + + Evaluator propertyEvaluator = data.newEvaluator() + .addViewpoint(new ArrayPropertyValueViewpointFactory(), 1.0) + .addLabeler(new ArrayPropertyLabelerFactory(), 1.0) + .addImager(new ArrayPropertyImagerFactory(), 1.0); + + data.addEvaluator(Resource.class, resourceEvaluator); + data.addEvaluator(ResourceArray.class, resourceEvaluator); + data.addEvaluator(Statement.class, statementEvaluator); + data.addEvaluator(RelationContext.class, relationContextEvaluator); + data.addEvaluator(ResourceProperty.class, propertyEvaluator); + + } else { + explorer.removeDataSource(AsyncReadGraph.class); + explorer.removeDataSource(ReadGraph.class); + } + + explorer.setProcessor(new ComparableFactoryResolver(data)); + explorer.setProcessor(new ViewpointFactoryResolver(data)); + explorer.setProcessor(new LabelerFactoryResolver(data)); + explorer.setProcessor(new ImagerFactoryResolver(data)); + explorer.setProcessor(new LabelDecoratorFactoryResolver(data)); + explorer.setProcessor(new ImageDecoratorFactoryResolver(data)); + explorer.setPrimitiveProcessor(new TypesQueryProcessor()); + + explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor); + explorer.setProcessor(new ComparableSelectorQueryProcessor()); + explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor); + explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor); + + // Make sure the explorer gets reset. + explorer.setRoot(GraphExplorer.EMPTY_INPUT); + } + + @Override + public void updatePartName(Consumer updateCallback) { + ISelection forSelection = currentInput; + if (forSelection instanceof IStructuredSelection) { + IStructuredSelection s = (IStructuredSelection) forSelection; + int size = s.size(); + if (size == 1) { + Object obj = s.getFirstElement(); + if (obj != null) + updateCallback.accept(obj.toString()); + else + updateCallback.accept("Properties"); + } else { + updateCallback.accept("Properties [" + size + "]"); + } + } else { + updateCallback.accept("Properties"); + } + } + +}