/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.browsing.ui.swt; import java.util.Map; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IMemento; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.services.IDisposable; import org.simantics.browsing.ui.Column; import org.simantics.browsing.ui.GraphExplorer; import org.simantics.browsing.ui.NodeContext; import org.simantics.browsing.ui.common.ColumnKeys; import org.simantics.browsing.ui.common.views.IViewArguments; import org.simantics.browsing.ui.graph.impl.SessionContextInputSource; import org.simantics.db.Session; import org.simantics.db.common.request.Queries; import org.simantics.db.exception.DatabaseException; import org.simantics.db.management.ISessionContext; import org.simantics.db.management.ISessionContextChangedListener; import org.simantics.db.management.ISessionContextProvider; import org.simantics.db.management.SessionContextChangedEvent; import org.simantics.project.IProject; import org.simantics.project.ProjectKeys; import org.simantics.ui.SimanticsUI; import org.simantics.ui.dnd.BasicDragSource; import org.simantics.ui.dnd.SessionContainer; import org.simantics.ui.workbench.IPropertyPage; import org.simantics.utils.ObjectUtils; import org.simantics.utils.datastructures.Function; import org.simantics.utils.datastructures.disposable.DisposeState; import org.simantics.utils.datastructures.hints.HintListenerAdapter; import org.simantics.utils.datastructures.hints.HintTracker; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintListener; import org.simantics.utils.datastructures.hints.IHintObservable; import org.simantics.utils.datastructures.hints.IHintTracker; import org.simantics.utils.ui.LayoutUtils; /** * An abstract base Eclipse workbench ViewPart for use in situations where a * tree-based GraphExplorer graph model browser is needed. * *
* Override to customize behavior: *
* You can invoke the following methods from within * {@link #createControls(Composite)} to customize how the view keeps track of * the active ISessionContext and how the view resolves the input object of the * GraphExplorer control. *
null
* to indicate that there is no input and nothing should be shown.
*/
@Override
public Object get(ISessionContext ctx) {
if (ctx == null)
return GraphExplorer.EMPTY_INPUT;
String inputId = getViewArguments().get(IViewArguments.INPUT);
if (inputId != null) {
try {
return ctx.getSession().syncRequest(Queries.resource(inputId));
} catch (DatabaseException e) {
// Ok, the view argument was invalid. Just continue to the next
// method.
}
}
Object input = GraphExplorer.EMPTY_INPUT;
IProject project2 = ctx.getHint(ProjectKeys.KEY_PROJECT);
if (project2 != null)
input = project2.get();
return input;
}
@Override
public IWorkbenchPart getProvider() {
return null;
}
}
protected LocalResourceManager resourceManager;
protected ISelectionListener workbenchSelectionListener;
protected Composite parent;
protected GraphExplorer explorer;
protected IMenuManager menuManager;
private MaprestoreState(IMemento)
in OntologyExplorer. Must be unique
// * within a workbench part.
// *
// * @return a unique name for this particular graph explorer view used for
// * saving and restoring the state of this view part
// */
// public String getExplorerName() {
// return "GraphExplorerViewBase";
// }
protected Column[] getColumns() {
return null;
}
/**
* Override this method to add controls to the view part. This is invoked
* before attaching the view part to a database session.
*
* @param parent
*/
protected void createControls(Composite parent) {
parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false));
// Initialize explorer control.
explorer = createExplorerControl(parent);
ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
Control control = explorer.getControl();
Column[] columns = getColumns();
if(columns != null)
explorer.setColumns(columns);
GridDataFactory.fillDefaults().grab(true, true).applyTo(control);
// Initialize context menu if an initializer is provided.
IContextMenuInitializer cmi = getContextMenuInitializer();
if (cmi != null) {
menuManager = cmi.createContextMenu(control, selectionProvider, getSite());
}
// Initialize DND.
dragSource = createDragSource(explorer);
// Listeners are only added once per listener, not every time the
// session context changes.
addListeners(explorer, menuManager);
}
/**
* Override this method and provide a proper context menu initializer if you
* want to have this base class initialize one for you.
*
* @return the initializer to be used by {@link #createControls(Composite)}
*/
protected IContextMenuInitializer getContextMenuInitializer() {
String contextMenuId = getContextMenuId();
if(contextMenuId != null) {
return new ContextMenuInitializer(contextMenuId);
} else {
return null;
}
}
/**
* @return the ID of the context menu to initialize for this this graph
* explorer view or null
to not initialize a context
* menu
*/
protected String getContextMenuId() {
return null;
}
protected int getStyle() {
return SWT.MULTI;
}
/**
* @param parent
* @return
*/
protected GraphExplorer createExplorerControl(Composite parent) {
return GraphExplorerFactory.getInstance()
.selectionDataResolver(new DefaultSelectionDataResolver())
.create(parent, getStyle());
}
/**
* Override to customize drag source initialization. This default
* implementation creates a {@link BasicDragSource}. The drag source is
* initialized when the active database session is set.
*
* @param explorer
* @return the object representing the drag source. If the object implements
* {@link SessionContainer}, its
* {@link SessionContainer#setSession(Session)} will be invoked
* every time the active database session changes.
*/
protected Object createDragSource(GraphExplorer explorer) {
ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
Control control = explorer.getControl();
return new BasicDragSource(selectionProvider, control, null);
}
protected void setupDragSource(Session session) {
if (dragSource instanceof SessionContainer) {
((SessionContainer) dragSource).setSession(session);
}
}
/**
* Override to customize the addition of listeners a newly created
* GraphExplorer.
*
* @param explorer
*/
protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {
addSelectionInputListeners(explorer, menuManager);
}
protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {
// Consider ENTER presses to simulate mouse left button double clicks
explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Functionnull
if there is no session
*/
protected void initializeExplorer(final GraphExplorer explorer, ISessionContext context) {
setupDragSource((context != null) ? context.getSession() : null);
}
// Needed for preventing unnecessary re-initialization of the explorer with the same input.
private Object currentInput;
protected boolean isImportantInput(Object previousInput, Object input) {
return !ObjectUtils.objectEquals(previousInput, input);
}
/**
* Invoke this to reinitialize the explorer and reset its input. The input
* will be resolved from the specified ISessionContext based on the
* {@link SessionContextInputSource} that is currently in use. If the input
* is identical to the previous input, nothing will be done.
*
* @param context
*/
protected final boolean applySessionContext(ISessionContext context) {
// If control is not alive anymore, do nothing.
// System.out.println(this + ": applySessionContext(" + context + "), explorer=" + explorer);
if (disposeState != DisposeState.Alive)
return false;
this.sessionContext = context;
Object input = inputSource.get(context);
if (!isImportantInput(currentInput, input))
return false;
// System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");
initializeExplorer(explorer, context);
// System.out.println(this + ": setRoot(" + input + ")");
explorer.setRoot(input);
currentInput = input;
// Start tracking the session context.
//
// If this is not the same session that is currently tracked, it will
// cause IHintListeners of the sessionContextTracker to fire.
// For this we need the above input equality (identity) checking.
// This is here just to make sure that we are tracking the correct
// session context.
sessionContextTracker.track(sessionContext);
return true;
}
@SuppressWarnings("unchecked")
@Override
public