1 package org.simantics.modeling.ui.actions.e4;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
10 import java.util.concurrent.atomic.AtomicReference;
12 import javax.annotation.PostConstruct;
13 import javax.annotation.PreDestroy;
14 import javax.inject.Inject;
16 import org.eclipse.core.runtime.IStatus;
17 import org.eclipse.core.runtime.Status;
18 import org.eclipse.e4.ui.di.UISynchronize;
19 import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
20 import org.eclipse.jface.action.Action;
21 import org.eclipse.jface.action.ActionContributionItem;
22 import org.eclipse.jface.action.IContributionItem;
23 import org.eclipse.jface.action.MenuManager;
24 import org.eclipse.jface.action.Separator;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.Control;
27 import org.eclipse.swt.widgets.ToolBar;
28 import org.eclipse.swt.widgets.ToolItem;
29 import org.simantics.Simantics;
30 import org.simantics.browsing.ui.NodeContext;
31 import org.simantics.browsing.ui.common.NodeContextBuilder;
32 import org.simantics.browsing.ui.model.InvalidContribution;
33 import org.simantics.browsing.ui.model.actions.ActionBrowseContext;
34 import org.simantics.browsing.ui.model.actions.IActionCategory;
35 import org.simantics.db.ReadGraph;
36 import org.simantics.db.Resource;
37 import org.simantics.db.common.request.BinaryRead;
38 import org.simantics.db.exception.DatabaseException;
39 import org.simantics.db.procedure.Listener;
40 import org.simantics.modeling.ui.Activator;
43 * Used like this in E4 model fragments:
46 * <fragments xsi:type="fragment:StringModelFragment" featurename="trimContributions" parentElementId="org.eclipse.e4.legacy.ide.application">
47 * <elements xsi:type="menu:TrimContribution" elementId="modeled.trim.id" parentId="org.eclipse.ui.main.toolbar" positionInParent="after=additions">
48 * <children xsi:type="menu:ToolBar" elementId="toolbar.id">
49 * <children xsi:type="menu:ToolControl" elementId="toolcontrol.id" contributionURI="bundleclass://org.simantics.modeling.ui/org.simantics.modeling.ui.actions.GlobalModeledToolbarActions">
50 * <tags>http://www.simantics.org/Project-1.2/MainToolbarActionContext</tags>
57 * @author Antti Villberg
58 * @author Jani Simomaa
59 * @author Tuukka Lehtonen
61 public class GlobalModeledToolbarActions {
63 @Inject UISynchronize sync;
65 private List<String> browseContexts;
66 private boolean disposed;
67 private Composite composite;
70 protected void create(Composite parent, MToolControl control) {
71 this.composite = parent;
72 browseContexts = new ArrayList<>(control.getTags());
73 Simantics.getSession().asyncRequest(
74 new GetContributions(Simantics.getProjectResource(), browseContexts),
75 new ContributionListener());
79 private void dispose() {
81 if (composite != null) {
82 for (Control c : composite.getChildren())
88 class ContributionListener implements Listener<List<IContributionItem>>, Runnable {
90 AtomicReference<List<IContributionItem>> lastResult = new AtomicReference<>();
93 public void execute(List<IContributionItem> result) {
94 if (composite != null) {
95 lastResult.set(result);
102 List<IContributionItem> result = lastResult.getAndSet(null);
103 if (result == null || composite == null || composite.isDisposed())
106 ToolBar tb = (ToolBar) composite.getParent();
107 for (ToolItem item : tb.getItems())
109 for (IContributionItem item : result)
112 Composite tbp = tb.getParent();
113 tbp.layout(true, true);
117 public void exception(Throwable t) {
118 Activator.getDefault().getLog().log(
119 new Status(IStatus.ERROR, Activator.PLUGIN_ID,
120 "Global modeled toolbar contribution listener ran into an unexpected exception.",
125 public boolean isDisposed() {
130 static class GetContributions extends BinaryRead<Resource, Collection<String>, List<IContributionItem>> {
131 public GetContributions(Resource from, Collection<String> browseContextNames) {
132 super(from, browseContextNames);
135 public List<IContributionItem> perform(ReadGraph graph) throws DatabaseException {
136 return getContributionItems(graph, parameter, parameter2);
140 private static Collection<Resource> getBrowseContextResources(ReadGraph graph, Collection<String> browseContexts) throws DatabaseException {
141 List<Resource> result = new ArrayList<Resource>(browseContexts.size());
142 for (String name : browseContexts)
143 result.add(graph.getResource(name));
147 private static List<IContributionItem> getContributionItems(ReadGraph graph, Resource from, Collection<String> browseContextNames) throws DatabaseException {
148 Collection<Resource> browseContexts = getBrowseContextResources(graph, browseContextNames);
149 NodeContext nodeContext = NodeContextBuilder.buildWithInput(from);
151 ActionBrowseContext defaultContext = ActionBrowseContext.create(graph, browseContexts);
152 ActionBrowseContext browseContext = ActionBrowseContext.get(graph, nodeContext, defaultContext);
153 Map<IActionCategory, List<Action>> result = browseContext.getActions(graph, nodeContext, Collections.singletonList(nodeContext));
154 return toContributionItems(result);
155 } catch (InvalidContribution e) {
156 Activator.getDefault().getLog().log(
157 new Status(IStatus.ERROR, Activator.PLUGIN_ID,
158 "Encountered invalid modeled contribution(s) while loading global modeled toolbar contributions.",
162 return Collections.emptyList();
165 private static List<IContributionItem> toContributionItems(Map<IActionCategory, List<Action>> map) {
167 return Collections.emptyList();
169 IActionCategory[] categories = map.keySet().toArray(new IActionCategory[map.size()]);
170 Arrays.sort(categories, IActionCategory.ACTION_CATEGORY_COMPARATOR);
172 ArrayList<IContributionItem> items = new ArrayList<>();
173 boolean first = true;
174 for (IActionCategory category : categories) {
175 List<Action> actions = map.get(category);
176 Collections.sort(actions, ACTION_COMPARATOR);
178 if (category != null && category.isSubmenu()) {
179 MenuManager manager = new MenuManager(category.getLabel());
180 for (Action action : actions)
181 manager.add(new ActionContributionItem(action));
188 items.add(new Separator(category == null ? "" : category.getLabel()));
189 for (Action action : actions)
190 items.add(new ActionContributionItem(action));
197 private static final Comparator<Action> ACTION_COMPARATOR = (o1, o2) -> {
198 String t1 = o1.getText();
199 String t2 = o2.getText();
201 (t2 == null ? 0 : -1)
202 : (t2 == null ? 1 : t1.compareTo(t2));