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