1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.ui.contribution;
14 import org.eclipse.jface.action.ActionContributionItem;
15 import org.eclipse.jface.action.IAction;
16 import org.eclipse.jface.action.IContributionItem;
17 import org.eclipse.jface.viewers.ISelection;
18 import org.eclipse.jface.viewers.IStructuredSelection;
19 import org.eclipse.ui.ISelectionService;
20 import org.eclipse.ui.IWorkbenchWindow;
21 import org.eclipse.ui.PlatformUI;
22 import org.eclipse.ui.actions.CompoundContributionItem;
23 import org.simantics.DatabaseJob;
24 import org.simantics.Simantics;
25 import org.simantics.db.ReadGraph;
26 import org.simantics.db.common.request.UniqueRead;
27 import org.simantics.db.common.utils.RequestUtil;
28 import org.simantics.db.exception.DatabaseException;
29 import org.simantics.db.management.ISessionContext;
30 import org.simantics.ui.SimanticsUI;
31 import org.simantics.utils.ui.ErrorLogger;
34 * A more or less carbon copy of CompoundContributionItem with the exception of
35 * adding Simantics Graph database traits to the menu filling process.
38 * The simplest way to use this class is to override the
39 * {@link #getActions(ReadGraph, Object[])} method which should return any
40 * actions that you want to be performed on the specified selection. Another way
41 * is to override {@link #getContributionItems(ReadGraph, Object[])} that by
42 * default simply invokes the simplest method
43 * {@link #getActions(ReadGraph, Object[])}. Overriding it allows you to create
44 * e.g. submenus, which you cannot do with actions.
48 * To customize what gets passed to either
49 * {@link #getActions(ReadGraph, Object[])} or
50 * {@link #getContributionItems(ReadGraph, Object[])} as the selection
51 * parameter, override {@link #getSelectedObjects()}
54 * @author Tuukka Lehtonen
56 public abstract class DynamicMenuContribution extends CompoundContributionItem {
58 protected static final Object[] NO_OBJECTS = {};
59 protected static final IAction[] NO_ACTIONS = {};
60 protected static final IContributionItem[] NONE = {};
63 * Creates a contribution item with a <code>null</code> id.
65 protected DynamicMenuContribution() {
70 * Creates a contribution item with the given (optional) id.
72 * @param id the contribution item identifier, or <code>null</code>
74 protected DynamicMenuContribution(String id) {
79 * @see org.eclipse.ui.actions.CompoundContributionItem#getContributionItems()
82 protected final IContributionItem[] getContributionItems() {
83 if (DatabaseJob.inProgress())
85 ISessionContext ctx = SimanticsUI.getSessionContext();
87 final Object[] selection = getSelectedObjects();
88 //System.out.println(getClass().getSimpleName() + "@" + System.identityHashCode(this) + "( " + System.identityHashCode(selection) + ": " + Arrays.toString(selection) + " )");
89 if (!preAcceptSelection(selection))
92 return RequestUtil.trySyncRequest(
93 Simantics.getSession(),
94 SimanticsUI.UI_THREAD_REQUEST_START_TIMEOUT,
95 SimanticsUI.UI_THREAD_REQUEST_EXECUTION_TIMEOUT_LONG,
97 new UniqueRead<IContributionItem[]>() {
99 public IContributionItem[] perform(ReadGraph graph) throws DatabaseException {
100 return getContributionItems(graph, selection);
103 public String toString() {
104 return DynamicMenuContribution.this.toString();
107 } catch (DatabaseException | InterruptedException e) {
108 ErrorLogger.defaultLogError(e);
115 * @see org.eclipse.ui.actions.CompoundContributionItem#isDynamic()
118 public boolean isDynamic() {
122 //////////////////////////////////////////////////////////////////////////
124 protected ISelection getSelection() {
125 IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
126 ISelectionService service = window.getSelectionService();
127 return service.getSelection();
130 protected Object[] getSelectedObjects() {
131 ISelection sel = getSelection();
132 if (!(sel instanceof IStructuredSelection))
134 return ((IStructuredSelection) sel).toArray();
137 protected Object getSingleSelectedObject() {
138 Object[] resources = getSelectedObjects();
139 return resources.length == 1 ? resources[0] : null;
142 protected IContributionItem[] toContributionItems(IAction... actions) {
146 IContributionItem[] ret = new IContributionItem[actions.length];
147 for (int i = 0; i < actions.length; ++i)
148 ret[i] = new ActionContributionItem(actions[i]);
153 //////////////////////////////////////////////////////////////////////////
154 // Override these where needed
157 * Tests the input selection for whether it can produce any meaningful
158 * contribution items in the first place. This is a filter that is invoked
159 * before performing a database request to find out more about the possible
163 * The default implementation checks that the input selection is not empty.
164 * To be able to provide contributions for empty selection, you must
165 * override this method.
170 protected boolean preAcceptSelection(Object[] selection) {
171 return selection != null && selection.length > 0;
174 protected IContributionItem[] getContributionItems(ReadGraph graph, Object[] selection) throws DatabaseException {
175 return toContributionItems( getActions(graph, selection) );
178 protected IAction[] getActions(ReadGraph graph, Object[] selection) throws DatabaseException {
179 return new IAction[0];