/*******************************************************************************
* 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:
*
* createExplorerControl
- reimplement to customize the way the IGraphExplorer control is created
* createControl
- reimplement to customize the way other supplementary controls get created
* createDragSource
- reimplement to customize the kind of DragSource this control provides
*
*
*
* @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