--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.ui.contribution;\r
+\r
+import org.eclipse.jface.action.ActionContributionItem;\r
+import org.eclipse.jface.action.IAction;\r
+import org.eclipse.jface.action.IContributionItem;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.ui.ISelectionService;\r
+import org.eclipse.ui.IWorkbenchWindow;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.eclipse.ui.actions.CompoundContributionItem;\r
+import org.simantics.DatabaseJob;\r
+import org.simantics.Simantics;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.common.request.UniqueRead;\r
+import org.simantics.db.common.utils.RequestUtil;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+\r
+/**\r
+ * A more or less carbon copy of CompoundContributionItem with the exception of\r
+ * adding Simantics Graph database traits to the menu filling process.\r
+ * \r
+ * <p>\r
+ * The simplest way to use this class is to override the\r
+ * {@link #getActions(ReadGraph, Object[])} method which should return any\r
+ * actions that you want to be performed on the specified selection. Another way\r
+ * is to override {@link #getContributionItems(ReadGraph, Object[])} that by\r
+ * default simply invokes the simplest method\r
+ * {@link #getActions(ReadGraph, Object[])}. Overriding it allows you to create\r
+ * e.g. submenus, which you cannot do with actions.\r
+ * </p>\r
+ * \r
+ * <p>\r
+ * To customize what gets passed to either\r
+ * {@link #getActions(ReadGraph, Object[])} or\r
+ * {@link #getContributionItems(ReadGraph, Object[])} as the selection\r
+ * parameter, override {@link #getSelectedObjects()}\r
+ * </p>\r
+ * \r
+ * @author Tuukka Lehtonen\r
+ */\r
+public abstract class DynamicMenuContribution extends CompoundContributionItem {\r
+\r
+ protected static final Object[] NO_OBJECTS = {};\r
+ protected static final IAction[] NO_ACTIONS = {};\r
+ protected static final IContributionItem[] NONE = {};\r
+\r
+ /**\r
+ * Creates a contribution item with a <code>null</code> id.\r
+ */\r
+ protected DynamicMenuContribution() {\r
+ super();\r
+ }\r
+\r
+ /**\r
+ * Creates a contribution item with the given (optional) id.\r
+ *\r
+ * @param id the contribution item identifier, or <code>null</code>\r
+ */\r
+ protected DynamicMenuContribution(String id) {\r
+ super(id);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see org.eclipse.ui.actions.CompoundContributionItem#getContributionItems()\r
+ */\r
+ @Override\r
+ protected final IContributionItem[] getContributionItems() {\r
+ if (DatabaseJob.inProgress())\r
+ return NONE;\r
+ ISessionContext ctx = SimanticsUI.getSessionContext();\r
+ if (ctx != null) {\r
+ final Object[] selection = getSelectedObjects();\r
+ //System.out.println(getClass().getSimpleName() + "@" + System.identityHashCode(this) + "( " + System.identityHashCode(selection) + ": " + Arrays.toString(selection) + " )");\r
+ if (!preAcceptSelection(selection))\r
+ return NONE;\r
+ try {\r
+ return RequestUtil.trySyncRequest(\r
+ Simantics.getSession(),\r
+ SimanticsUI.UI_THREAD_REQUEST_START_TIMEOUT,\r
+ SimanticsUI.UI_THREAD_REQUEST_EXECUTION_TIMEOUT_LONG,\r
+ NONE,\r
+ new UniqueRead<IContributionItem[]>() {\r
+ @Override\r
+ public IContributionItem[] perform(ReadGraph graph) throws DatabaseException {\r
+ return getContributionItems(graph, selection);\r
+ }\r
+ @Override\r
+ public String toString() {\r
+ return DynamicMenuContribution.this.toString();\r
+ }\r
+ });\r
+ } catch (DatabaseException | InterruptedException e) {\r
+ ErrorLogger.defaultLogError(e);\r
+ }\r
+ }\r
+ return NONE;\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see org.eclipse.ui.actions.CompoundContributionItem#isDynamic()\r
+ */\r
+ @Override\r
+ public boolean isDynamic() {\r
+ return true;\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ protected ISelection getSelection() {\r
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();\r
+ ISelectionService service = window.getSelectionService();\r
+ return service.getSelection();\r
+ }\r
+\r
+ protected Object[] getSelectedObjects() {\r
+ ISelection sel = getSelection();\r
+ if (!(sel instanceof IStructuredSelection))\r
+ return NO_OBJECTS;\r
+ return ((IStructuredSelection) sel).toArray();\r
+ }\r
+\r
+ protected Object getSingleSelectedObject() {\r
+ Object[] resources = getSelectedObjects();\r
+ return resources.length == 1 ? resources[0] : null;\r
+ }\r
+\r
+ protected IContributionItem[] toContributionItems(IAction... actions) {\r
+ if (actions == null)\r
+ return NONE;\r
+\r
+ IContributionItem[] ret = new IContributionItem[actions.length];\r
+ for (int i = 0; i < actions.length; ++i)\r
+ ret[i] = new ActionContributionItem(actions[i]);\r
+\r
+ return ret;\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+ // Override these where needed\r
+\r
+ /**\r
+ * Tests the input selection for whether it can produce any meaningful\r
+ * contribution items in the first place. This is a filter that is invoked\r
+ * before performing a database request to find out more about the possible\r
+ * contributions.\r
+ * \r
+ * <p>\r
+ * The default implementation checks that the input selection is not empty.\r
+ * To be able to provide contributions for empty selection, you must\r
+ * override this method.\r
+ * \r
+ * @param selection\r
+ * @return\r
+ */\r
+ protected boolean preAcceptSelection(Object[] selection) {\r
+ return selection != null && selection.length > 0;\r
+ }\r
+\r
+ protected IContributionItem[] getContributionItems(ReadGraph graph, Object[] selection) throws DatabaseException {\r
+ return toContributionItems( getActions(graph, selection) );\r
+ }\r
+\r
+ protected IAction[] getActions(ReadGraph graph, Object[] selection) throws DatabaseException {\r
+ return new IAction[0];\r
+ }\r
+\r
+}\r