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