]> gerrit.simantics Code Review - simantics/platform.git/blob
42ee2bdf812fe788e20b040139ac9ae9df4fdce6
[simantics/platform.git] /
1 /*******************************************************************************
2  * Copyright (c) 2007, 2012 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.browsing.ui.swt.widgets;
13
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.HashSet;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.function.BiFunction;
20 import java.util.function.Consumer;
21
22 import org.eclipse.core.runtime.IAdaptable;
23 import org.eclipse.core.runtime.Platform;
24 import org.eclipse.jface.action.IMenuManager;
25 import org.eclipse.jface.layout.GridDataFactory;
26 import org.eclipse.jface.layout.GridLayoutFactory;
27 import org.eclipse.jface.layout.TreeColumnLayout;
28 import org.eclipse.jface.resource.JFaceResources;
29 import org.eclipse.jface.resource.LocalResourceManager;
30 import org.eclipse.jface.viewers.ColumnWeightData;
31 import org.eclipse.jface.viewers.ISelectionProvider;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.dnd.DND;
34 import org.eclipse.swt.dnd.DragSource;
35 import org.eclipse.swt.dnd.DragSourceEvent;
36 import org.eclipse.swt.dnd.DragSourceListener;
37 import org.eclipse.swt.dnd.DropTarget;
38 import org.eclipse.swt.dnd.DropTargetEvent;
39 import org.eclipse.swt.dnd.DropTargetListener;
40 import org.eclipse.swt.dnd.FileTransfer;
41 import org.eclipse.swt.dnd.TextTransfer;
42 import org.eclipse.swt.dnd.Transfer;
43 import org.eclipse.swt.widgets.Composite;
44 import org.eclipse.swt.widgets.Control;
45 import org.eclipse.swt.widgets.Event;
46 import org.eclipse.swt.widgets.Listener;
47 import org.eclipse.swt.widgets.Tree;
48 import org.eclipse.swt.widgets.TreeColumn;
49 import org.eclipse.swt.widgets.TreeItem;
50 import org.eclipse.ui.ISelectionListener;
51 import org.eclipse.ui.IWorkbenchSite;
52 import org.eclipse.ui.contexts.IContextService;
53 import org.simantics.Simantics;
54 import org.simantics.browsing.ui.BuiltinKeys;
55 import org.simantics.browsing.ui.Column;
56 import org.simantics.browsing.ui.ExplorerState;
57 import org.simantics.browsing.ui.GraphExplorer;
58 import org.simantics.browsing.ui.GraphExplorer.TransientExplorerState;
59 import org.simantics.browsing.ui.NodeContext;
60 import org.simantics.browsing.ui.StatePersistor;
61 import org.simantics.browsing.ui.common.AdaptableHintContext;
62 import org.simantics.browsing.ui.common.ColumnKeys;
63 import org.simantics.browsing.ui.common.EvaluatorData;
64 import org.simantics.browsing.ui.common.EvaluatorDataImpl;
65 import org.simantics.browsing.ui.common.processors.ComparableFactoryResolver;
66 import org.simantics.browsing.ui.common.processors.ComparableSelectorQueryProcessor;
67 import org.simantics.browsing.ui.common.processors.FilterSelectionRequestQueryProcessor;
68 import org.simantics.browsing.ui.common.processors.ImageDecoratorFactoryResolver;
69 import org.simantics.browsing.ui.common.processors.ImagerFactoryResolver;
70 import org.simantics.browsing.ui.common.processors.LabelDecoratorFactoryResolver;
71 import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver;
72 import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor;
73 import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor;
74 import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver;
75 import org.simantics.browsing.ui.common.views.FilterAreaSource;
76 import org.simantics.browsing.ui.common.views.IFilterArea;
77 import org.simantics.browsing.ui.common.views.IFilterAreaProvider;
78 import org.simantics.browsing.ui.graph.impl.AsyncReadGraphDataSource;
79 import org.simantics.browsing.ui.graph.impl.Evaluators;
80 import org.simantics.browsing.ui.graph.impl.InheritsQueryProcessor;
81 import org.simantics.browsing.ui.graph.impl.ReadGraphDataSource;
82 import org.simantics.browsing.ui.graph.impl.RelatedObjectsQueryProcessor;
83 import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
84 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
85 import org.simantics.browsing.ui.model.nodetypes.NodeType;
86 import org.simantics.browsing.ui.swt.Activator;
87 import org.simantics.browsing.ui.swt.ComparatorSelector;
88 import org.simantics.browsing.ui.swt.ContextMenuInitializer;
89 import org.simantics.browsing.ui.swt.DefaultExplorerSelectionListener;
90 import org.simantics.browsing.ui.swt.DefaultIsCheckedProcessor2;
91 import org.simantics.browsing.ui.swt.DefaultKeyListener;
92 import org.simantics.browsing.ui.swt.DefaultMouseListener;
93 import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver;
94 import org.simantics.browsing.ui.swt.FilterArea;
95 import org.simantics.browsing.ui.swt.GraphExplorerFactory;
96 import org.simantics.browsing.ui.swt.IContextMenuInitializer;
97 import org.simantics.browsing.ui.swt.RootFilterArea;
98 import org.simantics.browsing.ui.swt.StandardContextTypesQueryProcessor;
99 import org.simantics.browsing.ui.swt.TypesQueryProcessor;
100 import org.simantics.browsing.ui.swt.ViewpointSelector;
101 import org.simantics.browsing.ui.swt.widgets.impl.Widget;
102 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;
103 import org.simantics.db.AsyncReadGraph;
104 import org.simantics.db.ReadGraph;
105 import org.simantics.db.Resource;
106 import org.simantics.db.Session;
107 import org.simantics.db.exception.DatabaseException;
108 import org.simantics.db.layer0.SelectionHints;
109 import org.simantics.db.layer0.request.PossibleVariable;
110 import org.simantics.db.layer0.request.PossibleVariableRepresents;
111 import org.simantics.db.layer0.variable.Variable;
112 import org.simantics.db.management.ISessionContext;
113 import org.simantics.db.management.ISessionContextChangedListener;
114 import org.simantics.db.management.ISessionContextProvider;
115 import org.simantics.db.management.SessionContextChangedEvent;
116 import org.simantics.project.ProjectKeys;
117 import org.simantics.ui.SimanticsUI;
118 import org.simantics.ui.dnd.LocalObjectTransfer;
119 import org.simantics.ui.dnd.LocalSelectionDragSourceListener;
120 import org.simantics.ui.dnd.NoImageDragSourceEffect;
121 import org.simantics.ui.dnd.SessionContainer;
122 import org.simantics.ui.selection.AnyResource;
123 import org.simantics.ui.selection.AnyVariable;
124 import org.simantics.ui.selection.ExplorerColumnContentType;
125 import org.simantics.ui.selection.ExplorerInputContentType;
126 import org.simantics.ui.selection.WorkbenchSelectionContentType;
127 import org.simantics.ui.selection.WorkbenchSelectionElement;
128 import org.simantics.ui.selection.WorkbenchSelectionUtils;
129 import org.simantics.utils.ObjectUtils;
130 import org.simantics.utils.datastructures.Function;
131 import org.simantics.utils.datastructures.disposable.DisposeState;
132 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
133 import org.simantics.utils.datastructures.hints.HintTracker;
134 import org.simantics.utils.datastructures.hints.IHintContext.Key;
135 import org.simantics.utils.datastructures.hints.IHintListener;
136 import org.simantics.utils.datastructures.hints.IHintObservable;
137 import org.simantics.utils.datastructures.hints.IHintTracker;
138 import org.slf4j.Logger;
139 import org.slf4j.LoggerFactory;
140
141
142 public class GraphExplorerComposite extends Composite implements Widget, IAdaptable {
143
144     private static final Logger LOGGER = LoggerFactory.getLogger(GraphExplorerComposite.class);
145
146     protected UserSelectedComparableFactoryQueryProcessor userSelectedComparableFactoryQueryProcessor;
147     protected UserSelectedViewpointFactoryQueryProcessor  userSelectedViewpointFactoryQueryProcessor;
148     protected FilterSelectionRequestQueryProcessor        filterSelectionRequestQueryProcessor;
149     protected IFilterArea                                 filterArea;
150     protected EvaluatorData                               evaluatorData;
151
152     protected LocalResourceManager                        resourceManager;
153
154     protected ISelectionListener                          workbenchSelectionListener;
155
156     private final int                                     style;
157
158     final private IWorkbenchSite                          site;
159
160     protected GraphExplorer                               explorer;
161
162     protected IMenuManager                                menuManager;
163
164     private final Map<String, Object>                     args;
165
166     protected ISessionContextProvider                       contextProvider;
167
168     private ISessionContext                               sessionContext;
169
170     private Object                                        dragSource;
171
172     private IHintTracker                                  sessionContextTracker = new SessionContextProjectTracker();
173
174     private InputSource                                   inputSource           = new DirectInputSource();
175     private FilterAreaSource                              filterAreaSource    = new SelectionFilterAreaSource();
176
177     private final TreeColumnLayout                                                        ad;
178     private String[]                                        editingColumn = ColumnKeys.KEYS_SINGLE;
179     
180     private StatePersistor                                                                      persistor = null;
181
182     private final Composite                                                                       toolComposite;
183     private final Composite                                                                       toolComposite2;
184     private final Composite                                                                       explorerComposite;
185     final private WidgetSupport                                 support;
186     private final boolean                                                                       useNodeBrowseContexts;
187     private final boolean                                                                       useNodeActionContexts;
188
189     static class SelectionElement extends AdaptableHintContext {
190
191         final public WorkbenchSelectionElement wse;
192         final public Object content;
193         final public Resource resource;
194         final public Variable variable;
195         final public Object input;
196         final public TransientExplorerState explorerState;
197         
198         private WorkbenchSelectionElement extractWse(Object content) {
199             if(content instanceof NodeContext) {
200                 NodeContext context = (NodeContext)content;
201                 Object input = context.getConstant(NodeType.TYPE);
202                 if(input instanceof NodeType) 
203                     return ((NodeType)input).getWorkbenchSelectionElement(context);
204             }
205             return null;
206         }
207         
208         private Resource extractResource(Object content) {
209                 if(content instanceof NodeContext) {
210                         NodeContext context = (NodeContext)content;
211                         Object input = context.getConstant(BuiltinKeys.INPUT);
212                         if(input instanceof Resource) return (Resource)input;
213                         if(input instanceof IAdaptable) {
214                                 Resource var = (Resource)((IAdaptable)input).getAdapter(Resource.class);
215                                 if(var != null) return var;
216                         }
217                 }
218                 return null;
219         }
220         
221         private Variable extractVariable(Object content) {
222                 if(content instanceof NodeContext) {
223                         NodeContext context = (NodeContext)content;
224                         Object input = context.getConstant(BuiltinKeys.INPUT);
225                         if(input instanceof Variable) return (Variable)input;
226                         if(input instanceof IAdaptable) {
227                                 Variable var = (Variable)((IAdaptable)input).getAdapter(Variable.class);
228                                 if(var != null) return var;
229                         }
230                 }
231                 return null;
232         }
233
234         private Object extractInput(Object content) {
235                 if(content instanceof NodeContext) {
236                         NodeContext context = (NodeContext)content;
237                         return context.getConstant(BuiltinKeys.INPUT);
238                 }
239                 return null;
240         }
241
242         public SelectionElement(GraphExplorer explorer, Key[] keys, Object content) {
243             super(keys);
244             this.content = content;
245             this.wse = extractWse(content);
246             this.resource = extractResource(content);
247             this.variable = extractVariable(content);
248             this.input = extractInput(content);
249             this.explorerState = explorer.getTransientState();
250         }
251
252         @SuppressWarnings("unchecked")
253         @Override
254         public <T> T getContent(WorkbenchSelectionContentType<T> contentType) {
255             if (wse != null) {
256                 T result = wse.getContent(contentType);
257                 if (result != null)
258                     return result;
259             }
260
261             if (contentType instanceof AnyResource) {
262                 if (resource != null)
263                     return (T) resource;
264                 if (variable == null)
265                     return null;
266                 try {
267                     return (T) ((AnyResource) contentType).processor.syncRequest(new PossibleVariableRepresents(variable));
268                 } catch (DatabaseException e) {
269                     LOGGER.error("Unexpected error occurred while resolving Resource from Variable " + variable, e);
270                 }
271             }
272             else if (contentType instanceof AnyVariable) {
273                 if (variable != null)
274                     return (T) variable;
275                 if (resource == null)
276                     return null;
277                 try {
278                     return (T) ((AnyVariable) contentType).processor.syncRequest(new PossibleVariable(resource));
279                 } catch (DatabaseException e) {
280                     LOGGER.error("Unexpected error occurred while resolving Variable from Resource " + resource, e);
281                 }
282             } else if (contentType instanceof ExplorerInputContentType) {
283                 return (T) input;
284             } else if (contentType instanceof ExplorerColumnContentType) {
285                 return (T) explorerState.getActiveColumn();
286             }
287             return null;
288         }
289
290         @SuppressWarnings("rawtypes")
291         @Override
292         public Object getAdapter(Class adapter) {
293                 if(WorkbenchSelectionElement.class == adapter) {
294                         return wse;
295                 }
296                 if(NodeContext.class == adapter) {
297                     if(content instanceof NodeContext)
298                         return (NodeContext)content;
299                     else
300                         return null;
301                 }
302                 return super.getAdapter(adapter);
303         }
304
305     }
306     private BiFunction<GraphExplorer, Object[], Object[]> selectionTransformation = new BiFunction<GraphExplorer, Object[], Object[]>() {
307
308         private Key[] KEYS = new Key[] { SelectionHints.KEY_MAIN };
309         
310         @Override
311         public Object[] apply(GraphExplorer explorer, Object[] objects) {
312             Object[] result = new Object[objects.length];
313             for (int i = 0; i < objects.length; i++) {
314                 SelectionElement context = new SelectionElement(explorer, KEYS, objects[i]);
315                 context.setHint(SelectionHints.KEY_MAIN, objects[i]);
316                 result[i] = context;
317             }
318             return result;
319         }
320
321     };
322
323     private Set<String>                                   browseContexts        = null;
324
325     private DisposeState                                  disposeState          = DisposeState.Alive;
326
327     private boolean                                       created               = false;
328
329     protected String                                      contextMenuId         = null;
330
331     protected Set<String>                                 uiContext             = null;
332
333     protected ISessionContextChangedListener              contextChangeListener = new ISessionContextChangedListener() {
334         @Override
335         public void sessionContextChanged(SessionContextChangedEvent event) {
336             sessionContext = event.getNewValue();
337             sessionContextTracker.track(sessionContext);
338         }
339     };
340
341     public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, WidgetSupport support, int style) {
342
343         super(parent, SWT.NONE);
344
345         if (args == null)
346             args = Collections.emptyMap();
347
348         this.args = args;
349         this.site = site;
350         this.style = style;
351         this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), this);
352
353         contextProvider = getSessionContextProvider(site);
354
355         Integer maxChildren = (Integer)args.get("maxChildren");
356
357         GridLayoutFactory.fillDefaults().equalWidth(false).numColumns(1).margins(0,0).spacing(0,0).applyTo(this);
358
359         toolComposite = new Composite(this, SWT.NONE);
360 //        toolComposite.setBackground(toolComposite.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
361 //        GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
362         GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite);
363         GridLayoutFactory.fillDefaults().applyTo(toolComposite);
364
365         ad = new TreeColumnLayout();
366         explorerComposite = new Composite(this, SWT.NONE);
367         explorerComposite.setLayout(ad);
368         GridDataFactory.fillDefaults().grab(true, true).minSize(1, 50).applyTo(explorerComposite);
369
370         if (args.containsKey("treeView") && Boolean.TRUE.equals(args.get("treeView"))) {
371                 explorer = createExplorerControl2(explorerComposite, maxChildren);
372         } else if (args.containsKey("natTable") && Boolean.TRUE.equals(args.get("natTable"))) {
373                 explorer = createExplorerControl3(explorerComposite, maxChildren);
374         } else {
375                 explorer = createExplorerControl(explorerComposite, maxChildren);
376         }
377         
378         if (args.containsKey("useNodeBrowseContexts") && Boolean.TRUE.equals(args.get("useNodeBrowseContexts"))) {
379                 useNodeBrowseContexts = true;
380         } else {
381                 useNodeBrowseContexts = false;
382         }
383         
384         if (args.containsKey("useNodeActionContexts") && Boolean.TRUE.equals(args.get("useNodeActionContexts"))) {
385                 useNodeActionContexts = true;
386         } else {
387                 useNodeActionContexts = false;
388         }
389         
390         toolComposite2 = new Composite(this, SWT.NONE);
391 //        toolComposite2.setBackground(toolComposite2.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
392 //        GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
393         GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite2);
394         GridLayoutFactory.fillDefaults().applyTo(toolComposite2);
395
396         this.support = support;
397
398         if (support != null)
399             support.register(this);
400
401     }
402
403     public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, int style) {
404
405         this(args, site, parent, null, style);
406
407     }
408
409     public ISessionContextProvider getSessionContextProvider(IWorkbenchSite site) {
410         if(site != null)
411             return SimanticsUI.getSessionContextProvider(site.getWorkbenchWindow());
412         else
413             return Simantics.getSessionContextProvider();
414     }
415
416     public GraphExplorer getExplorer() {
417         return explorer;
418     }
419
420     public Composite getExplorerComposite() {
421         return explorerComposite;
422     }
423
424     public <T> T getExplorerControl() {
425         return explorer.getControl();
426     }
427
428     public void addListenerToControl(int eventType, Listener listener) {
429         ((Control)explorer.getControl()).addListener(eventType, listener);
430     }
431
432     public void finish() {
433         created = true;
434         createControls(site);
435         attachToSession();
436     }
437
438     IWorkbenchSite getSite() {
439         return site;
440     }
441
442     protected void activateUiContexts() {
443         Collection<String> contexts = getUiContexts();
444         if (contexts == null || contexts.isEmpty())
445             return;
446         IWorkbenchSite site = getSite();
447         if (site != null) {
448             IContextService cs = (IContextService) getSite().getService(IContextService.class);
449             for (String context : contexts)
450                 cs.activateContext(context);
451         }
452     }
453
454     protected void createControls(IWorkbenchSite site) {
455
456         // Initialize explorer control.
457 //        GridDataFactory.fillDefaults().grab(true, true).applyTo(explorer.getControl());
458
459         Control control = explorer.getControl();
460
461         // Initialize context menu if an initializer is provided.
462         IContextMenuInitializer cmi = getContextMenuInitializer();
463         if (cmi != null) {
464             ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
465             menuManager = cmi.createContextMenu(control, selectionProvider, site);
466         }
467
468         // Initialize UI contexts
469         activateUiContexts();
470
471         // Initialize DND.
472         dragSource = setupDND(explorer);
473
474         // Listeners are only added once per listener, not every time the
475         // session context changes.
476         addListeners(explorer, menuManager);
477
478         userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor();
479         userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor();
480         filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor();
481         
482         explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
483
484         boolean hasExtraControls = false;
485         boolean hasExtraControls2 = false;
486
487         Boolean displaySelectors = (Boolean)args.get("displaySelectors");
488         if(displaySelectors == null || displaySelectors == true) {
489
490             @SuppressWarnings("unused")
491             ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
492 //            comparatorSelector.moveAbove(control);
493
494             @SuppressWarnings("unused")
495             ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
496 //            viewpointSelector.moveAbove(control);
497
498             hasExtraControls = true;
499
500         }
501
502         Boolean displayFilter = (Boolean)args.get("displayFilter");
503         if(displayFilter == null || displayFilter == true) {
504
505                 
506                 filterArea = filterAreaSource.getFilterArea(toolComposite, explorer);
507 //            filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite, SWT.READ_ONLY);
508             //filterArea.moveAbove(control);
509
510             hasExtraControls = true;
511
512         }
513
514         Boolean displayFilter2 = (Boolean)args.get("displayFilter2");
515         if(displayFilter2 != null && displayFilter2 == true) {
516
517                 filterArea = filterAreaSource.getFilterArea(toolComposite2, explorer);
518 //            filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite2, SWT.READ_ONLY);
519 //            //filterArea.moveAbove(control);
520
521             hasExtraControls2 = true;
522
523         }
524
525 //        filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, this, SWT.READ_ONLY);
526 //        filterArea.moveAbove(control);
527
528         if(!hasExtraControls)
529             GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite);
530         if(!hasExtraControls2)
531             GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite2);
532
533         GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control);
534
535         //tree.getTree().setLayout(new FillLayout()
536         //this.setLayout(LayoutUtils.createNoBorderGridLayout(2, false));
537
538         DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_DEFAULT);
539         target.setTransfer(getAcceptedDataTypes());
540         if (control instanceof Tree)  {
541         target.addDropListener(new DropTargetListener() {
542
543             Tree tree = (Tree)explorer.getControl();
544
545             @Override
546             public void dragEnter(DropTargetEvent event) {
547                 event.detail = DND.DROP_COPY;
548             }
549
550             @Override
551             public void dragLeave(DropTargetEvent event) {
552             }
553
554             @Override
555             public void dragOperationChanged(DropTargetEvent event) {
556             }
557
558             @Override
559             public void dragOver(DropTargetEvent event) {
560             }
561
562             @Override
563             public void drop(DropTargetEvent event) {
564                 TreeItem item = tree.getItem(tree.toControl(event.x, event.y));
565                 if(item != null) {
566                         Object data = item.getData();
567                         if (data instanceof NodeContext)
568                                 handleDrop(event.data, (NodeContext) data);
569                         else if (data instanceof IAdaptable) {
570                                 IAdaptable a = (IAdaptable) data;
571                                 handleDrop(event.data, (NodeContext) a.getAdapter(NodeContext.class));
572                         }
573                 } else
574                     handleDrop(event.data, null);
575             }
576
577             @Override
578             public void dropAccept(DropTargetEvent event) {
579             }
580
581         });
582         }
583
584         // Add workbench listeners and make sure they are cleaned up
585         setWorkbenchListeners();
586         control.addListener(SWT.Dispose, new Listener() {
587             @Override
588             public void handleEvent(Event event) {
589                 doDispose();
590             }
591         });
592     }
593
594     @SuppressWarnings({ "rawtypes", "unchecked" })
595     @Override
596     public Object getAdapter(Class adapter) {
597         if (GraphExplorer.class == adapter)
598             return explorer;
599         if (EvaluatorData.class == adapter)
600             return evaluatorData;
601         if (BrowseContext.class == adapter) {
602             EvaluatorData ed = evaluatorData;
603             return ed != null ? ed.getBrowseContext() : null;
604         }
605         if (adapter == IFilterAreaProvider.class)
606             return filterArea;
607         return explorer.getAdapter(adapter);
608     }
609
610     protected void doDispose() {
611         //System.out.println(this + ".GraphExplorerComposite.doDispose()");
612         removeWorkbenchListeners();
613         userSelectedComparableFactoryQueryProcessor = null;
614         userSelectedViewpointFactoryQueryProcessor = null;
615         filterSelectionRequestQueryProcessor = null;
616
617         disposeState = DisposeState.Disposing;
618         try {
619             //System.out.println(this + ".GraphExplorerViewBase.dispose()");
620             if (contextProvider != null) {
621                 contextProvider.removeContextChangedListener(contextChangeListener);
622                 contextProvider = null;
623             }
624             sessionContextTracker.untrack();
625             resourceManager = null;
626             explorer = null;
627             sessionContext = null;
628             dragSource = null;
629 //            parent = null;
630         } finally {
631             disposeState = DisposeState.Disposed;
632         }
633     }
634
635     @Override
636     public void dispose() {
637         doDispose();
638         super.dispose();
639     }
640
641     protected StatePersistor getStatePersistor() {
642         return persistor;
643     }
644     
645     public void setStatePersistor(StatePersistor persistor) {
646         this.persistor = persistor;
647     }
648     
649     protected void initializeExplorer(GraphExplorer explorer, ISessionContext context) {
650
651         if(explorer == null || explorer.isDisposed()) return;
652         if(context == null) return;
653         if(browseContexts == null) return;
654
655         Session session = context != null ? context.getSession() : null;
656         setupDragSource(session);
657
658         if (session != null) {
659             evaluatorData = createEvaluatorData(session);
660             explorer.setDataSource(new AsyncReadGraphDataSource(session));
661             explorer.setDataSource(new ReadGraphDataSource(session));
662         }
663         else {
664             evaluatorData = new EvaluatorDataImpl();
665             explorer.removeDataSource(AsyncReadGraph.class);
666             explorer.removeDataSource(ReadGraph.class);
667         }
668
669         explorer.setPersistor(getStatePersistor());
670         
671         explorer.setProcessor(new ComparableFactoryResolver(evaluatorData));
672         explorer.setProcessor(new ViewpointFactoryResolver(evaluatorData));
673         explorer.setProcessor(new LabelerFactoryResolver(evaluatorData));
674         explorer.setProcessor(new ImagerFactoryResolver(evaluatorData));
675         explorer.setProcessor(new LabelDecoratorFactoryResolver(evaluatorData));
676         explorer.setProcessor(new ImageDecoratorFactoryResolver(evaluatorData));
677         explorer.setProcessor(new DefaultIsCheckedProcessor2(evaluatorData));
678         explorer.setPrimitiveProcessor(new TypesQueryProcessor());
679         explorer.setPrimitiveProcessor(new StandardContextTypesQueryProcessor());
680         explorer.setPrimitiveProcessor(new InheritsQueryProcessor());
681         explorer.setPrimitiveProcessor(new RelatedObjectsQueryProcessor());
682
683         explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor);
684         explorer.setProcessor(new ComparableSelectorQueryProcessor());
685         explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor);
686         explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
687
688         initializeExplorerWithEvaluator(explorer, context, evaluatorData);
689     }
690
691     protected void initializeExplorerWithEvaluator(GraphExplorer explorer, ISessionContext context, EvaluatorData data) {
692     }
693
694     protected EvaluatorData createEvaluatorData(Session context) {
695
696 //        Set<String> browseContexts = getArgument("browseContexts");
697
698         return Evaluators.load(context.getSession(), browseContexts, resourceManager, useNodeBrowseContexts, useNodeActionContexts);
699
700     }
701
702     protected Transfer[] getAcceptedDataTypes() {
703         return new Transfer[] { LocalObjectTransfer.getTransfer(), FileTransfer.getInstance(), TextTransfer.getInstance() };
704     }
705
706     protected void handleDrop(Object data, NodeContext target) {
707     }
708
709     DragSourceListenerFactory dragSourceListenerFactory = new DragSourceListenerFactory() {
710
711         final Transfer[] transfers = new Transfer[] {LocalObjectTransfer.getTransfer(), TextTransfer.getInstance() };
712
713         @Override
714         public DragSourceListener get(ISelectionProvider selectionProvider) {
715
716                 LocalSelectionDragSourceListener ls = new LocalSelectionDragSourceListener(selectionProvider);
717
718                 return new DragSourceListener() {
719                                 
720                                 @Override
721                                 public void dragStart(DragSourceEvent event) {
722                                         ls.dragStart(event);
723                                 }
724                                 
725                                 @Override
726                                 public void dragSetData(DragSourceEvent event) {
727                                         if(TextTransfer.getInstance().isSupportedType(event.dataType)) {
728                                         try {
729                                                         event.data = WorkbenchSelectionUtils.getPossibleJSON(selectionProvider.getSelection());
730                                                 } catch (DatabaseException e) {
731                                                         event.data = "{ type:\"Exception\" }";
732                                                         LOGGER.error("Failed to get current selection as JSON.", e);
733                                                 }
734                                         } else if (LocalObjectTransfer.getTransfer().isSupportedType(event.dataType)) {
735                                                 ls.dragSetData(event);
736                                         }
737                                 }
738                                 
739                                 @Override
740                                 public void dragFinished(DragSourceEvent event) {
741                                         ls.dragFinished(event);
742                                 }
743                         };
744         }
745
746         @Override
747         public Transfer[] getTransfers() {
748             return transfers;
749         }
750
751     };
752
753     public void setDragSourceListenerFactory(DragSourceListenerFactory dragSourceListenerFactory) {
754         this.dragSourceListenerFactory = dragSourceListenerFactory;
755     }
756
757     protected DragSourceListener setupDND(GraphExplorer explorer) {
758
759         ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
760
761         DragSourceListener listener = createDragSourceListener(selectionProvider);
762
763         Control control = explorer.getControl();
764         DragSource source = createDragSource(control);
765         source.setTransfer(getTransfers());
766         source.addDragListener(listener);
767         source.setDragSourceEffect(new NoImageDragSourceEffect(control));
768
769         return listener;
770
771     }
772
773     protected DragSourceListener createDragSourceListener(ISelectionProvider selectionProvider) {
774         return dragSourceListenerFactory.get(selectionProvider);
775     }
776
777     private int dragStyle = DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
778
779     protected void setDragStyle(int style) {
780         this.dragStyle = style;
781     }
782
783     protected int getDragStyle() {
784         return dragStyle;
785     }
786
787     protected DragSource createDragSource(Control control) {
788         return new DragSource(control, getDragStyle());
789     }
790
791     protected Transfer[] getTransfers() {
792         return dragSourceListenerFactory.getTransfers();
793     }
794
795     public EvaluatorData getEvaluatorData() {
796         return evaluatorData;
797     }
798
799     public interface InputSource {
800         /**
801          * @param ctx the session context to read the input from. May be
802          *        <code>null</code> if there is no session.
803          * @return the input object of a graph explorer. To indicate no input,
804          *         use {@link GraphExplorerConstants#EMPTY_INPUT}. Never return
805          *         <code>null</code>.
806          */
807         Object get(ISessionContext ctx, Object selection);
808     }
809     
810     public interface FilterSource {
811         
812         
813         
814     }
815
816     /**
817      * The default hint tracker that will be active if
818      * {@link GraphExplorerComposite#setSessionContextTracker(IHintTracker) is
819      * not called.
820      */
821     public class SessionContextProjectTracker extends HintTracker {
822         public SessionContextProjectTracker() {
823             IHintListener activeProjectListener = new HintListenerAdapter() {
824                 @Override
825                 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
826                     applySessionContext(getSessionContext());
827                 }
828             };
829             addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);
830         }
831     }
832
833     public class DirectInputSource implements InputSource {
834         @Override
835         public Object get(ISessionContext ctx, Object selection) {
836             return selection;
837         }
838     }
839     
840     public static class SelectionFilterAreaSource implements FilterAreaSource {
841
842                 @Override
843                 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
844                         FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
845                         return new FilterArea(explorer, processor, parent, SWT.READ_ONLY);
846                 }
847         
848     }
849
850     public static class RootFilterAreaSource implements FilterAreaSource {
851
852                 @Override
853                 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
854                         FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
855                         return new RootFilterArea(explorer, processor, parent, SWT.READ_ONLY);
856                 }
857         
858     }
859
860     protected void setSessionContextTracker(IHintTracker tracker) {
861         this.sessionContextTracker = tracker;
862     }
863
864     public void setInputSource(InputSource source) {
865         this.inputSource = source;
866     }
867     
868     public void setFilterAreaSource(FilterAreaSource provider) {
869         this.filterAreaSource = provider;
870     }
871
872     public void setSelectionTransformation(BiFunction<GraphExplorer, Object[], Object[]> transformation) {
873         this.selectionTransformation = transformation;
874         if(explorer != null) explorer.setSelectionTransformation(transformation);
875     }
876
877     protected Set<String> getBrowseContexts() {
878         return browseContexts;
879     }
880     
881     public void setBrowseContexts(Set<String> contexts) {
882         this.browseContexts = contexts;
883         //initializeExplorer(explorer, getSessionContext());
884     }
885
886     public void setBrowseContexts(String ... contexts) {
887         this.browseContexts = new HashSet<String>();
888         for(String s : contexts) this.browseContexts.add(s);
889         initializeExplorer(explorer, getSessionContext());
890     }
891
892     public void setContextMenuId(String contextMenuId) {
893         this.contextMenuId = contextMenuId;
894     }
895
896 //    protected IContextMenuInitializer getContextMenuInitializer() {
897 //        String contextMenuId = getContextMenuId();
898 //        if(contextMenuId != null) {
899 //            return new ContextMenuInitializer(contextMenuId);
900 //        } else {
901 //            return null;
902 //        }
903 //    }
904
905     protected String getContextMenuId() {
906         return this.contextMenuId;
907     }
908
909     public void setUiContexts(Set<String> uiContext) {
910         this.uiContext = uiContext;
911     }
912
913     public Set<String> getUiContexts() {
914         return uiContext;
915     }
916
917     protected InputSource getInputSource() {
918         return inputSource;
919     }
920
921     protected Map<String, Object> getArguments() {
922         return args;
923     }
924
925     @SuppressWarnings("unchecked")
926     protected <T> T getArgument(String key) {
927         return (T) args.get(key);
928     }
929
930     protected DisposeState getDisposeState() {
931         return disposeState;
932     }
933
934     public ISessionContext getSessionContext() {
935         return sessionContext;
936     }
937
938     public ISessionContextProvider getSessionContextProvider() {
939         return contextProvider;
940     }
941
942     @Override
943     public boolean setFocus() {
944         if (explorer != null && !explorer.isDisposed())
945             explorer.setFocus();
946         return true;
947     }
948
949     public void setWorkbenchListeners() {
950         if (workbenchSelectionListener == null && getSite() != null) {
951             ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
952             getSite().setSelectionProvider(selectionProvider);
953
954             // Listen to the workbench selection also to propagate it to
955             // the explorer also.
956             workbenchSelectionListener = new DefaultExplorerSelectionListener(site.getPage().getActivePart(), explorer);
957             //System.out.println("ADD WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
958             getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener);
959         }
960     }
961
962     protected void removeWorkbenchListeners() {
963         //System.out.println("REMOVE WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
964         // Remember to remove the installed workbench selection listener
965         if (workbenchSelectionListener != null) {
966             getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener);
967             workbenchSelectionListener = null;
968
969             ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
970             if(getSite().getSelectionProvider() == selectionProvider) getSite().setSelectionProvider(null);
971             
972         }
973     }
974
975     protected final void attachToSession() {
976
977         // Track active ISessionContext changes
978         //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());
979         contextProvider.addContextChangedListener(contextChangeListener);
980
981         // Start tracking the current session context for input changes.
982         // This will/must cause applySessionContext to get called.
983         // Doing the applySessionContext initialization this way
984         // instead of directly calling it will also make sure that
985         // applySessionContext is only called once when first initialized,
986         // and not twice like with the direct invocation.
987         this.sessionContext = contextProvider.getSessionContext();
988         sessionContextTracker.track(sessionContext);
989     }
990
991     // /////////////////////////////////////////////////////////////////////////
992     // Override / implement these:
993
994 //    /**
995 //     * Returns an ID that is used for persisting a GraphExplorer instance.
996 //     *
997 //     * Used for </code>restoreState(IMemento)</code> and
998 //     * <code>restoreState(IMemento)</code> in OntologyExplorer. Must be unique
999 //     * within a workbench part.
1000 //     *
1001 //     * @return a unique name for this particular graph explorer view used for
1002 //     *         saving and restoring the state of this view part
1003 //     */
1004 //    public String getExplorerName() {
1005 //        return "GraphExplorerViewBase";
1006 //    }
1007
1008     /**
1009      * Override this method to add controls to the view part. This is invoked
1010      * before attaching the view part to a database session.
1011      * 
1012      * @param parent
1013      */
1014     protected void createControls(Composite parent) {
1015
1016     }
1017
1018     /**
1019      * Override this method and provide a proper context menu initializer if you
1020      * want to have this base class initialize one for you.
1021      * 
1022      * @return the initializer to be used by {@link #createControls(Composite)}
1023      */
1024     protected IContextMenuInitializer getContextMenuInitializer() {
1025         String contextMenuId = getContextMenuId();
1026         if(contextMenuId != null) {
1027             return new ContextMenuInitializer(contextMenuId);
1028         } else {
1029             return null;
1030         }
1031     }
1032
1033     /**
1034      * @param parent
1035      * @return
1036      */
1037     protected GraphExplorer createExplorerControl(Composite parent, Integer maxChildren) {
1038         GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1039         if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1040
1041         GraphExplorer ge = factory
1042         .selectionDataResolver(new DefaultSelectionDataResolver())
1043         .selectionTransformation(selectionTransformation)
1044         .setServiceLocator(site)
1045         .create(parent, style);
1046
1047         return ge;
1048     }
1049     
1050     protected GraphExplorer createExplorerControl2(Composite parent, Integer maxChildren) {
1051         GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1052         if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1053
1054         GraphExplorer ge = factory
1055         .selectionDataResolver(new DefaultSelectionDataResolver())
1056         .selectionTransformation(selectionTransformation)
1057         .setServiceLocator(site)
1058         .create2(parent, style);
1059
1060         return ge;
1061     }
1062     
1063     protected GraphExplorer createExplorerControl3(Composite parent, Integer maxChildren) {
1064         GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1065         if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1066
1067         GraphExplorer ge = factory
1068         .selectionDataResolver(new DefaultSelectionDataResolver())
1069         .selectionTransformation(selectionTransformation)
1070         .setServiceLocator(site)
1071         .create3(parent, style);
1072
1073         return ge;
1074     }
1075
1076     protected void setupDragSource(Session session) {
1077         if (dragSource instanceof SessionContainer) {
1078             ((SessionContainer) dragSource).setSession(session);
1079         }
1080     }
1081
1082     /**
1083      * Override to customize the addition of listeners a newly created
1084      * GraphExplorer.
1085      * 
1086      * @param explorer
1087      */
1088     protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {
1089         addSelectionInputListeners(explorer, menuManager);
1090     }
1091
1092     protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {
1093         // Consider ENTER presses to simulate mouse left button double clicks
1094         explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function<String[]>() {
1095             @Override
1096             public String[] execute(Object... obj) {
1097                 return getEditingColumn((NodeContext) obj[0]);
1098             }
1099         }));
1100         // Default double click handling
1101         explorer.addListener(new DefaultMouseListener(explorer));
1102     }
1103
1104     protected String[] getEditingColumn(NodeContext context) {
1105         return editingColumn;
1106     }
1107     
1108     public void setEditingColumn(String... columnKeysInOrderOfTrial) {
1109         this.editingColumn = columnKeysInOrderOfTrial;
1110     }
1111
1112     // Needed for preventing unnecessary re-initialization of the explorer with the same input.
1113     private Object currentInput;
1114     private Object currentRoot;
1115
1116     /**
1117      * Invoke this to reinitialize the explorer and reset its input. The input
1118      * will be resolved from the specified ISessionContext based on the
1119      * {@link SessionContextInputSource} that is currently in use. If the input
1120      * is identical to the previous input, nothing will be done.
1121      * 
1122      * @param context
1123      */
1124     public final boolean applySessionContext(ISessionContext context) {
1125
1126         // If control is not alive anymore, do nothing.
1127         //System.out.println(this + ": applySessionContext(" + context + "), explorer="  + explorer);
1128         if (disposeState != DisposeState.Alive)
1129             return false;
1130
1131         //System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");
1132         initializeExplorer(explorer, context);
1133
1134
1135         // Start tracking the session context.
1136         //
1137         // If this is not the same session that is currently tracked, it will
1138         // cause IHintListeners of the sessionContextTracker to fire.
1139         // For this we need the above input equality (identity) checking.
1140         // This is here just to make sure that we are tracking the correct
1141         // session context.
1142         sessionContextTracker.track(sessionContext);
1143
1144         this.sessionContext = context;
1145         Object root = inputSource.get(context, currentInput);
1146         if (ObjectUtils.objectEquals(root, currentRoot))
1147             return false;
1148
1149         currentRoot = root;
1150
1151         //System.out.println(this + ": setRoot(" + input + ")");
1152         explorer.setUIContexts(uiContext);
1153         explorer.setRoot(root);
1154
1155         return true;
1156
1157     }
1158
1159     protected boolean isImportantInput(Object previousSelection, Object selection) {
1160         return !ObjectUtils.objectEquals(previousSelection, selection);
1161     }
1162
1163     public void setInput(Object selection, boolean force) {
1164
1165         assert(created);
1166
1167         if (isDisposed())
1168             return;
1169         if (sessionContext == null)
1170             return;
1171
1172         // Check if this is a duplicate of the previous selection to reduce unnecessary flicker.
1173         if (!force && !isImportantInput(currentInput, selection))
1174             return;
1175
1176         currentInput = selection;
1177
1178         Object root = inputSource.get(sessionContext, selection);
1179
1180         currentRoot = root;
1181
1182         explorer.setUIContexts(uiContext);
1183
1184         if (root == null) {
1185             explorer.setRoot(GraphExplorer.EMPTY_INPUT);
1186         } else {
1187             explorer.setRoot(root);
1188         }
1189
1190     }
1191
1192     public void setColumnsVisible(boolean visible) {
1193         explorer.setColumnsVisible(visible);
1194     }
1195
1196     private int getColumnWidth(Column column, ExplorerState state) {
1197         // Get saved width from the persistor if there is one.
1198         if (state != null && state.columnWidths != null) {
1199                 Integer width = state.columnWidths.get(column.getLabel());
1200                 if (width != null)
1201                         return width;
1202         }
1203         return column.getWidth();
1204     }
1205     
1206     public void setColumns(Column[] columns) {
1207
1208         explorer.setColumns(columns, new Consumer<Map<Column, Object>>() {
1209
1210             @Override
1211             public void accept(Map<Column, Object> objects) {
1212                 ExplorerState state = null;
1213                 if (persistor != null) {
1214                         state = persistor.deserialize(
1215                                 Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
1216                                 explorer.getRoot());
1217                 }
1218
1219                 for(Map.Entry<Column, Object> entry : objects.entrySet()) {
1220                     Column column = entry.getKey();
1221                     TreeColumn treeColumn = (TreeColumn)entry.getValue();
1222
1223                     if (column.getWidth() < 0) {
1224                         throw new IllegalArgumentException("Column minimum width cannot be < 0, got " + column.getWidth());
1225                     }
1226
1227                     int width = getColumnWidth(column, state);
1228                     if(column.hasGrab()) {
1229                         
1230                         ad.setColumnData(treeColumn, new ColumnWeightData(column.getWeight(), width));
1231
1232                     } else {
1233
1234                         ad.setColumnData(treeColumn, new ColumnWeightData(0, width));
1235
1236                     }
1237
1238                 }
1239             }
1240
1241         });
1242
1243     }
1244
1245     @Override
1246     public void setInput(ISessionContext context, Object input) {
1247         setInput(input, false);
1248     }
1249
1250     public void setMaxChildren(int maxChildren) {
1251         explorer.setMaxChildren(maxChildren);
1252     }
1253     
1254     public <T> void addListener(ExplorerMouseListenerImpl<T> listener) {
1255         
1256         support.register(listener);
1257         listener.register(explorer);
1258         explorer.addListener(listener);
1259         
1260     }
1261
1262 //    @Override
1263 //    public Point computeSize(int wHint, int hHint) {
1264 //      Point p = super.computeSize(wHint, hHint);
1265 //      System.err.println("graphExplorerComposite.computeSize " + p);
1266 //      return p;
1267 //    }
1268 //    
1269 //    @Override
1270 //    public Point computeSize(int wHint, int hHint, boolean changed) {
1271 //      Point p = super.computeSize(wHint, hHint, changed);
1272 //      System.err.println("graphExplorerComposite.computeSize " + p);
1273 //      return p;
1274 //    }
1275     
1276 }