]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.ui/src/org/simantics/ui/toolbar/ToolbarContributor.java
84413bb4684f572fe2f20c53570c96be2fa33be0
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / toolbar / ToolbarContributor.java
1 package org.simantics.ui.toolbar;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.HashMap;\r
5 import java.util.HashSet;\r
6 import java.util.List;\r
7 import java.util.Map;\r
8 import java.util.Set;\r
9 \r
10 import org.eclipse.core.commands.Command;\r
11 import org.eclipse.core.commands.CommandEvent;\r
12 import org.eclipse.core.commands.ExecutionException;\r
13 import org.eclipse.core.commands.ICommandListener;\r
14 import org.eclipse.core.commands.State;\r
15 import org.eclipse.core.runtime.CoreException;\r
16 import org.eclipse.core.runtime.IConfigurationElement;\r
17 import org.eclipse.core.runtime.IExecutableExtension;\r
18 import org.eclipse.jface.action.Action;\r
19 import org.eclipse.jface.action.ActionContributionItem;\r
20 import org.eclipse.jface.action.IContributionItem;\r
21 import org.eclipse.jface.action.ICoolBarManager;\r
22 import org.eclipse.jface.action.IToolBarManager;\r
23 import org.eclipse.jface.action.ToolBarContributionItem;\r
24 import org.eclipse.jface.resource.ImageDescriptor;\r
25 import org.eclipse.nebula.widgets.tablecombo.TableCombo;\r
26 import org.eclipse.swt.SWT;\r
27 import org.eclipse.swt.events.SelectionEvent;\r
28 import org.eclipse.swt.events.SelectionListener;\r
29 import org.eclipse.swt.layout.GridData;\r
30 import org.eclipse.swt.layout.GridLayout;\r
31 import org.eclipse.swt.widgets.Composite;\r
32 import org.eclipse.swt.widgets.Control;\r
33 import org.eclipse.swt.widgets.TableItem;\r
34 import org.eclipse.ui.IEditorPart;\r
35 import org.eclipse.ui.IPartListener;\r
36 import org.eclipse.ui.IWorkbenchPart;\r
37 import org.eclipse.ui.PlatformUI;\r
38 import org.eclipse.ui.commands.ICommandService;\r
39 import org.eclipse.ui.handlers.HandlerUtil;\r
40 import org.eclipse.ui.handlers.IHandlerService;\r
41 import org.eclipse.ui.handlers.RadioState;\r
42 import org.eclipse.ui.handlers.RegistryToggleState;\r
43 import org.eclipse.ui.menus.WorkbenchWindowControlContribution;\r
44 import org.eclipse.ui.part.EditorActionBarContributor;\r
45 \r
46 import org.simantics.db.common.utils.Logger;\r
47 import org.simantics.ui.internal.Activator;\r
48 import org.simantics.ui.toolbar.ToolBarCommandRegistry.ToolbarCommandExtension;\r
49 import org.simantics.utils.datastructures.MapList;\r
50 \r
51 \r
52 /**\r
53  * EditorBarContributor, which tracks toggle states separately for each command.\r
54  * \r
55  * @see org.simantics.g3d.toolbarCommand Extension Point\r
56  * \r
57  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
58  * \r
59  * \r
60  * \r
61  * TODO : configuring the position of buttons. \r
62  *\r
63  */\r
64 public class ToolbarContributor extends EditorActionBarContributor implements ICommandListener, IPartListener, CommandStateListener, IExecutableExtension {\r
65 \r
66         private static boolean DEBUG = false;                   // Print debug messages to console\r
67         private static boolean REUSE = true;                    // true: Reuse contribution items / false: delete items on dispose \r
68         \r
69         private static final String PLATFORM = "platform:/plugin/";\r
70 \r
71         private String toolbarId;\r
72         \r
73         private IEditorPart    activePart;\r
74         private Set<IEditorPart> parts = new HashSet<IEditorPart>();\r
75     IToolBarManager        mgr;\r
76     \r
77     \r
78     ICommandService service;\r
79     IHandlerService handlerService;\r
80     List<IContributionItem> items = new ArrayList<IContributionItem>();\r
81     MapList<String, CommandAction> actions = new MapList<String, ToolbarContributor.CommandAction>();\r
82     \r
83     CommandStateRegistry stateRegistry;\r
84         \r
85         private Map<String,ComboContribution> menus = new HashMap<String, ComboContribution>();\r
86         \r
87         public ToolbarContributor() {\r
88                 service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); \r
89                 handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);\r
90                 stateRegistry = CommandStateRegistry.getInstance();\r
91                 \r
92         }\r
93         \r
94         @Override\r
95         public void setInitializationData(IConfigurationElement config,String propertyName, Object data) throws CoreException {\r
96                 if (data instanceof String) {\r
97                          String[] parameters = ((String) data).split(";");\r
98                          for (String parameter : parameters) {\r
99                         String[] keyValue = parameter.split("=");\r
100                         if (keyValue.length > 2) {\r
101                             //ErrorLogger.defaultLogWarning("Invalid parameter '" + parameter + ". Complete view argument: " + data, null);\r
102                             continue;\r
103                         }\r
104                         String key = keyValue[0];\r
105                         String value = keyValue.length > 1 ? keyValue[1] : "";\r
106 \r
107                         if ("toolbar".equals(key)) {\r
108                             toolbarId = value;\r
109                         } \r
110                     }\r
111                 }\r
112                 \r
113         }\r
114         \r
115         public String getToolbarId() {\r
116                 return toolbarId;\r
117         }\r
118         \r
119         \r
120         private ICoolBarManager coolBarManager;\r
121         private IContributionItem toolBar;\r
122         public void contributeToCoolBar(ICoolBarManager coolBarManager) {\r
123                 this.coolBarManager = coolBarManager;\r
124                 toolBar = coolBarManager.find(getToolbarId());\r
125                 \r
126                  if (toolBar instanceof ToolBarContributionItem)\r
127                  mgr = ((ToolBarContributionItem) toolBar).getToolBarManager();\r
128              if (mgr == null)\r
129                     return;\r
130              \r
131              createCommands();\r
132              \r
133              mgr.markDirty();\r
134              \r
135         }\r
136         \r
137         private void createCommands() {\r
138                 for (ToolbarCommandExtension ext : ToolBarCommandRegistry.getInstance().getExtensions(getToolbarId())) {\r
139                         addCommand(ext);\r
140                 }\r
141         }\r
142         \r
143         private void addCommand(ToolbarCommandExtension ext) {\r
144                 if (DEBUG) System.out.println("Adding command to toolbar " +getToolbarId()  + " " + ext);\r
145                 String commandId = ext.commandId;\r
146                 Command command = service.getCommand(commandId);\r
147                 \r
148                 String type = ext.type;\r
149                 \r
150                 State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
151                 State radioState = command.getState(RadioState.STATE_ID);\r
152                 \r
153                 String name = ext.name;\r
154                 \r
155                 \r
156                 ImageDescriptor image = getImage(ext);\r
157                 \r
158                 CommandAction a = null;\r
159                 if (type.equals("toggle") && toggleState != null) {\r
160                         a = new CommandCheckboxAction(command,name,image);\r
161 \r
162                         stateRegistry.storeDefaultState(commandId);\r
163                 } else if (radioState != null && ext.value != null) {\r
164                         stateRegistry.storeDefaultState(commandId);\r
165                         if (type.equals("radio")) {\r
166                                 a = new CommandRadioAction(command,name,ext.value,image);\r
167                         } else if (type.equals("combo")) {\r
168                                 a = new CommandRadioAction(command,name,ext.value,image);\r
169                                 ComboContribution combo = menus.get(commandId);\r
170                                 if (REUSE && combo == null) {\r
171                                         combo = (ComboContribution)mgr.find(commandId);\r
172                                         if (combo != null) {\r
173                                                 menus.put(commandId, combo);\r
174                                                 items.add(combo);\r
175                                                 a.getCommand().addCommandListener(this);\r
176                                                 CommandStateRegistry.getInstance().addListener(commandId, this);\r
177                                         }\r
178                                 }\r
179                                 if (combo == null) {\r
180                                         combo = new ComboContribution();\r
181                                         combo.setId(commandId);\r
182                                         menus.put(commandId, combo);\r
183                                         items.add(combo);\r
184                                         mgr.add(combo);\r
185                                         a.getCommand().addCommandListener(this);\r
186                                         CommandStateRegistry.getInstance().addListener(commandId, this);\r
187                                 }\r
188                                 actions.add(commandId,a);\r
189                                 combo.addAction(a);\r
190                                 return;\r
191                         }\r
192                 } else if (type.equals("push")) {\r
193                         a = new CommandPushAction(command,name,image);\r
194                 } else {\r
195                         if (DEBUG) System.out.println(ext + " is not valid.");\r
196                         Logger.defaultLogError(ext + " is not valid.");\r
197                         return;\r
198                 }\r
199                 IContributionItem item = null;\r
200                 if (REUSE) {\r
201                         String id = commandId;\r
202                         if (ext.value != null)\r
203                                 id += "."+ext.value;\r
204                         item = mgr.find(id);\r
205                         if (item == null) {\r
206                                 item =  new ActionContributionItem(a);\r
207                                 ((ActionContributionItem)item).setId(id);\r
208                         } else {\r
209                                 if (DEBUG) System.out.println("Reusing " + ext);\r
210                                 a = (CommandAction)((ActionContributionItem)item).getAction();\r
211                         }\r
212                 } else {\r
213                         item =  new ActionContributionItem(a);\r
214                 }\r
215                 a.getCommand().addCommandListener(this);\r
216                 actions.add(commandId,a);\r
217                 items.add(item);\r
218                 mgr.add(item);\r
219                 CommandStateRegistry.getInstance().addListener(commandId, this);\r
220         }\r
221         \r
222         private ImageDescriptor getImage(ToolbarCommandExtension ext) {\r
223                 ImageDescriptor image = null;\r
224                 if (ext.image != null) {\r
225                         String plugin = null;\r
226                         String file = null;\r
227                         if (ext.image.startsWith(PLATFORM)) {\r
228                                 String s = ext.image.substring(PLATFORM.length());\r
229                                 int i = s.indexOf("/");\r
230                                 plugin = s.substring(0,i);\r
231                                 file = s.substring(i+1);\r
232                         } else {\r
233                                 plugin = ext.contributorId;\r
234                                 file = ext.image;\r
235                         }\r
236                         image = Activator.imageDescriptorFromPlugin(plugin, file);\r
237                 }\r
238                 return image;\r
239         }\r
240         \r
241 \r
242         \r
243         @Override\r
244         public void commandChanged(CommandEvent commandEvent) {\r
245                 if (commandEvent.isHandledChanged()||commandEvent.isEnabledChanged()) {\r
246                         Command command = commandEvent.getCommand();\r
247                         String commandId = command.getId();\r
248                         for (CommandAction a : actions.getValues(commandId)) {\r
249                                 a.setEnabled(command.isHandled() && command.isEnabled());\r
250                         }\r
251                 }\r
252         }\r
253         \r
254         @Override\r
255         public void setActiveEditor(IEditorPart targetEditor) {\r
256                 if (targetEditor == activePart)\r
257                         return;\r
258                 setContext(targetEditor);\r
259         }\r
260         \r
261         @Override\r
262         public void stateChanged(IWorkbenchPart part, String commandId, String state) {\r
263                 // TODO : update only given command\r
264                 if (settingState)\r
265                         return;\r
266                 if (part instanceof IEditorPart)\r
267                         setContext((IEditorPart)part);\r
268         }\r
269         \r
270         private void setContext(IEditorPart part) {\r
271                 this.activePart = part;\r
272         if (activePart != null && !parts.contains(activePart)) {\r
273                 activePart.getSite().getPage().addPartListener(this);\r
274         }\r
275         if (part != null) {\r
276                 for (String commandId : actions.getKeys()) {\r
277                                 for (CommandAction a : actions.getValues(commandId)) {\r
278                                         a.setEnabled(true);\r
279                                 }\r
280                                 ComboContribution menu = menus.get(commandId);\r
281                                 if (menu != null) {\r
282                                         menu.setEnabled(true);\r
283                                 }\r
284                         }\r
285             updateActionBars(part);\r
286         } else {\r
287                         for (String commandId : actions.getKeys()) {\r
288                                 for (CommandAction a : actions.getValues(commandId)) {\r
289                                         a.setEnabled(false);\r
290                                 }\r
291                                 ComboContribution menu = menus.get(commandId);\r
292                                 if (menu != null) \r
293                                         menu.setEnabled(false);\r
294                                 \r
295                         }\r
296         }\r
297     }\r
298 \r
299     private void updateActionBars(IEditorPart part) {\r
300         restoreActionStates();\r
301         part.getEditorSite().getActionBars().updateActionBars();\r
302     }\r
303         \r
304         @Override\r
305         public void dispose() {\r
306                 if (DEBUG) System.out.println("ToolBarContributor.dispose()");\r
307                 setActiveEditor(null);\r
308                 if (mgr != null) {\r
309                         if (!REUSE) {\r
310                                 for (IContributionItem item : items) {\r
311                                         mgr.remove(item);\r
312                                         item.dispose();\r
313                                 }\r
314                         }\r
315                         items.clear();\r
316                         \r
317                         for (String commandId : actions.getKeys()) {\r
318                                 for (CommandAction a : actions.getValues(commandId)) {\r
319                                         a.getCommand().removeCommandListener(this);\r
320                                 }\r
321                                 \r
322                         }\r
323                         actions.clear();\r
324                         \r
325                         // without this the contributed toolbar widgets would continue reserve the space even when they are destroyed.\r
326                         // TODO : how to make the toolbar fix its layout?\r
327                         // Note: Using REUSE flag alleviates the problem, since the widgets are not removed.\r
328                         coolBarManager.update(true);\r
329                 }\r
330                 CommandStateRegistry.getInstance().removeListener(this);\r
331                 super.dispose();\r
332                 activePart = null;\r
333         }\r
334         \r
335         boolean settingState = false;\r
336         private void storeRadioActionState(CommandRadioAction action, boolean checked) {\r
337                 if (activePart == null)\r
338                         return;\r
339                 settingState = true;\r
340                 stateRegistry.setEditorState(activePart, action.getCommandId(), action.getValue());\r
341                 settingState = false;\r
342         }\r
343         \r
344         private void storeToggleActionState(CommandAction action, boolean checked) {\r
345                 if (activePart == null)\r
346                         return;\r
347                 settingState = true;\r
348                 stateRegistry.setEditorState(activePart, action.getCommandId(), checked);\r
349                 settingState = false;\r
350         }\r
351         \r
352         \r
353         \r
354         private void restoreActionStates() {\r
355                 if (activePart == null)\r
356                         return;\r
357                 // toggles\r
358                 Map<String,Boolean> defaultToggleStates = stateRegistry.getDefaultToggleStates();\r
359                 for (String commandId : defaultToggleStates.keySet()) {\r
360                         for (CommandAction a : actions.getValues(commandId)) {\r
361                                 a.setChecked(defaultToggleStates.get(commandId));\r
362                         }\r
363                 }\r
364                 Map<String,Boolean> editorStates = stateRegistry.getEditorToggleStates(activePart);//toggleStates.get(activePart);\r
365                 if (editorStates != null) {\r
366                         for (String commandId : editorStates.keySet()) {\r
367                                 for (CommandAction a : actions.getValues(commandId)) {\r
368                                         a.setChecked(editorStates.get(commandId));\r
369                                 }\r
370                         }\r
371                 }\r
372                 // radios\r
373                 Map<String,String> defaultRadioStates = stateRegistry.getDefaultRadioStates();\r
374                 for (String commandId : defaultRadioStates.keySet()) {\r
375                         String defaultValue = defaultRadioStates.get(commandId);\r
376                         for (CommandAction a : actions.getValues(commandId)) {\r
377                                 CommandRadioAction r = (CommandRadioAction)a;\r
378                                 r.setChecked(r.getValue().equals(defaultValue));\r
379                         }\r
380                 }\r
381                 \r
382                 Map<String,String> editorRadioStates = stateRegistry.getEditorRadioStates(activePart);//radioStates.get(activePart);\r
383                 if (editorRadioStates != null) {\r
384                         for (String commandId : editorRadioStates.keySet()) {\r
385                                 String defaultValue = editorRadioStates.get(commandId);\r
386                                 for (CommandAction a : actions.getValues(commandId)) {\r
387                                         CommandRadioAction r = (CommandRadioAction)a;\r
388                                         r.setChecked(r.getValue().equals(defaultValue));\r
389                                 }\r
390                         }\r
391                 }\r
392                 \r
393                 for (ComboContribution c : menus.values()) {\r
394                         c.updateSelection();\r
395                 }\r
396 \r
397         }\r
398         \r
399         @Override\r
400         public void partActivated(IWorkbenchPart part) {\r
401 \r
402         }\r
403         \r
404         @Override\r
405         public void partBroughtToTop(IWorkbenchPart part) {\r
406                 \r
407         }\r
408         \r
409         @Override\r
410         public void partClosed(IWorkbenchPart part) {\r
411                 parts.remove(part);\r
412                 stateRegistry.clearStates(part);\r
413                 part.getSite().getPage().removePartListener(this);\r
414                 if (parts.size() == 0) {\r
415                         \r
416                 }\r
417                 if (part instanceof IEditorPart)\r
418                         ((IEditorPart)part).getEditorSite().getActionBars().updateActionBars();\r
419                 \r
420         }\r
421         \r
422         @Override\r
423         public void partDeactivated(IWorkbenchPart part) {\r
424                 \r
425         }\r
426         \r
427         @Override\r
428         public void partOpened(IWorkbenchPart part) {\r
429                 \r
430         }\r
431         \r
432         private boolean getToggleState(Command command) {\r
433                 State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
434                 return (Boolean)toggleState.getValue();\r
435         }\r
436         \r
437         private abstract class CommandAction extends Action {\r
438                 private Command command;\r
439                 \r
440                 public CommandAction(Command command, String name, ImageDescriptor image, int style) {\r
441                         super(name,style);\r
442                         this.command = command;\r
443                         if (image != null)\r
444                                 setImageDescriptor(image);\r
445                 }\r
446                 \r
447                 @Override\r
448                 public void run() {\r
449                         try {\r
450                                 handlerService.executeCommand(command.getId(), null);\r
451                         } catch (Exception e) {\r
452                                 e.printStackTrace();\r
453                         }\r
454                 }\r
455                 \r
456                 public Command getCommand() {\r
457                         return command;\r
458                 }\r
459                 \r
460                 public String getCommandId() {\r
461                         return command.getId();\r
462                 }\r
463                 \r
464 \r
465                 @Override\r
466                 public boolean equals(Object obj) {\r
467                         if (obj.getClass() != getClass())\r
468                                 return false;\r
469                         CommandAction other= (CommandAction)obj;\r
470                         if (!other.getCommandId().equals(getCommandId()))\r
471                                 return false;\r
472                         return true;\r
473                 }\r
474 \r
475                 \r
476                 @Override\r
477                 public int hashCode() {\r
478                         return command.getId().hashCode();\r
479                 }\r
480         }\r
481         \r
482         private class CommandCheckboxAction extends CommandAction {\r
483                 \r
484                 public CommandCheckboxAction(Command command, String name, ImageDescriptor image) {\r
485                         super(command,name,image,Action.AS_CHECK_BOX);\r
486                         \r
487                 }\r
488                 \r
489                 @Override\r
490                 public void run() {\r
491                         boolean checked = isChecked(); \r
492                         storeToggleActionState(this, checked);\r
493                         try {\r
494                                 if (checked == getToggleState(getCommand()))\r
495                                         HandlerUtil.toggleCommandState(getCommand());\r
496                         } catch (ExecutionException e) {\r
497                                 e.printStackTrace();\r
498                         }\r
499                         super.run();\r
500                 }\r
501                 \r
502         }\r
503         \r
504         private class CommandRadioAction extends CommandAction {\r
505 \r
506                 private String value;\r
507                 \r
508                 public CommandRadioAction(Command command, String name, String value, ImageDescriptor image) {\r
509                         super(command,name,image,Action.AS_RADIO_BUTTON);\r
510                         this.value = value;\r
511                 }\r
512                 \r
513                 @Override\r
514                 public void run() {\r
515                         boolean checked = isChecked(); \r
516                         storeRadioActionState(this, checked);\r
517                         try {\r
518                                 HandlerUtil.updateRadioState(getCommand(), value);\r
519                         } catch (ExecutionException e) {\r
520                                 e.printStackTrace();\r
521                                 return;\r
522                         }\r
523                         super.run();\r
524                 }\r
525                 \r
526                 public String getValue() {\r
527                         return value;\r
528                 }\r
529                 \r
530                 @Override\r
531                 public boolean equals(Object obj) {\r
532                         if (obj.getClass() != getClass())\r
533                                 return false;\r
534                         CommandRadioAction other= (CommandRadioAction)obj;\r
535                         if (!other.getCommandId().equals(getCommandId()))\r
536                                 return false;\r
537                         if (!other.value.equals(value))\r
538                                 return false;\r
539                         return true;\r
540                 }\r
541                 \r
542         }\r
543 \r
544         private class CommandPushAction extends CommandAction {\r
545                 \r
546                 public CommandPushAction(Command command, String name, ImageDescriptor image) {\r
547                         super(command,name,image,Action.AS_PUSH_BUTTON);\r
548                 }\r
549 \r
550         }\r
551         \r
552         private class ComboContribution extends WorkbenchWindowControlContribution {\r
553                 private TableCombo combo;\r
554                 \r
555                 private List<Action> actions = new ArrayList<Action>();\r
556                 \r
557                 @Override\r
558                 protected Control createControl(Composite parent) {\r
559                         Composite container = new Composite(parent, SWT.NONE);\r
560                         GridLayout glContainer = new GridLayout(1, false);\r
561                         glContainer.marginTop = 0;\r
562                         glContainer.marginHeight = 0;\r
563                         glContainer.marginWidth = 0;\r
564                         container.setLayout(glContainer);\r
565                         GridData glReader = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);\r
566                         combo = new TableCombo(container, SWT.BORDER | SWT.READ_ONLY);\r
567                         combo.setLayoutData(glReader);\r
568 \r
569                         for (Action a : actions) {\r
570                                 TableItem item = new TableItem(combo.getTable(), SWT.NONE);\r
571                                 item.setText(a.getText());\r
572                                 if (a.getImageDescriptor() != null)\r
573                                         item.setImage(a.getImageDescriptor().createImage());\r
574                         }\r
575                         \r
576                         combo.addSelectionListener(new SelectionListener() {\r
577                                 \r
578                                 @Override\r
579                                 public void widgetSelected(SelectionEvent e) {\r
580                                         int index = combo.getSelectionIndex();\r
581                                         if (index == -1)\r
582                                                 return;\r
583                                         actions.get(index).run();\r
584                                 }\r
585                                 \r
586                                 @Override\r
587                                 public void widgetDefaultSelected(SelectionEvent e) {\r
588                                         \r
589                                 }\r
590                         });\r
591                         updateSelection();\r
592                         return container;\r
593                 }\r
594                 \r
595                 public boolean addAction(Action a) {\r
596                         // old action must be replaced. (otherwise reused ComboContributor would use different instances to ToolBarContributor.) \r
597                         actions.remove(a);\r
598                         actions.add(a);\r
599                         return true;\r
600                         \r
601                 }\r
602                 \r
603                 void updateSelection() {\r
604                         if (combo == null)\r
605                                 return;\r
606                         for (int i = 0; i < actions.size(); i++) {\r
607                                 if (actions.get(i).isChecked()) {\r
608                                         combo.select(i);\r
609                                         return;\r
610                                 }\r
611                         }\r
612                 }\r
613                 \r
614                 public void setEnabled(boolean enabled) {\r
615                         if (combo != null)\r
616                                 combo.setEnabled(enabled);\r
617                 }\r
618         }\r
619         \r
620 }\r