]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/actions/e4/GlobalModeledToolbarActions.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / actions / e4 / GlobalModeledToolbarActions.java
1 package org.simantics.modeling.ui.actions.e4;\r
2 \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
11 \r
12 import javax.annotation.PostConstruct;\r
13 import javax.annotation.PreDestroy;\r
14 import javax.inject.Inject;\r
15 \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
41 \r
42 /**\r
43  * Used like this in E4 model fragments:\r
44  * \r
45  * <pre>\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
51  *      </children>\r
52  *    </children>\r
53  *  </elements>\r
54  * </fragments>\r
55  * </pre>\r
56  * \r
57  * @author Antti Villberg\r
58  * @author Jani Simomaa\r
59  * @author Tuukka Lehtonen\r
60  */\r
61 public class GlobalModeledToolbarActions {\r
62 \r
63     @Inject UISynchronize sync;\r
64 \r
65     private List<String> browseContexts;\r
66     private boolean disposed;\r
67     private Composite composite;\r
68 \r
69     @PostConstruct\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
76     }\r
77 \r
78     @PreDestroy\r
79     private void dispose() {\r
80         disposed = true;\r
81         if (composite != null) {\r
82             for (Control c : composite.getChildren())\r
83                 c.dispose();\r
84             composite = null;\r
85         }\r
86     }\r
87 \r
88     class ContributionListener implements Listener<List<IContributionItem>>, Runnable {\r
89 \r
90         AtomicReference<List<IContributionItem>> lastResult = new AtomicReference<>();\r
91 \r
92         @Override\r
93         public void execute(List<IContributionItem> result) {\r
94             if (composite != null) {\r
95                 lastResult.set(result);\r
96                 sync.asyncExec(this);\r
97             }\r
98         }\r
99 \r
100         @Override\r
101         public void run() {\r
102             List<IContributionItem> result = lastResult.getAndSet(null);\r
103             if (result == null || composite == null || composite.isDisposed())\r
104                 return;\r
105 \r
106             ToolBar tb = (ToolBar) composite.getParent();\r
107             for (ToolItem item : tb.getItems())\r
108                 item.dispose();\r
109             for (IContributionItem item : result)\r
110                 item.fill(tb, -1);\r
111 \r
112             Composite tbp = tb.getParent();\r
113             tbp.layout(true, true);\r
114         }\r
115 \r
116         @Override\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
121                             t));\r
122         }\r
123 \r
124         @Override\r
125         public boolean isDisposed() {\r
126             return disposed;\r
127         }\r
128     }\r
129 \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
133         }\r
134         @Override\r
135         public List<IContributionItem> perform(ReadGraph graph) throws DatabaseException {\r
136             return getContributionItems(graph, parameter, parameter2);\r
137         }\r
138     }\r
139 \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
144         return result;\r
145     }\r
146 \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
150         try {\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
159                             e));\r
160         }\r
161 \r
162         return Collections.emptyList();\r
163     }\r
164 \r
165     private static List<IContributionItem> toContributionItems(Map<IActionCategory, List<Action>> map) {\r
166         if (map.isEmpty())\r
167             return Collections.emptyList();\r
168 \r
169         IActionCategory[] categories = map.keySet().toArray(new IActionCategory[map.size()]);\r
170         Arrays.sort(categories, IActionCategory.ACTION_CATEGORY_COMPARATOR);\r
171 \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
177 \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
183             }\r
184             else {\r
185                 if (first)\r
186                     first = false;\r
187                 else\r
188                     items.add(new Separator(category == null ? "" : category.getLabel()));\r
189                 for (Action action : actions)\r
190                     items.add(new ActionContributionItem(action));\r
191             }\r
192         }\r
193 \r
194         return items;\r
195     }\r
196 \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
203     };\r
204 \r
205 }\r