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