]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.ui/src/org/simantics/ui/toolbar/ToolbarContributor.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / toolbar / ToolbarContributor.java
diff --git a/bundles/org.simantics.ui/src/org/simantics/ui/toolbar/ToolbarContributor.java b/bundles/org.simantics.ui/src/org/simantics/ui/toolbar/ToolbarContributor.java
new file mode 100644 (file)
index 0000000..84413bb
--- /dev/null
@@ -0,0 +1,620 @@
+package org.simantics.ui.toolbar;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.commands.Command;\r
+import org.eclipse.core.commands.CommandEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.core.commands.ICommandListener;\r
+import org.eclipse.core.commands.State;\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.core.runtime.IConfigurationElement;\r
+import org.eclipse.core.runtime.IExecutableExtension;\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.ActionContributionItem;\r
+import org.eclipse.jface.action.IContributionItem;\r
+import org.eclipse.jface.action.ICoolBarManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.action.ToolBarContributionItem;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.eclipse.nebula.widgets.tablecombo.TableCombo;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.TableItem;\r
+import org.eclipse.ui.IEditorPart;\r
+import org.eclipse.ui.IPartListener;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.eclipse.ui.commands.ICommandService;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+import org.eclipse.ui.handlers.IHandlerService;\r
+import org.eclipse.ui.handlers.RadioState;\r
+import org.eclipse.ui.handlers.RegistryToggleState;\r
+import org.eclipse.ui.menus.WorkbenchWindowControlContribution;\r
+import org.eclipse.ui.part.EditorActionBarContributor;\r
+\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.ui.internal.Activator;\r
+import org.simantics.ui.toolbar.ToolBarCommandRegistry.ToolbarCommandExtension;\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+\r
+/**\r
+ * EditorBarContributor, which tracks toggle states separately for each command.\r
+ * \r
+ * @see org.simantics.g3d.toolbarCommand Extension Point\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ * \r
+ * \r
+ * \r
+ * TODO : configuring the position of buttons. \r
+ *\r
+ */\r
+public class ToolbarContributor extends EditorActionBarContributor implements ICommandListener, IPartListener, CommandStateListener, IExecutableExtension {\r
+\r
+       private static boolean DEBUG = false;                   // Print debug messages to console\r
+       private static boolean REUSE = true;                    // true: Reuse contribution items / false: delete items on dispose \r
+       \r
+       private static final String PLATFORM = "platform:/plugin/";\r
+\r
+       private String toolbarId;\r
+       \r
+       private IEditorPart    activePart;\r
+       private Set<IEditorPart> parts = new HashSet<IEditorPart>();\r
+    IToolBarManager        mgr;\r
+    \r
+    \r
+    ICommandService service;\r
+    IHandlerService handlerService;\r
+    List<IContributionItem> items = new ArrayList<IContributionItem>();\r
+    MapList<String, CommandAction> actions = new MapList<String, ToolbarContributor.CommandAction>();\r
+    \r
+    CommandStateRegistry stateRegistry;\r
+       \r
+       private Map<String,ComboContribution> menus = new HashMap<String, ComboContribution>();\r
+       \r
+       public ToolbarContributor() {\r
+               service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); \r
+               handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);\r
+               stateRegistry = CommandStateRegistry.getInstance();\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void setInitializationData(IConfigurationElement config,String propertyName, Object data) throws CoreException {\r
+               if (data instanceof String) {\r
+                        String[] parameters = ((String) data).split(";");\r
+                        for (String parameter : parameters) {\r
+                       String[] keyValue = parameter.split("=");\r
+                       if (keyValue.length > 2) {\r
+                           //ErrorLogger.defaultLogWarning("Invalid parameter '" + parameter + ". Complete view argument: " + data, null);\r
+                           continue;\r
+                       }\r
+                       String key = keyValue[0];\r
+                       String value = keyValue.length > 1 ? keyValue[1] : "";\r
+\r
+                       if ("toolbar".equals(key)) {\r
+                           toolbarId = value;\r
+                       } \r
+                   }\r
+               }\r
+               \r
+       }\r
+       \r
+       public String getToolbarId() {\r
+               return toolbarId;\r
+       }\r
+       \r
+       \r
+       private ICoolBarManager coolBarManager;\r
+       private IContributionItem toolBar;\r
+       public void contributeToCoolBar(ICoolBarManager coolBarManager) {\r
+               this.coolBarManager = coolBarManager;\r
+               toolBar = coolBarManager.find(getToolbarId());\r
+               \r
+                if (toolBar instanceof ToolBarContributionItem)\r
+                mgr = ((ToolBarContributionItem) toolBar).getToolBarManager();\r
+            if (mgr == null)\r
+                   return;\r
+            \r
+            createCommands();\r
+            \r
+            mgr.markDirty();\r
+            \r
+       }\r
+       \r
+       private void createCommands() {\r
+               for (ToolbarCommandExtension ext : ToolBarCommandRegistry.getInstance().getExtensions(getToolbarId())) {\r
+                       addCommand(ext);\r
+               }\r
+       }\r
+       \r
+       private void addCommand(ToolbarCommandExtension ext) {\r
+               if (DEBUG) System.out.println("Adding command to toolbar " +getToolbarId()  + " " + ext);\r
+               String commandId = ext.commandId;\r
+               Command command = service.getCommand(commandId);\r
+               \r
+               String type = ext.type;\r
+               \r
+               State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
+               State radioState = command.getState(RadioState.STATE_ID);\r
+               \r
+               String name = ext.name;\r
+               \r
+               \r
+               ImageDescriptor image = getImage(ext);\r
+               \r
+               CommandAction a = null;\r
+               if (type.equals("toggle") && toggleState != null) {\r
+                       a = new CommandCheckboxAction(command,name,image);\r
+\r
+                       stateRegistry.storeDefaultState(commandId);\r
+               } else if (radioState != null && ext.value != null) {\r
+                       stateRegistry.storeDefaultState(commandId);\r
+                       if (type.equals("radio")) {\r
+                               a = new CommandRadioAction(command,name,ext.value,image);\r
+                       } else if (type.equals("combo")) {\r
+                               a = new CommandRadioAction(command,name,ext.value,image);\r
+                               ComboContribution combo = menus.get(commandId);\r
+                               if (REUSE && combo == null) {\r
+                                       combo = (ComboContribution)mgr.find(commandId);\r
+                                       if (combo != null) {\r
+                                               menus.put(commandId, combo);\r
+                                               items.add(combo);\r
+                                               a.getCommand().addCommandListener(this);\r
+                                               CommandStateRegistry.getInstance().addListener(commandId, this);\r
+                                       }\r
+                               }\r
+                               if (combo == null) {\r
+                                       combo = new ComboContribution();\r
+                                       combo.setId(commandId);\r
+                                       menus.put(commandId, combo);\r
+                                       items.add(combo);\r
+                                       mgr.add(combo);\r
+                                       a.getCommand().addCommandListener(this);\r
+                                       CommandStateRegistry.getInstance().addListener(commandId, this);\r
+                               }\r
+                               actions.add(commandId,a);\r
+                               combo.addAction(a);\r
+                               return;\r
+                       }\r
+               } else if (type.equals("push")) {\r
+                       a = new CommandPushAction(command,name,image);\r
+               } else {\r
+                       if (DEBUG) System.out.println(ext + " is not valid.");\r
+                       Logger.defaultLogError(ext + " is not valid.");\r
+                       return;\r
+               }\r
+               IContributionItem item = null;\r
+               if (REUSE) {\r
+                       String id = commandId;\r
+                       if (ext.value != null)\r
+                               id += "."+ext.value;\r
+                       item = mgr.find(id);\r
+                       if (item == null) {\r
+                               item =  new ActionContributionItem(a);\r
+                               ((ActionContributionItem)item).setId(id);\r
+                       } else {\r
+                               if (DEBUG) System.out.println("Reusing " + ext);\r
+                               a = (CommandAction)((ActionContributionItem)item).getAction();\r
+                       }\r
+               } else {\r
+                       item =  new ActionContributionItem(a);\r
+               }\r
+               a.getCommand().addCommandListener(this);\r
+               actions.add(commandId,a);\r
+               items.add(item);\r
+               mgr.add(item);\r
+               CommandStateRegistry.getInstance().addListener(commandId, this);\r
+       }\r
+       \r
+       private ImageDescriptor getImage(ToolbarCommandExtension ext) {\r
+               ImageDescriptor image = null;\r
+               if (ext.image != null) {\r
+                       String plugin = null;\r
+                       String file = null;\r
+                       if (ext.image.startsWith(PLATFORM)) {\r
+                               String s = ext.image.substring(PLATFORM.length());\r
+                               int i = s.indexOf("/");\r
+                               plugin = s.substring(0,i);\r
+                               file = s.substring(i+1);\r
+                       } else {\r
+                               plugin = ext.contributorId;\r
+                               file = ext.image;\r
+                       }\r
+                       image = Activator.imageDescriptorFromPlugin(plugin, file);\r
+               }\r
+               return image;\r
+       }\r
+       \r
+\r
+       \r
+       @Override\r
+       public void commandChanged(CommandEvent commandEvent) {\r
+               if (commandEvent.isHandledChanged()||commandEvent.isEnabledChanged()) {\r
+                       Command command = commandEvent.getCommand();\r
+                       String commandId = command.getId();\r
+                       for (CommandAction a : actions.getValues(commandId)) {\r
+                               a.setEnabled(command.isHandled() && command.isEnabled());\r
+                       }\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void setActiveEditor(IEditorPart targetEditor) {\r
+               if (targetEditor == activePart)\r
+                       return;\r
+               setContext(targetEditor);\r
+       }\r
+       \r
+       @Override\r
+       public void stateChanged(IWorkbenchPart part, String commandId, String state) {\r
+               // TODO : update only given command\r
+               if (settingState)\r
+                       return;\r
+               if (part instanceof IEditorPart)\r
+                       setContext((IEditorPart)part);\r
+       }\r
+       \r
+       private void setContext(IEditorPart part) {\r
+               this.activePart = part;\r
+        if (activePart != null && !parts.contains(activePart)) {\r
+               activePart.getSite().getPage().addPartListener(this);\r
+        }\r
+        if (part != null) {\r
+               for (String commandId : actions.getKeys()) {\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       a.setEnabled(true);\r
+                               }\r
+                               ComboContribution menu = menus.get(commandId);\r
+                               if (menu != null) {\r
+                                       menu.setEnabled(true);\r
+                               }\r
+                       }\r
+            updateActionBars(part);\r
+        } else {\r
+                       for (String commandId : actions.getKeys()) {\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       a.setEnabled(false);\r
+                               }\r
+                               ComboContribution menu = menus.get(commandId);\r
+                               if (menu != null) \r
+                                       menu.setEnabled(false);\r
+                               \r
+                       }\r
+        }\r
+    }\r
+\r
+    private void updateActionBars(IEditorPart part) {\r
+       restoreActionStates();\r
+        part.getEditorSite().getActionBars().updateActionBars();\r
+    }\r
+       \r
+       @Override\r
+       public void dispose() {\r
+               if (DEBUG) System.out.println("ToolBarContributor.dispose()");\r
+               setActiveEditor(null);\r
+               if (mgr != null) {\r
+                       if (!REUSE) {\r
+                               for (IContributionItem item : items) {\r
+                                       mgr.remove(item);\r
+                                       item.dispose();\r
+                               }\r
+                       }\r
+                       items.clear();\r
+                       \r
+                       for (String commandId : actions.getKeys()) {\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       a.getCommand().removeCommandListener(this);\r
+                               }\r
+                               \r
+                       }\r
+                       actions.clear();\r
+                       \r
+                       // without this the contributed toolbar widgets would continue reserve the space even when they are destroyed.\r
+                       // TODO : how to make the toolbar fix its layout?\r
+                       // Note: Using REUSE flag alleviates the problem, since the widgets are not removed.\r
+                       coolBarManager.update(true);\r
+               }\r
+               CommandStateRegistry.getInstance().removeListener(this);\r
+               super.dispose();\r
+               activePart = null;\r
+       }\r
+       \r
+       boolean settingState = false;\r
+       private void storeRadioActionState(CommandRadioAction action, boolean checked) {\r
+               if (activePart == null)\r
+                       return;\r
+               settingState = true;\r
+               stateRegistry.setEditorState(activePart, action.getCommandId(), action.getValue());\r
+               settingState = false;\r
+       }\r
+       \r
+       private void storeToggleActionState(CommandAction action, boolean checked) {\r
+               if (activePart == null)\r
+                       return;\r
+               settingState = true;\r
+               stateRegistry.setEditorState(activePart, action.getCommandId(), checked);\r
+               settingState = false;\r
+       }\r
+       \r
+       \r
+       \r
+       private void restoreActionStates() {\r
+               if (activePart == null)\r
+                       return;\r
+               // toggles\r
+               Map<String,Boolean> defaultToggleStates = stateRegistry.getDefaultToggleStates();\r
+               for (String commandId : defaultToggleStates.keySet()) {\r
+                       for (CommandAction a : actions.getValues(commandId)) {\r
+                               a.setChecked(defaultToggleStates.get(commandId));\r
+                       }\r
+               }\r
+               Map<String,Boolean> editorStates = stateRegistry.getEditorToggleStates(activePart);//toggleStates.get(activePart);\r
+               if (editorStates != null) {\r
+                       for (String commandId : editorStates.keySet()) {\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       a.setChecked(editorStates.get(commandId));\r
+                               }\r
+                       }\r
+               }\r
+               // radios\r
+               Map<String,String> defaultRadioStates = stateRegistry.getDefaultRadioStates();\r
+               for (String commandId : defaultRadioStates.keySet()) {\r
+                       String defaultValue = defaultRadioStates.get(commandId);\r
+                       for (CommandAction a : actions.getValues(commandId)) {\r
+                               CommandRadioAction r = (CommandRadioAction)a;\r
+                               r.setChecked(r.getValue().equals(defaultValue));\r
+                       }\r
+               }\r
+               \r
+               Map<String,String> editorRadioStates = stateRegistry.getEditorRadioStates(activePart);//radioStates.get(activePart);\r
+               if (editorRadioStates != null) {\r
+                       for (String commandId : editorRadioStates.keySet()) {\r
+                               String defaultValue = editorRadioStates.get(commandId);\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       CommandRadioAction r = (CommandRadioAction)a;\r
+                                       r.setChecked(r.getValue().equals(defaultValue));\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               for (ComboContribution c : menus.values()) {\r
+                       c.updateSelection();\r
+               }\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void partActivated(IWorkbenchPart part) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void partBroughtToTop(IWorkbenchPart part) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void partClosed(IWorkbenchPart part) {\r
+               parts.remove(part);\r
+               stateRegistry.clearStates(part);\r
+               part.getSite().getPage().removePartListener(this);\r
+               if (parts.size() == 0) {\r
+                       \r
+               }\r
+               if (part instanceof IEditorPart)\r
+                       ((IEditorPart)part).getEditorSite().getActionBars().updateActionBars();\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void partDeactivated(IWorkbenchPart part) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void partOpened(IWorkbenchPart part) {\r
+               \r
+       }\r
+       \r
+       private boolean getToggleState(Command command) {\r
+               State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
+               return (Boolean)toggleState.getValue();\r
+       }\r
+       \r
+       private abstract class CommandAction extends Action {\r
+               private Command command;\r
+               \r
+               public CommandAction(Command command, String name, ImageDescriptor image, int style) {\r
+                       super(name,style);\r
+                       this.command = command;\r
+                       if (image != null)\r
+                               setImageDescriptor(image);\r
+               }\r
+               \r
+               @Override\r
+               public void run() {\r
+                       try {\r
+                               handlerService.executeCommand(command.getId(), null);\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+               \r
+               public Command getCommand() {\r
+                       return command;\r
+               }\r
+               \r
+               public String getCommandId() {\r
+                       return command.getId();\r
+               }\r
+               \r
+\r
+               @Override\r
+               public boolean equals(Object obj) {\r
+                       if (obj.getClass() != getClass())\r
+                               return false;\r
+                       CommandAction other= (CommandAction)obj;\r
+                       if (!other.getCommandId().equals(getCommandId()))\r
+                               return false;\r
+                       return true;\r
+               }\r
+\r
+               \r
+               @Override\r
+               public int hashCode() {\r
+                       return command.getId().hashCode();\r
+               }\r
+       }\r
+       \r
+       private class CommandCheckboxAction extends CommandAction {\r
+               \r
+               public CommandCheckboxAction(Command command, String name, ImageDescriptor image) {\r
+                       super(command,name,image,Action.AS_CHECK_BOX);\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public void run() {\r
+                       boolean checked = isChecked(); \r
+                       storeToggleActionState(this, checked);\r
+                       try {\r
+                               if (checked == getToggleState(getCommand()))\r
+                                       HandlerUtil.toggleCommandState(getCommand());\r
+                       } catch (ExecutionException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+                       super.run();\r
+               }\r
+               \r
+       }\r
+       \r
+       private class CommandRadioAction extends CommandAction {\r
+\r
+               private String value;\r
+               \r
+               public CommandRadioAction(Command command, String name, String value, ImageDescriptor image) {\r
+                       super(command,name,image,Action.AS_RADIO_BUTTON);\r
+                       this.value = value;\r
+               }\r
+               \r
+               @Override\r
+               public void run() {\r
+                       boolean checked = isChecked(); \r
+                       storeRadioActionState(this, checked);\r
+                       try {\r
+                               HandlerUtil.updateRadioState(getCommand(), value);\r
+                       } catch (ExecutionException e) {\r
+                               e.printStackTrace();\r
+                               return;\r
+                       }\r
+                       super.run();\r
+               }\r
+               \r
+               public String getValue() {\r
+                       return value;\r
+               }\r
+               \r
+               @Override\r
+               public boolean equals(Object obj) {\r
+                       if (obj.getClass() != getClass())\r
+                               return false;\r
+                       CommandRadioAction other= (CommandRadioAction)obj;\r
+                       if (!other.getCommandId().equals(getCommandId()))\r
+                               return false;\r
+                       if (!other.value.equals(value))\r
+                               return false;\r
+                       return true;\r
+               }\r
+               \r
+       }\r
+\r
+       private class CommandPushAction extends CommandAction {\r
+               \r
+               public CommandPushAction(Command command, String name, ImageDescriptor image) {\r
+                       super(command,name,image,Action.AS_PUSH_BUTTON);\r
+               }\r
+\r
+       }\r
+       \r
+       private class ComboContribution extends WorkbenchWindowControlContribution {\r
+               private TableCombo combo;\r
+               \r
+               private List<Action> actions = new ArrayList<Action>();\r
+               \r
+               @Override\r
+               protected Control createControl(Composite parent) {\r
+                       Composite container = new Composite(parent, SWT.NONE);\r
+                       GridLayout glContainer = new GridLayout(1, false);\r
+                       glContainer.marginTop = 0;\r
+                       glContainer.marginHeight = 0;\r
+                       glContainer.marginWidth = 0;\r
+                       container.setLayout(glContainer);\r
+                       GridData glReader = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);\r
+                       combo = new TableCombo(container, SWT.BORDER | SWT.READ_ONLY);\r
+                       combo.setLayoutData(glReader);\r
+\r
+                       for (Action a : actions) {\r
+                               TableItem item = new TableItem(combo.getTable(), SWT.NONE);\r
+                               item.setText(a.getText());\r
+                               if (a.getImageDescriptor() != null)\r
+                                       item.setImage(a.getImageDescriptor().createImage());\r
+                       }\r
+                       \r
+                       combo.addSelectionListener(new SelectionListener() {\r
+                               \r
+                               @Override\r
+                               public void widgetSelected(SelectionEvent e) {\r
+                                       int index = combo.getSelectionIndex();\r
+                                       if (index == -1)\r
+                                               return;\r
+                                       actions.get(index).run();\r
+                               }\r
+                               \r
+                               @Override\r
+                               public void widgetDefaultSelected(SelectionEvent e) {\r
+                                       \r
+                               }\r
+                       });\r
+                       updateSelection();\r
+                       return container;\r
+               }\r
+               \r
+               public boolean addAction(Action a) {\r
+                       // old action must be replaced. (otherwise reused ComboContributor would use different instances to ToolBarContributor.) \r
+                       actions.remove(a);\r
+                       actions.add(a);\r
+                       return true;\r
+                       \r
+               }\r
+               \r
+               void updateSelection() {\r
+                       if (combo == null)\r
+                               return;\r
+                       for (int i = 0; i < actions.size(); i++) {\r
+                               if (actions.get(i).isChecked()) {\r
+                                       combo.select(i);\r
+                                       return;\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               public void setEnabled(boolean enabled) {\r
+                       if (combo != null)\r
+                               combo.setEnabled(enabled);\r
+               }\r
+       }\r
+       \r
+}\r