]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolbarContributor.java
70fb9c6b80455edb34da5564e9971fc46f875378
[simantics/3d.git] / org.simantics.g3d / src / org / simantics / g3d / toolbar / ToolbarContributor.java
1 /*******************************************************************************\r
2  * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.g3d.toolbar;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.HashMap;\r
16 import java.util.HashSet;\r
17 import java.util.List;\r
18 import java.util.Map;\r
19 import java.util.Set;\r
20 \r
21 import org.eclipse.core.commands.Command;\r
22 import org.eclipse.core.commands.CommandEvent;\r
23 import org.eclipse.core.commands.ExecutionException;\r
24 import org.eclipse.core.commands.ICommandListener;\r
25 import org.eclipse.core.commands.State;\r
26 import org.eclipse.jface.action.Action;\r
27 import org.eclipse.jface.action.ActionContributionItem;\r
28 import org.eclipse.jface.action.IContributionItem;\r
29 import org.eclipse.jface.action.ICoolBarManager;\r
30 import org.eclipse.jface.action.IToolBarManager;\r
31 import org.eclipse.jface.action.ToolBarContributionItem;\r
32 import org.eclipse.jface.resource.ImageDescriptor;\r
33 import org.eclipse.nebula.widgets.tablecombo.TableCombo;\r
34 import org.eclipse.swt.SWT;\r
35 import org.eclipse.swt.events.SelectionEvent;\r
36 import org.eclipse.swt.events.SelectionListener;\r
37 import org.eclipse.swt.layout.GridData;\r
38 import org.eclipse.swt.layout.GridLayout;\r
39 import org.eclipse.swt.widgets.Composite;\r
40 import org.eclipse.swt.widgets.Control;\r
41 import org.eclipse.swt.widgets.TableItem;\r
42 import org.eclipse.ui.IEditorPart;\r
43 import org.eclipse.ui.IPartListener;\r
44 import org.eclipse.ui.IWorkbenchPart;\r
45 import org.eclipse.ui.PlatformUI;\r
46 import org.eclipse.ui.commands.ICommandService;\r
47 import org.eclipse.ui.handlers.HandlerUtil;\r
48 import org.eclipse.ui.handlers.IHandlerService;\r
49 import org.eclipse.ui.handlers.RadioState;\r
50 import org.eclipse.ui.handlers.RegistryToggleState;\r
51 import org.eclipse.ui.menus.WorkbenchWindowControlContribution;\r
52 import org.eclipse.ui.part.EditorActionBarContributor;\r
53 import org.simantics.db.common.utils.ErrorLogger;\r
54 import org.simantics.g3d.Activator;\r
55 import org.simantics.g3d.toolbar.ToolBarCommandRegistry.ToolbarCommandExtension;\r
56 import org.simantics.utils.datastructures.MapList;\r
57 \r
58 \r
59 /**\r
60  * EditorBarContributor, which tracks toggle states separately for each command.\r
61  * \r
62  * @see org.simantics.g3d.toolbarCommand Extension Point\r
63  * \r
64  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
65  * \r
66  * \r
67  * \r
68  * TODO : test radio buttons.\r
69  * TODO : configuring the position of buttons. \r
70  *\r
71  */\r
72 public abstract class ToolbarContributor extends EditorActionBarContributor implements ICommandListener, IPartListener {\r
73 \r
74         private static final String PLATFORM = "platform:/plugin/";\r
75         \r
76         private IEditorPart    activePart;\r
77         private Set<IEditorPart> parts = new HashSet<IEditorPart>();\r
78         IToolBarManager        mgr;\r
79         \r
80         \r
81         ICommandService service;\r
82         IHandlerService handlerService;\r
83         List<IContributionItem> items = new ArrayList<IContributionItem>();\r
84         MapList<String, CommandAction> actions = new MapList<String, ToolbarContributor.CommandAction>();\r
85         \r
86         CommandStateRegistry stateRegistry;\r
87         \r
88         private Map<String,ComboContribution> menus = new HashMap<String, ComboContribution>();\r
89         \r
90         public ToolbarContributor() {\r
91                 service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); \r
92                 handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);\r
93                 stateRegistry = CommandStateRegistry.getInstance();\r
94         }\r
95         \r
96         public abstract String getToolbarId();\r
97         \r
98         public void contributeToCoolBar(ICoolBarManager coolBarManager) {\r
99                 IContributionItem toolBar = coolBarManager.find(getToolbarId());\r
100                 if (toolBar instanceof ToolBarContributionItem)\r
101                         mgr = ((ToolBarContributionItem) toolBar).getToolBarManager();\r
102                 if (mgr == null)\r
103                                 return;\r
104                 \r
105                 createCommands();\r
106                 \r
107                 mgr.markDirty();\r
108                 \r
109         }\r
110         \r
111         private void createCommands() {\r
112                 for (ToolbarCommandExtension ext : ToolBarCommandRegistry.getInstance().getExtensions(getToolbarId())) {\r
113                         addCommand(ext);\r
114                 }\r
115         }\r
116         \r
117         private void addCommand(ToolbarCommandExtension ext) {\r
118                 String commandId = ext.commandId;\r
119                 Command command = service.getCommand(commandId);\r
120                 \r
121                 String type = ext.type;\r
122                 \r
123                 State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
124                 State radioState = command.getState(RadioState.STATE_ID);\r
125                 \r
126                 String name = ext.name;\r
127                 \r
128                 \r
129                 ImageDescriptor image = getImage(ext);\r
130                 \r
131                 CommandAction a = null;\r
132                 if (type.equals("toggle") && toggleState != null) {\r
133                         a = new CommandCheckboxAction(command,name,image);\r
134 \r
135                         stateRegistry.storeDefaultState(commandId);\r
136                 } else if (radioState != null && ext.value != null) {\r
137                         stateRegistry.storeDefaultState(commandId);\r
138                         if (type.equals("radio")) {\r
139                                 a = new CommandRadioAction(command,name,ext.value,image);\r
140                         } else if (type.equals("combo")) {\r
141                                 a = new CommandRadioAction(command,name,ext.value,image);\r
142                                 ComboContribution combo = menus.get(commandId);\r
143                                 if (combo == null) {\r
144                                         combo = new ComboContribution();\r
145                                         menus.put(commandId, combo);\r
146                                         items.add(combo);\r
147                                         mgr.add(combo);\r
148                                         a.getCommand().addCommandListener(this);\r
149                                 }\r
150                                 actions.add(commandId,a);\r
151                                 combo.addAction(a);\r
152                                 return;\r
153                         }\r
154                 } else if (type.equals("push")) {\r
155                         a = new CommandPushAction(command,name,image);\r
156                 } else {\r
157                         ErrorLogger.defaultLogError(ext + " is not valid.");\r
158                         return;\r
159                 }\r
160                 a.getCommand().addCommandListener(this);\r
161                 IContributionItem item =  new ActionContributionItem(a);\r
162                 actions.add(commandId,a);\r
163                 items.add(item);\r
164                 mgr.add(item);\r
165         }\r
166         \r
167         private ImageDescriptor getImage(ToolbarCommandExtension ext) {\r
168                 ImageDescriptor image = null;\r
169                 if (ext.image != null) {\r
170                         String plugin = null;\r
171                         String file = null;\r
172                         if (ext.image.startsWith(PLATFORM)) {\r
173                                 String s = ext.image.substring(PLATFORM.length());\r
174                                 int i = s.indexOf("/");\r
175                                 plugin = s.substring(0,i);\r
176                                 file = s.substring(i+1);\r
177                         } else {\r
178                                 plugin = ext.contributorId;\r
179                                 file = ext.image;\r
180                         }\r
181                         image = Activator.imageDescriptorFromPlugin(plugin, file);\r
182                 }\r
183                 return image;\r
184         }\r
185         \r
186 \r
187         \r
188         @Override\r
189         public void commandChanged(CommandEvent commandEvent) {\r
190                 if (commandEvent.isHandledChanged()||commandEvent.isEnabledChanged()) {\r
191                         Command command = commandEvent.getCommand();\r
192                         String commandId = command.getId();\r
193                         for (CommandAction a : actions.getValues(commandId)) {\r
194                                 a.setEnabled(command.isHandled() && command.isEnabled());\r
195                         }\r
196                 }\r
197         }\r
198         \r
199         @Override\r
200         public void setActiveEditor(IEditorPart targetEditor) {\r
201                 if (targetEditor == activePart)\r
202                         return;\r
203                 setContext(targetEditor);\r
204         }\r
205         \r
206         private void setContext(IEditorPart part) {\r
207                 this.activePart = part;\r
208                 if (!parts.contains(activePart)) {\r
209                         activePart.getSite().getPage().addPartListener(this);\r
210                 }\r
211                 if (part != null) {\r
212                         for (String commandId : actions.getKeys()) {\r
213                                 for (CommandAction a : actions.getValues(commandId)) {\r
214                                         a.setEnabled(true);\r
215                                 }\r
216                         }\r
217                         updateActionBars(part);\r
218                 } else {\r
219                         for (String commandId : actions.getKeys()) {\r
220                                 for (CommandAction a : actions.getValues(commandId)) {\r
221                                         a.setEnabled(false);\r
222                                 }\r
223                         }\r
224                 }\r
225         }\r
226 \r
227         private void updateActionBars(IEditorPart part) {\r
228                 restoreActionStates();\r
229                 part.getEditorSite().getActionBars().updateActionBars();\r
230         }\r
231         \r
232         @Override\r
233         public void dispose() {\r
234                 if (mgr != null) {\r
235                         for (IContributionItem item : items) {\r
236                                 mgr.remove(item);\r
237                                 item.dispose();\r
238                         }\r
239                         mgr.markDirty();\r
240                         mgr.update(true);\r
241                         if (activePart != null) {\r
242                                 activePart.getEditorSite().getActionBars().updateActionBars();\r
243                         }\r
244                         \r
245                         for (String commandId : actions.getKeys()) {\r
246                                 for (CommandAction a : actions.getValues(commandId)) {\r
247                                         a.getCommand().removeCommandListener(this);\r
248                                 }\r
249                         }\r
250                         actions.clear();\r
251                 }\r
252                 \r
253                 super.dispose();\r
254                 activePart = null;\r
255         }\r
256         \r
257 \r
258         private void storeRadioActionState(CommandRadioAction action, boolean checked) {\r
259                 if (activePart == null)\r
260                         return;\r
261                 stateRegistry.setEditorState(activePart, action.getCommandId(), action.getValue());\r
262         }\r
263         \r
264         private void storeToggleActionState(CommandAction action, boolean checked) {\r
265                 if (activePart == null)\r
266                         return;\r
267                 stateRegistry.setEditorState(activePart, action.getCommandId(), checked);\r
268         }\r
269         \r
270         private void restoreActionStates() {\r
271                 if (activePart == null)\r
272                         return;\r
273                 // toggles\r
274                 Map<String,Boolean> defaultToggleStates = stateRegistry.getDefaultToggleStates();\r
275                 for (String commandId : defaultToggleStates.keySet()) {\r
276                         for (CommandAction a : actions.getValues(commandId)) {\r
277                                 a.setChecked(defaultToggleStates.get(commandId));\r
278                         }\r
279                 }\r
280                 Map<String,Boolean> editorStates = stateRegistry.getEditorToggleStates(activePart);//toggleStates.get(activePart);\r
281                 if (editorStates != null) {\r
282                         for (String commandId : editorStates.keySet()) {\r
283                                 for (CommandAction a : actions.getValues(commandId)) {\r
284                                         a.setChecked(editorStates.get(commandId));\r
285                                 }\r
286                         }\r
287                 }\r
288                 // radios\r
289                 Map<String,String> defaultRadioStates = stateRegistry.getDefaultRadioStates();\r
290                 for (String commandId : defaultRadioStates.keySet()) {\r
291                         String defaultValue = defaultRadioStates.get(commandId);\r
292                         for (CommandAction a : actions.getValues(commandId)) {\r
293                                 CommandRadioAction r = (CommandRadioAction)a;\r
294                                 r.setChecked(r.getValue().equals(defaultValue));\r
295                         }\r
296                 }\r
297                 \r
298                 Map<String,String> editorRadioStates = stateRegistry.getEditorRadioStates(activePart);//radioStates.get(activePart);\r
299                 if (editorRadioStates != null) {\r
300                         for (String commandId : editorRadioStates.keySet()) {\r
301                                 String defaultValue = editorRadioStates.get(commandId);\r
302                                 for (CommandAction a : actions.getValues(commandId)) {\r
303                                         CommandRadioAction r = (CommandRadioAction)a;\r
304                                         r.setChecked(r.getValue().equals(defaultValue));\r
305                                 }\r
306                         }\r
307                 }\r
308                 \r
309                 for (ComboContribution c : menus.values()) {\r
310                         c.updateSelection();\r
311                 }\r
312                 \r
313 \r
314         }\r
315         \r
316         @Override\r
317         public void partActivated(IWorkbenchPart part) {\r
318 \r
319         }\r
320         \r
321         @Override\r
322         public void partBroughtToTop(IWorkbenchPart part) {\r
323                 \r
324         }\r
325         \r
326         @Override\r
327         public void partClosed(IWorkbenchPart part) {\r
328                 parts.remove(part);\r
329                 stateRegistry.clearStates(part);\r
330                 part.getSite().getPage().removePartListener(this);\r
331         }\r
332         \r
333         @Override\r
334         public void partDeactivated(IWorkbenchPart part) {\r
335                 \r
336         }\r
337         \r
338         @Override\r
339         public void partOpened(IWorkbenchPart part) {\r
340                 \r
341         }\r
342         \r
343         private boolean getToggleState(Command command) {\r
344                 State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
345                 return (Boolean)toggleState.getValue();\r
346         }\r
347         \r
348         private abstract class CommandAction extends Action {\r
349                 private Command command;\r
350                 \r
351                 public CommandAction(Command command, String name, ImageDescriptor image, int style) {\r
352                         super(name,style);\r
353                         this.command = command;\r
354                         if (image != null)\r
355                                 setImageDescriptor(image);\r
356                 }\r
357                 \r
358                 @Override\r
359                 public void run() {\r
360                         try {\r
361                                 handlerService.executeCommand(command.getId(), null);\r
362                         } catch (Exception e) {\r
363                                 e.printStackTrace();\r
364                         }\r
365                 }\r
366                 \r
367                 public Command getCommand() {\r
368                         return command;\r
369                 }\r
370                 \r
371                 public String getCommandId() {\r
372                         return command.getId();\r
373                 }\r
374         }\r
375         \r
376         private class CommandCheckboxAction extends CommandAction {\r
377                 \r
378                 public CommandCheckboxAction(Command command, String name, ImageDescriptor image) {\r
379                         super(command,name,image,Action.AS_CHECK_BOX);\r
380                         \r
381                 }\r
382                 \r
383                 @Override\r
384                 public void run() {\r
385                         boolean checked = isChecked(); \r
386                         storeToggleActionState(this, checked);\r
387                         try {\r
388                                 if (checked == getToggleState(getCommand()))\r
389                                         HandlerUtil.toggleCommandState(getCommand());\r
390                         } catch (ExecutionException e) {\r
391                                 e.printStackTrace();\r
392                         }\r
393                         super.run();\r
394                 }\r
395                 \r
396         }\r
397         \r
398         private class CommandRadioAction extends CommandAction {\r
399 \r
400                 private String value;\r
401                 \r
402                 public CommandRadioAction(Command command, String name, String value, ImageDescriptor image) {\r
403                         super(command,name,image,Action.AS_RADIO_BUTTON);\r
404                         this.value = value;\r
405                 }\r
406                 \r
407                 @Override\r
408                 public void run() {\r
409                         boolean checked = isChecked(); \r
410                         storeRadioActionState(this, checked);\r
411                         try {\r
412                                 HandlerUtil.updateRadioState(getCommand(), value);\r
413                         } catch (ExecutionException e) {\r
414                                 e.printStackTrace();\r
415                                 return;\r
416                         }\r
417                         super.run();\r
418                 }\r
419                 \r
420                 public String getValue() {\r
421                         return value;\r
422                 }\r
423                 \r
424         }\r
425 \r
426         private class CommandPushAction extends CommandAction {\r
427                 \r
428                 public CommandPushAction(Command command, String name, ImageDescriptor image) {\r
429                         super(command,name,image,Action.AS_PUSH_BUTTON);\r
430                 }\r
431 \r
432         }\r
433         \r
434         private class ComboContribution extends WorkbenchWindowControlContribution {\r
435                 private TableCombo combo;\r
436                 \r
437                 private List<Action> actions = new ArrayList<Action>();\r
438                 \r
439                 @Override\r
440                 protected Control createControl(Composite parent) {\r
441                         Composite container = new Composite(parent, SWT.NONE);\r
442                         GridLayout glContainer = new GridLayout(1, false);\r
443                         glContainer.marginTop = 0;\r
444                         glContainer.marginHeight = 0;\r
445                         glContainer.marginWidth = 0;\r
446                         container.setLayout(glContainer);\r
447                         GridData glReader = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);\r
448                         combo = new TableCombo(container, SWT.BORDER | SWT.READ_ONLY);\r
449                         combo.setLayoutData(glReader);\r
450 \r
451                         for (Action a : actions) {\r
452                                 TableItem item = new TableItem(combo.getTable(), SWT.NONE);\r
453                                 item.setText(a.getText());\r
454                                 if (a.getImageDescriptor() != null)\r
455                                         item.setImage(a.getImageDescriptor().createImage());\r
456                         }\r
457                         \r
458                         combo.addSelectionListener(new SelectionListener() {\r
459                                 \r
460                                 @Override\r
461                                 public void widgetSelected(SelectionEvent e) {\r
462                                         int index = combo.getSelectionIndex();\r
463                                         if (index == -1)\r
464                                                 return;\r
465                                         actions.get(index).run();\r
466                                 }\r
467                                 \r
468                                 @Override\r
469                                 public void widgetDefaultSelected(SelectionEvent e) {\r
470                                         \r
471                                 }\r
472                         });\r
473                         updateSelection();\r
474                         return container;\r
475                 }\r
476                 \r
477                 public void addAction(Action a) {\r
478                         actions.add(a);\r
479                 }\r
480                 \r
481                 void updateSelection() {\r
482                         if (combo == null)\r
483                                 return;\r
484                         for (int i = 0; i < actions.size(); i++) {\r
485                                 if (actions.get(i).isChecked()) {\r
486                                         combo.select(i);\r
487                                         return;\r
488                                 }\r
489                         }\r
490                 }\r
491         }\r
492         \r
493 }\r