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