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