1 /*******************************************************************************
\r
2 * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.g3d.toolbar;
\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
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
60 * EditorBarContributor, which tracks toggle states separately for each command.
\r
62 * @see org.simantics.g3d.toolbarCommand Extension Point
\r
64 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
\r
68 * TODO : test radio buttons.
\r
69 * TODO : configuring the position of buttons.
\r
72 public abstract class ToolbarContributor extends EditorActionBarContributor implements ICommandListener, IPartListener {
\r
74 private static final String PLATFORM = "platform:/plugin/";
\r
76 private IEditorPart activePart;
\r
77 private Set<IEditorPart> parts = new HashSet<IEditorPart>();
\r
78 IToolBarManager mgr;
\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
86 CommandStateRegistry stateRegistry;
\r
88 private Map<String,ComboContribution> menus = new HashMap<String, ComboContribution>();
\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
96 public abstract String getToolbarId();
\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
111 private void createCommands() {
\r
112 for (ToolbarCommandExtension ext : ToolBarCommandRegistry.getInstance().getExtensions(getToolbarId())) {
\r
117 private void addCommand(ToolbarCommandExtension ext) {
\r
118 String commandId = ext.commandId;
\r
119 Command command = service.getCommand(commandId);
\r
121 String type = ext.type;
\r
123 State toggleState = command.getState(RegistryToggleState.STATE_ID);
\r
124 State radioState = command.getState(RadioState.STATE_ID);
\r
126 String name = ext.name;
\r
129 ImageDescriptor image = getImage(ext);
\r
131 CommandAction a = null;
\r
132 if (type.equals("toggle") && toggleState != null) {
\r
133 a = new CommandCheckboxAction(command,name,image);
\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
148 a.getCommand().addCommandListener(this);
\r
150 actions.add(commandId,a);
\r
151 combo.addAction(a);
\r
154 } else if (type.equals("push")) {
\r
155 a = new CommandPushAction(command,name,image);
\r
157 ErrorLogger.defaultLogError(ext + " is not valid.");
\r
160 a.getCommand().addCommandListener(this);
\r
161 IContributionItem item = new ActionContributionItem(a);
\r
162 actions.add(commandId,a);
\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
178 plugin = ext.contributorId;
\r
181 image = Activator.imageDescriptorFromPlugin(plugin, file);
\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
200 public void setActiveEditor(IEditorPart targetEditor) {
\r
201 if (targetEditor == activePart)
\r
203 setContext(targetEditor);
\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
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
217 updateActionBars(part);
\r
219 for (String commandId : actions.getKeys()) {
\r
220 for (CommandAction a : actions.getValues(commandId)) {
\r
221 a.setEnabled(false);
\r
227 private void updateActionBars(IEditorPart part) {
\r
228 restoreActionStates();
\r
229 part.getEditorSite().getActionBars().updateActionBars();
\r
233 public void dispose() {
\r
235 for (IContributionItem item : items) {
\r
241 if (activePart != null) {
\r
242 activePart.getEditorSite().getActionBars().updateActionBars();
\r
245 for (String commandId : actions.getKeys()) {
\r
246 for (CommandAction a : actions.getValues(commandId)) {
\r
247 a.getCommand().removeCommandListener(this);
\r
258 private void storeRadioActionState(CommandRadioAction action, boolean checked) {
\r
259 if (activePart == null)
\r
261 stateRegistry.setEditorState(activePart, action.getCommandId(), action.getValue());
\r
264 private void storeToggleActionState(CommandAction action, boolean checked) {
\r
265 if (activePart == null)
\r
267 stateRegistry.setEditorState(activePart, action.getCommandId(), checked);
\r
270 private void restoreActionStates() {
\r
271 if (activePart == null)
\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
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
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
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
309 for (ComboContribution c : menus.values()) {
\r
310 c.updateSelection();
\r
317 public void partActivated(IWorkbenchPart part) {
\r
322 public void partBroughtToTop(IWorkbenchPart part) {
\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
334 public void partDeactivated(IWorkbenchPart part) {
\r
339 public void partOpened(IWorkbenchPart part) {
\r
343 private boolean getToggleState(Command command) {
\r
344 State toggleState = command.getState(RegistryToggleState.STATE_ID);
\r
345 return (Boolean)toggleState.getValue();
\r
348 private abstract class CommandAction extends Action {
\r
349 private Command command;
\r
351 public CommandAction(Command command, String name, ImageDescriptor image, int style) {
\r
353 this.command = command;
\r
355 setImageDescriptor(image);
\r
359 public void run() {
\r
361 handlerService.executeCommand(command.getId(), null);
\r
362 } catch (Exception e) {
\r
363 e.printStackTrace();
\r
367 public Command getCommand() {
\r
371 public String getCommandId() {
\r
372 return command.getId();
\r
376 private class CommandCheckboxAction extends CommandAction {
\r
378 public CommandCheckboxAction(Command command, String name, ImageDescriptor image) {
\r
379 super(command,name,image,Action.AS_CHECK_BOX);
\r
384 public void run() {
\r
385 boolean checked = isChecked();
\r
386 storeToggleActionState(this, checked);
\r
388 if (checked == getToggleState(getCommand()))
\r
389 HandlerUtil.toggleCommandState(getCommand());
\r
390 } catch (ExecutionException e) {
\r
391 e.printStackTrace();
\r
398 private class CommandRadioAction extends CommandAction {
\r
400 private String value;
\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
408 public void run() {
\r
409 boolean checked = isChecked();
\r
410 storeRadioActionState(this, checked);
\r
412 HandlerUtil.updateRadioState(getCommand(), value);
\r
413 } catch (ExecutionException e) {
\r
414 e.printStackTrace();
\r
420 public String getValue() {
\r
426 private class CommandPushAction extends CommandAction {
\r
428 public CommandPushAction(Command command, String name, ImageDescriptor image) {
\r
429 super(command,name,image,Action.AS_PUSH_BUTTON);
\r
434 private class ComboContribution extends WorkbenchWindowControlContribution {
\r
435 private TableCombo combo;
\r
437 private List<Action> actions = new ArrayList<Action>();
\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
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
458 combo.addSelectionListener(new SelectionListener() {
\r
461 public void widgetSelected(SelectionEvent e) {
\r
462 int index = combo.getSelectionIndex();
\r
465 actions.get(index).run();
\r
469 public void widgetDefaultSelected(SelectionEvent e) {
\r
477 public void addAction(Action a) {
\r
481 void updateSelection() {
\r
484 for (int i = 0; i < actions.size(); i++) {
\r
485 if (actions.get(i).isChecked()) {
\r