1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2012 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.browsing.ui.swt;
\r
14 import java.util.Collections;
\r
15 import java.util.Map;
\r
16 import java.util.Set;
\r
18 import org.eclipse.jface.action.IMenuManager;
\r
19 import org.eclipse.jface.dialogs.Dialog;
\r
20 import org.eclipse.jface.resource.LocalResourceManager;
\r
21 import org.eclipse.jface.viewers.ISelectionProvider;
\r
22 import org.eclipse.swt.SWT;
\r
23 import org.eclipse.swt.dnd.DND;
\r
24 import org.eclipse.swt.dnd.DragSource;
\r
25 import org.eclipse.swt.dnd.DragSourceListener;
\r
26 import org.eclipse.swt.dnd.Transfer;
\r
27 import org.eclipse.swt.widgets.Composite;
\r
28 import org.eclipse.swt.widgets.Control;
\r
29 import org.eclipse.swt.widgets.Shell;
\r
30 import org.eclipse.ui.IMemento;
\r
31 import org.eclipse.ui.ISelectionListener;
\r
32 import org.simantics.Simantics;
\r
33 import org.simantics.browsing.ui.BuiltinKeys;
\r
34 import org.simantics.browsing.ui.GraphExplorer;
\r
35 import org.simantics.browsing.ui.NodeContext;
\r
36 import org.simantics.browsing.ui.common.ColumnKeys;
\r
37 import org.simantics.browsing.ui.common.node.IDropTargetNode;
\r
38 import org.simantics.browsing.ui.graph.impl.GraphInputSources;
\r
39 import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
\r
40 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;
\r
41 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl;
\r
42 import org.simantics.db.management.ISessionContext;
\r
43 import org.simantics.project.ProjectKeys;
\r
44 import org.simantics.ui.dnd.LocalObjectTransfer;
\r
45 import org.simantics.ui.dnd.LocalSelectionDragSourceListener;
\r
46 import org.simantics.ui.dnd.NoImageDragSourceEffect;
\r
47 import org.simantics.utils.ObjectUtils;
\r
48 import org.simantics.utils.datastructures.Function;
\r
49 import org.simantics.utils.datastructures.disposable.DisposeState;
\r
50 import org.simantics.utils.datastructures.hints.HintContext;
\r
51 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
\r
52 import org.simantics.utils.datastructures.hints.HintTracker;
\r
53 import org.simantics.utils.datastructures.hints.IHintContext;
\r
54 import org.simantics.utils.datastructures.hints.IHintContext.Key;
\r
55 import org.simantics.utils.datastructures.hints.IHintListener;
\r
56 import org.simantics.utils.datastructures.hints.IHintObservable;
\r
57 import org.simantics.utils.datastructures.hints.IHintTracker;
\r
59 public abstract class SimanticsDialog extends Dialog {
\r
61 private final WidgetSupportImpl widgetSupport = new WidgetSupportImpl();
\r
63 protected IHintContext factoryHints = new HintContext();
\r
65 protected LocalResourceManager resourceManager;
\r
67 protected ISelectionListener workbenchSelectionListener;
\r
69 protected Composite parent;
\r
71 private Map<String, String> args;
\r
73 // private ISessionContextProvider contextProvider;
\r
75 private ISessionContext sessionContext;
\r
77 protected IMemento memento;
\r
79 //private IHintTracker sessionContextTracker = new SessionContextProjectTracker();
\r
81 private SessionContextInputSource inputSource = GraphInputSources.projectSource();
\r
83 private DisposeState disposeState = DisposeState.Alive;
\r
85 private final String title;
\r
87 // protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {
\r
89 // public void sessionContextChanged(SessionContextChangedEvent event) {
\r
90 // sessionContext = event.getNewValue();
\r
91 // sessionContextTracker.track(sessionContext);
\r
95 abstract protected void createControls(Composite body, ISessionContext context, WidgetSupport support);
\r
97 public SimanticsDialog(Shell shell, String title) {
\r
103 protected void configureShell(Shell shell) {
\r
104 super.configureShell(shell);
\r
105 if (title != null) {
\r
106 shell.setText(title);
\r
110 protected Transfer[] getAcceptedDataTypes() {
\r
111 return new Transfer[] { LocalObjectTransfer.getTransfer() };
\r
114 protected void handleDrop(Object data, NodeContext target) {
\r
115 if (target != null) {
\r
116 Object input = target.getConstant(BuiltinKeys.INPUT);
\r
117 //System.out.println("DROPPED " + data + " ON " + target);
\r
118 if (input instanceof IDropTargetNode)
\r
119 ((IDropTargetNode) input).drop(data);
\r
123 protected Object createDragSource(GraphExplorer explorer) {
\r
124 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
\r
126 DragSourceListener listener = new LocalSelectionDragSourceListener(selectionProvider);
\r
128 Control control = explorer.getControl();
\r
129 DragSource source = new DragSource(control, DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT);
\r
130 source.setTransfer(new Transfer[] {LocalObjectTransfer.getTransfer()});
\r
131 source.addDragListener(listener);
\r
132 source.setDragSourceEffect(new NoImageDragSourceEffect(control));
\r
138 * @return the set of <code>org.eclipse.ui.context</code> contexts to
\r
139 * activate for this view site
\r
141 protected Set<String> getUiContexts() {
\r
142 return Collections.emptySet();
\r
146 * The default hint tracker that will be active if
\r
147 * {@link SimanticsViewBase#setSessionContextTracker(IHintTracker) is
\r
150 public class SessionContextProjectTracker extends HintTracker {
\r
151 public SessionContextProjectTracker() {
\r
152 IHintListener activeProjectListener = new HintListenerAdapter() {
\r
154 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
\r
155 applySessionContext(getSessionContext());
\r
158 addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);
\r
162 // protected void setSessionContextTracker(IHintTracker tracker) {
\r
163 // this.sessionContextTracker = tracker;
\r
166 protected void setInputSource(SessionContextInputSource source) {
\r
167 this.inputSource = source;
\r
170 protected SessionContextInputSource getInputSource() {
\r
171 return inputSource;
\r
174 protected Map<String, String> getViewArguments() {
\r
178 protected DisposeState getDisposeState() {
\r
179 return disposeState;
\r
182 public ISessionContext getSessionContext() {
\r
183 return Simantics.getSessionContext();
\r
186 // public ISessionContextProvider getSessionContextProvider() {
\r
187 // return contextProvider;
\r
190 protected final void attachToSession() {
\r
191 // Track active ISessionContext changes
\r
192 //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());
\r
193 // contextProvider.addContextChangedListener(contextChangeListener);
\r
195 // Start tracking the current session context for input changes.
\r
196 // This will/must cause applySessionContext to get called.
\r
197 // Doing the applySessionContext initialization this way
\r
198 // instead of directly calling it will also make sure that
\r
199 // applySessionContext is only called once when first initialized,
\r
200 // and not twice like with the direct invocation.
\r
201 this.sessionContext = getSessionContext();
\r
202 applySessionContext(this.sessionContext);
\r
203 // sessionContextTracker.track(sessionContext);
\r
206 // /////////////////////////////////////////////////////////////////////////
\r
207 // Override / implement these:
\r
210 * Override this method and provide a proper context menu initializer if you
\r
211 * want to have this base class initialize one for you.
\r
213 * @return the initializer to be used by {@link #createControls(Composite)}
\r
215 protected IContextMenuInitializer getContextMenuInitializer() {
\r
216 String contextMenuId = getContextMenuId();
\r
217 if(contextMenuId != null) {
\r
218 return new ContextMenuInitializer(contextMenuId);
\r
224 protected String getContextMenuId() {
\r
228 protected int getStyle() {
\r
236 protected GraphExplorer createExplorerControl(Composite parent) {
\r
237 return GraphExplorerFactory.getInstance()
\r
238 .selectionDataResolver(new DefaultSelectionDataResolver())
\r
239 .create(parent, getStyle());
\r
243 * Override to customize the addition of listeners a newly created
\r
248 protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {
\r
249 addSelectionInputListeners(explorer, menuManager);
\r
252 protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {
\r
253 // Consider ENTER presses to simulate mouse left button double clicks
\r
254 explorer.addListener(new DefaultKeyListener(Simantics.getSessionContextProvider(), explorer, new Function<String[]>() {
\r
256 public String[] execute(Object... obj) {
\r
257 return new String[] { getEditingColumn((NodeContext) obj[0]) };
\r
260 // Default double click handling
\r
261 explorer.addListener(new DefaultMouseListener(explorer));
\r
264 protected String getEditingColumn(NodeContext context) {
\r
265 return ColumnKeys.SINGLE;
\r
268 // Needed for preventing unnecessary re-initialization of the explorer with the same input.
\r
269 private Object currentInput;
\r
271 protected boolean isImportantInput(Object previousInput, Object input) {
\r
272 return !ObjectUtils.objectEquals(previousInput, input);
\r
276 * Invoke this to reinitialize the explorer and reset its input. The input
\r
277 * will be resolved from the specified ISessionContext based on the
\r
278 * {@link SessionContextInputSource} that is currently in use. If the input
\r
279 * is identical to the previous input, nothing will be done.
\r
283 protected final boolean applySessionContext(ISessionContext context) {
\r
285 // If control is not alive anymore, do nothing.
\r
286 // System.out.println(this + ": applySessionContext(" + context + "), explorer=" + explorer);
\r
287 if (disposeState != DisposeState.Alive)
\r
290 this.sessionContext = context;
\r
291 Object input = getInputSource().get(context);
\r
292 // System.out.println("SimanticsView applySessionContext: " + input);
\r
293 if (!isImportantInput(currentInput, input))
\r
296 // System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");
\r
297 // initializeExplorer(explorer, context);
\r
298 // System.out.println(this + ": setRoot(" + input + ")");
\r
299 // explorer.setRoot(input);
\r
301 currentInput = input;
\r
302 // System.out.println("SimanticsView new input: " + currentInput);
\r
304 widgetSupport.fireInput(context, input);
\r
306 // Start tracking the session context.
\r
308 // If this is not the same session that is currently tracked, it will
\r
309 // cause IHintListeners of the sessionContextTracker to fire.
\r
310 // For this we need the above input equality (identity) checking.
\r
311 // This is here just to make sure that we are tracking the correct
\r
312 // session context.
\r
313 //sessionContextTracker.track(sessionContext);
\r
314 applySessionContext(context);
\r
319 protected Control createDialogArea(Composite parent) {
\r
320 // parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_GREEN));
\r
321 this.parent = parent;
\r
322 Composite composite = (Composite)super.createDialogArea(parent);
\r
323 // parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_BLUE));
\r
324 createControls(composite, sessionContext, widgetSupport);
\r
330 protected Control createContents(Composite parent) {
\r
331 // parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_RED));
\r
332 return super.createContents(parent);
\r
335 protected Object getSelection() {
\r