1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.selectionview;
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.function.Consumer;
19 import org.eclipse.jface.action.ContributionItem;
20 import org.eclipse.jface.action.IContributionItem;
21 import org.eclipse.jface.layout.GridDataFactory;
22 import org.eclipse.jface.resource.JFaceResources;
23 import org.eclipse.jface.resource.LocalResourceManager;
24 import org.eclipse.jface.viewers.IPostSelectionProvider;
25 import org.eclipse.jface.viewers.ISelection;
26 import org.eclipse.jface.viewers.ISelectionProvider;
27 import org.eclipse.jface.viewers.IStructuredSelection;
28 import org.eclipse.swt.SWT;
29 import org.eclipse.swt.dnd.DND;
30 import org.eclipse.swt.dnd.DragSource;
31 import org.eclipse.swt.widgets.Composite;
32 import org.eclipse.swt.widgets.Control;
33 import org.eclipse.swt.widgets.Event;
34 import org.eclipse.swt.widgets.Listener;
35 import org.eclipse.swt.widgets.ToolBar;
36 import org.eclipse.swt.widgets.ToolItem;
37 import org.eclipse.swt.widgets.Tree;
38 import org.eclipse.ui.IActionBars;
39 import org.eclipse.ui.IWorkbenchSite;
40 import org.simantics.browsing.ui.GraphExplorer;
41 import org.simantics.browsing.ui.common.ColumnKeys;
42 import org.simantics.browsing.ui.common.EvaluatorData;
43 import org.simantics.browsing.ui.common.EvaluatorData.Evaluator;
44 import org.simantics.browsing.ui.common.EvaluatorDataImpl;
45 import org.simantics.browsing.ui.common.comparators.AlphanumericComparatorFactory;
46 import org.simantics.browsing.ui.common.processors.ComparableFactoryResolver;
47 import org.simantics.browsing.ui.common.processors.ComparableSelectorQueryProcessor;
48 import org.simantics.browsing.ui.common.processors.FilterSelectionRequestQueryProcessor;
49 import org.simantics.browsing.ui.common.processors.ImageDecoratorFactoryResolver;
50 import org.simantics.browsing.ui.common.processors.ImagerFactoryResolver;
51 import org.simantics.browsing.ui.common.processors.LabelDecoratorFactoryResolver;
52 import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver;
53 import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor;
54 import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor;
55 import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver;
56 import org.simantics.browsing.ui.common.views.IFilterArea;
57 import org.simantics.browsing.ui.common.views.IFilterAreaProvider;
58 import org.simantics.browsing.ui.common.views.PropertyTableConstants;
59 import org.simantics.browsing.ui.graph.impl.ArrayPropertyLabelerFactory;
60 import org.simantics.browsing.ui.graph.impl.ArrayPropertyValueViewpointFactory;
61 import org.simantics.browsing.ui.graph.impl.AsyncReadGraphDataSource;
62 import org.simantics.browsing.ui.graph.impl.PropertyViewpointFactory;
63 import org.simantics.browsing.ui.graph.impl.ReadGraphDataSource;
64 import org.simantics.browsing.ui.graph.impl.RelationContextLabelerFactory;
65 import org.simantics.browsing.ui.graph.impl.ResourceProperty;
66 import org.simantics.browsing.ui.graph.impl.StringRepresentationLabelerFactory;
67 import org.simantics.browsing.ui.swt.ArrayPropertyImagerFactory;
68 import org.simantics.browsing.ui.swt.ComparatorSelector;
69 import org.simantics.browsing.ui.swt.ContextMenuInitializer;
70 import org.simantics.browsing.ui.swt.GraphExplorerFactory;
71 import org.simantics.browsing.ui.swt.PropertyTableUtil;
72 import org.simantics.browsing.ui.swt.RootFilterArea;
73 import org.simantics.browsing.ui.swt.TypesQueryProcessor;
74 import org.simantics.browsing.ui.swt.ViewpointSelector;
75 import org.simantics.db.AsyncReadGraph;
76 import org.simantics.db.ReadGraph;
77 import org.simantics.db.RelationContext;
78 import org.simantics.db.Resource;
79 import org.simantics.db.Session;
80 import org.simantics.db.Statement;
81 import org.simantics.db.common.ResourceArray;
82 import org.simantics.db.management.ISessionContext;
83 import org.simantics.ui.dnd.BasicDragSource;
84 import org.simantics.ui.dnd.SessionContainer;
85 import org.simantics.ui.utils.ResourceAdaptionUtils;
86 import org.simantics.utils.ObjectUtils;
87 import org.simantics.utils.ui.LayoutUtils;
92 * Subclasses may extend or reimplement the following methods as required:
94 * <li><code>createExplorerControl</code> - reimplement to customize the way the IGraphExplorer control is created</li>
95 * <li><code>createControl</code> - reimplement to customize the way other supplementary controls get created</li>
96 * <li><code>createDragSource</code> - reimplement to customize the kind of DragSource this control provides</li>
100 * @author Tuukka Lehtonen
102 public class PropertyTable extends Composite implements IFilterAreaProvider, IPropertyTab2 {
104 protected IWorkbenchSite site;
105 protected GraphExplorer explorer;
106 protected Object dragSource;
107 protected ISessionContext sessionContext;
108 protected ISelection currentInput;
110 protected UserSelectedComparableFactoryQueryProcessor userSelectedComparableFactoryQueryProcessor;
111 protected UserSelectedViewpointFactoryQueryProcessor userSelectedViewpointFactoryQueryProcessor;
112 protected FilterSelectionRequestQueryProcessor filterSelectionRequestQueryProcessor;
114 protected LocalResourceManager resourceManager;
116 private RootFilterArea filterArea;
117 private IContributionItem filterAreaContribution;
118 private IActionBars actionBars;
120 public PropertyTable(IWorkbenchSite site, Composite parent, int style) {
121 super(parent, style);
123 //System.out.println("created " + this + " " + System.identityHashCode(this));
124 resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()));
126 addListener(SWT.Dispose, new Listener() {
128 public void handleEvent(Event event) {
129 //System.out.println("DISPOSING " + this + " " + System.identityHashCode(PropertyTable.this));
132 PropertyTableUtil.setupDragSource(dragSource, null);
134 PropertyTable.this.site = null;
137 sessionContext = null;
140 userSelectedComparableFactoryQueryProcessor = null;
141 userSelectedViewpointFactoryQueryProcessor = null;
142 filterSelectionRequestQueryProcessor = null;
144 resourceManager.dispose();
150 * Override to perform actions when this property table is disposed.
151 * Remember to call super.
153 protected void tableDisposed() {
154 getDisplay().asyncExec(new Runnable() {
157 if (filterAreaContribution != null) {
158 actionBars.getToolBarManager().remove(filterAreaContribution);
159 filterAreaContribution.dispose();
160 filterAreaContribution = null;
161 actionBars.updateActionBars();
168 public Control getControl() {
173 public void createControl(final Composite parent, ISessionContext context) {
174 explorer = createExplorerControl(parent);
175 dragSource = createDragSource(explorer);
177 Control control = explorer.getControl();
179 userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor();
180 userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor();
181 filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor();
183 parent.setLayout(LayoutUtils.createNoBorderGridLayout(2, false));
184 GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control);
187 setSessionContext(context);
190 protected void addControls(Composite parent) {
191 //createSelectors(parent);
192 //createFilterArea(parent);
195 protected void createSelectors(Composite parent) {
196 Control control = explorer.getControl();
197 ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, parent, SWT.READ_ONLY);
198 comparatorSelector.moveAbove(control);
199 ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, parent, SWT.READ_ONLY);
200 viewpointSelector.moveAbove(control);
203 protected void createFilterArea(IActionBars actionBars) {
204 this.filterAreaContribution = new ContributionItem("filterArea") {
207 public boolean isDynamic() {
211 public final void fill(ToolBar parent, int index) {
212 Control control = createControl(parent);
213 item = new ToolItem(parent, SWT.SEPARATOR, index);
214 item.setControl(control);
215 item.setWidth(computeWidth(control));
217 protected Control createControl(Composite parent) {
218 filterArea = new RootFilterArea(explorer, filterSelectionRequestQueryProcessor, parent, SWT.NONE);
221 protected int computeWidth(Control control) {
222 // FIXME: better size control?
223 return control.computeSize(150, SWT.DEFAULT, true).x;
226 public void dispose() {
227 if (filterArea != null) {
228 filterArea.dispose();
237 this.actionBars = actionBars;
238 actionBars.getToolBarManager().add(filterAreaContribution);
241 protected void createFilterArea(Composite parent) {
242 Control control = explorer.getControl();
243 filterArea = new RootFilterArea(explorer, filterSelectionRequestQueryProcessor, parent, SWT.NONE);
244 filterArea.moveAbove(control);
247 protected GraphExplorer createExplorerControl(Composite parent) {
248 GraphExplorer e = GraphExplorerFactory.getInstance().create(parent, SWT.FULL_SELECTION);
249 Control c = e.getControl();
250 ISelectionProvider selectionProvider = (ISelectionProvider)e.getAdapter(ISelectionProvider.class);
251 new ContextMenuInitializer("#PropertiesPopup").createContextMenu(c, selectionProvider, site);
252 if (c instanceof Tree)
253 ((Tree) c).setLinesVisible(true);
254 e.setColumns(PropertyTableConstants.NORMAL_COLUMNS);
259 * Override to customize drag source initialization. This default
260 * implementation creates a {@link BasicDragSource}. The drag source is
261 * initialized when the active database session is set.
264 * @return the object representing the drag source. If the object implements
265 * {@link SessionContainer}, its
266 * {@link SessionContainer#setSession(Session)} will be invoked
267 * every time the active database session changes.
269 protected Object createDragSource(GraphExplorer explorer) {
270 Control c = explorer.getControl();
271 DragSource existingSource = (DragSource) c.getData(DND.DRAG_SOURCE_KEY);
272 if (existingSource != null)
273 return existingSource;
274 return PropertyTableUtil.createResourceDragSource(explorer);
277 protected void setupDragSource(ISessionContext sessionContext) {
278 PropertyTableUtil.setupDragSource(dragSource, sessionContext);
282 public ISelectionProvider getSelectionProvider() {
283 GraphExplorer e = explorer;
285 IPostSelectionProvider selectionProvider = (IPostSelectionProvider)e.getAdapter(IPostSelectionProvider.class);
286 return selectionProvider;
292 public void requestFocus() {
293 GraphExplorer e = explorer;
299 public IFilterArea getFilterArea() {
303 protected ISessionContext getSessionContext() {
304 return sessionContext;
307 protected Session getSession() {
308 return sessionContext != null ? sessionContext.getSession() : null;
312 public void setInput(ISessionContext context, ISelection selection, boolean force) {
315 if (sessionContext == null)
318 // Check if this is a duplicate of the previous selection to reduce unnecessary flicker.
319 if (!force && ObjectUtils.objectEquals(currentInput, selection))
322 //Resource[] rs = ResourceAdaptionUtils.toResources(selection);
323 Object[] rs = toObjects(selection);
324 // System.out.println("resources: " + Arrays.toString(rs));
326 if (rs.length == 0) {
327 explorer.setRoot(GraphExplorer.EMPTY_INPUT);
329 if (rs.length == 1) {
330 explorer.setRoot(rs[0]);
332 explorer.setRoot(rs);
336 currentInput = selection;
339 protected Object[] toObjects(ISelection s) {
340 ResourceArray[] ras = ResourceAdaptionUtils.toResourceArrays(s);
343 Resource[] rs = ResourceAdaptionUtils.toResources(s);
347 if (!(s instanceof IStructuredSelection))
348 return new Object[0];
349 IStructuredSelection ss = (IStructuredSelection) s;
350 List<Object> result = new ArrayList<Object>();
351 for (Iterator<?> iterator = ss.iterator(); iterator.hasNext();)
352 result.add(iterator.next());
353 return result.toArray();
356 public void setSessionContext(ISessionContext sessionContext) {
360 // System.out.println("setSessionContext: " + sessionContext + " (" + this + ")");
361 if (this.sessionContext == sessionContext)
363 this.sessionContext = sessionContext;
364 Session session = sessionContext != null ? sessionContext.getSession() : null;
365 reinitializeExplorer(explorer, sessionContext, session);
368 protected void reinitializeExplorer(GraphExplorer explorer, ISessionContext sessionContext, Session session) {
372 setupDragSource(sessionContext);
374 // TODO: synchronize the explorer somehow to make sure nothing running in its background is trying to modify the explorer during this process
376 EvaluatorData data = new EvaluatorDataImpl();
378 if (session != null) {
379 explorer.setDataSource(new AsyncReadGraphDataSource(session));
380 explorer.setDataSource(new ReadGraphDataSource(session));
382 Evaluator resourceEvaluator = data.newEvaluator()
383 .addViewpoint(new PropertyViewpointFactory(), 1.0)
384 .addComparator(new AlphanumericComparatorFactory(ColumnKeys.PROPERTY), 2.0)
385 .addComparator(new AlphanumericComparatorFactory(ColumnKeys.PROPERTY, true), 1.0)
386 .addLabeler(new StringRepresentationLabelerFactory(ColumnKeys.PROPERTY), 1.0);
388 Evaluator statementEvaluator = data.newEvaluator()
389 .addViewpoint(new PropertyViewpointFactory(), 1.0)
390 .addComparator(new AlphanumericComparatorFactory(ColumnKeys.PROPERTY), 2.0)
391 .addComparator(new AlphanumericComparatorFactory(ColumnKeys.PROPERTY, true), 1.0);
393 Evaluator relationContextEvaluator = data.newEvaluator()
394 .addLabeler(new RelationContextLabelerFactory(), 1.0);
396 Evaluator propertyEvaluator = data.newEvaluator()
397 .addViewpoint(new ArrayPropertyValueViewpointFactory(), 1.0)
398 .addLabeler(new ArrayPropertyLabelerFactory(), 1.0)
399 .addImager(new ArrayPropertyImagerFactory(), 1.0);
401 data.addEvaluator(Resource.class, resourceEvaluator);
402 data.addEvaluator(ResourceArray.class, resourceEvaluator);
403 data.addEvaluator(Statement.class, statementEvaluator);
404 data.addEvaluator(RelationContext.class, relationContextEvaluator);
405 data.addEvaluator(ResourceProperty.class, propertyEvaluator);
408 explorer.removeDataSource(AsyncReadGraph.class);
409 explorer.removeDataSource(ReadGraph.class);
412 explorer.setProcessor(new ComparableFactoryResolver(data));
413 explorer.setProcessor(new ViewpointFactoryResolver(data));
414 explorer.setProcessor(new LabelerFactoryResolver(data));
415 explorer.setProcessor(new ImagerFactoryResolver(data));
416 explorer.setProcessor(new LabelDecoratorFactoryResolver(data));
417 explorer.setProcessor(new ImageDecoratorFactoryResolver(data));
418 explorer.setPrimitiveProcessor(new TypesQueryProcessor());
420 explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor);
421 explorer.setProcessor(new ComparableSelectorQueryProcessor());
422 explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor);
423 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
425 // Make sure the explorer gets reset.
426 explorer.setRoot(GraphExplorer.EMPTY_INPUT);
430 public void updatePartName(Consumer<String> updateCallback) {
431 ISelection forSelection = currentInput;
432 if (forSelection instanceof IStructuredSelection) {
433 IStructuredSelection s = (IStructuredSelection) forSelection;
436 Object obj = s.getFirstElement();
438 updateCallback.accept(obj.toString());
440 updateCallback.accept("Properties");
442 updateCallback.accept("Properties [" + size + "]");
445 updateCallback.accept("Properties");