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