1 /******************************************************************************* 2 * Copyright (c) 2000, 2019 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Alexander Fedorov <alexander.fedorov@arsysop.ru> - Bug 548799 14 *******************************************************************************/ 15 package org.eclipse.ui.internal; 16 17 import org.eclipse.core.runtime.IConfigurationElement; 18 import org.eclipse.jface.action.Action; 19 import org.eclipse.jface.action.ActionContributionItem; 20 import org.eclipse.jface.action.IAction; 21 import org.eclipse.jface.resource.ResourceLocator; 22 import org.eclipse.ui.IEditorPart; 23 import org.eclipse.ui.IPluginContribution; 24 import org.eclipse.ui.IViewPart; 25 import org.eclipse.ui.IWorkbenchActionConstants; 26 import org.eclipse.ui.IWorkbenchWindow; 27 import org.eclipse.ui.PlatformUI; 28 import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; 29 30 /** 31 * When 'action' tag is found in the registry, an object of this class is 32 * created. It creates the appropriate action object and captures information 33 * that is later used to add this action object into menu/tool bar. This class 34 * is reused for global (workbench) menu/tool bar, popup menu actions, as well 35 * as view's pulldown and local tool bar. 36 */ 37 public class ActionDescriptor implements IPluginContribution { 38 private PluginAction action; 39 40 private String toolbarId; 41 42 private String menuPath; 43 44 private String id; 45 46 private String pluginId; 47 48 private String menuGroup; 49 50 private String toolbarGroupId; 51 52 private int mode = 0; 53 54 /** 55 * Popup constant. Value <code>0x1</code>. 56 */ 57 public static final int T_POPUP = 0x1; 58 59 /** 60 * View constant. Value <code>0x2</code>. 61 */ 62 public static final int T_VIEW = 0x2; 63 64 /** 65 * Workbench constant. Value <code>0x3</code>. 66 */ 67 public static final int T_WORKBENCH = 0x3; 68 69 /** 70 * Editor constant. Value <code>0x4</code>. 71 */ 72 public static final int T_EDITOR = 0x4; 73 74 /** 75 * Workbench pulldown constant. Value <code>0x5</code>. 76 */ 77 public static final int T_WORKBENCH_PULLDOWN = 0x5; 78 79 /** 80 * Push style constant. Value <code>push</code>. 81 */ 82 public static final String STYLE_PUSH = "push"; //$NON-NLS-1$ 83 84 /** 85 * Radio style constant. Value <code>radio</code>. 86 */ 87 public static final String STYLE_RADIO = "radio"; //$NON-NLS-1$ 88 89 /*** 90 * Toggle style constant. Value <code>toggle</code>. 91 */ 92 public static final String STYLE_TOGGLE = "toggle"; //$NON-NLS-1$ 93 94 /** 95 * Pulldown style constant. Value <code>pulldown</code>. 96 */ 97 public static final String STYLE_PULLDOWN = "pulldown"; //$NON-NLS-1$ 98 99 /** 100 * Creates a new descriptor with the specified target. 101 * 102 * @param actionElement the configuration element 103 * @param targetType the type of action 104 */ ActionDescriptor(IConfigurationElement actionElement, int targetType)105 public ActionDescriptor(IConfigurationElement actionElement, int targetType) { 106 this(actionElement, targetType, null); 107 } 108 109 /** 110 * Creates a new descriptor with the target and destination workbench part it 111 * will go into. 112 * 113 * @param actionElement the configuration element 114 * @param targetType the type of action 115 * @param target the target object 116 */ ActionDescriptor(IConfigurationElement actionElement, int targetType, Object target)117 public ActionDescriptor(IConfigurationElement actionElement, int targetType, Object target) { 118 // Load attributes. 119 id = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID); 120 pluginId = actionElement.getContributor().getName(); 121 String label = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL); 122 String tooltip = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_TOOLTIP); 123 String helpContextId = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_HELP_CONTEXT_ID); 124 String mpath = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_MENUBAR_PATH); 125 String tpath = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_TOOLBAR_PATH); 126 String style = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STYLE); 127 String icon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ICON); 128 String hoverIcon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_HOVERICON); 129 String disabledIcon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_DISABLEDICON); 130 String description = actionElement.getAttribute(IWorkbenchRegistryConstants.TAG_DESCRIPTION); 131 String accelerator = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ACCELERATOR); 132 if ("FORCE_TEXT".equals(actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_MODE))) { //$NON-NLS-1$ 133 mode = ActionContributionItem.MODE_FORCE_TEXT; 134 } 135 136 // Verify input. 137 if (label == null) { 138 WorkbenchPlugin.log("Invalid action declaration (label == null): " + id); //$NON-NLS-1$ 139 label = WorkbenchMessages.ActionDescriptor_invalidLabel; 140 } 141 142 // Calculate menu and toolbar paths. 143 String mgroup = null; 144 String tgroup = null; 145 if (mpath != null) { 146 int loc = mpath.lastIndexOf('/'); 147 if (loc != -1) { 148 mgroup = mpath.substring(loc + 1); 149 mpath = mpath.substring(0, loc); 150 } else { 151 mgroup = mpath; 152 mpath = null; 153 } 154 } 155 if (targetType == T_POPUP && mgroup == null) { 156 mgroup = IWorkbenchActionConstants.MB_ADDITIONS; 157 } 158 if (tpath != null) { 159 int loc = tpath.lastIndexOf('/'); 160 if (loc != -1) { 161 tgroup = tpath.substring(loc + 1); 162 tpath = tpath.substring(0, loc); 163 } else { 164 tgroup = tpath; 165 tpath = null; 166 } 167 } 168 menuPath = mpath; 169 menuGroup = mgroup; 170 if ((tpath != null) && tpath.equals("Normal")) { //$NON-NLS-1$ 171 tpath = ""; //$NON-NLS-1$ 172 } 173 toolbarId = tpath; 174 toolbarGroupId = tgroup; 175 176 // Create action. 177 action = createAction(targetType, actionElement, target, style); 178 if (action.getText() == null) { 179 action.setText(label); 180 } 181 if (action.getToolTipText() == null && tooltip != null) { 182 action.setToolTipText(tooltip); 183 } 184 if (helpContextId != null) { 185 String fullID = helpContextId; 186 if (helpContextId.indexOf('.') == -1) { 187 // For backward compatibility we auto qualify the id if it is not 188 // qualified) 189 fullID = actionElement.getContributor().getName() + "." + helpContextId;//$NON-NLS-1$ 190 } 191 PlatformUI.getWorkbench().getHelpSystem().setHelp(action, fullID); 192 } 193 if (description != null) { 194 action.setDescription(description); 195 } 196 197 if (style != null) { 198 // Since 2.1, the "state" and "pulldown" attributes means something different 199 // when the new "style" attribute has been set. See doc for more info. 200 String state = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STATE); 201 if (state != null) { 202 if (style.equals(STYLE_RADIO) || style.equals(STYLE_TOGGLE)) { 203 action.setChecked(state.equals("true"));//$NON-NLS-1$ 204 } 205 } 206 } else { 207 // Keep for backward compatibility for actions not using the 208 // new style attribute. 209 String state = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STATE); 210 if (state != null) { 211 action.setChecked(state.equals("true"));//$NON-NLS-1$ 212 } 213 } 214 215 String extendingPluginId = actionElement.getDeclaringExtension().getContributor().getName(); 216 217 if (icon != null) { 218 ResourceLocator.imageDescriptorFromBundle(extendingPluginId, icon).ifPresent(action::setImageDescriptor); 219 } 220 if (hoverIcon != null) { 221 ResourceLocator.imageDescriptorFromBundle(extendingPluginId, hoverIcon) 222 .ifPresent(action::setHoverImageDescriptor); 223 } 224 if (disabledIcon != null) { 225 ResourceLocator.imageDescriptorFromBundle(extendingPluginId, disabledIcon) 226 .ifPresent(action::setDisabledImageDescriptor); 227 } 228 229 if (accelerator != null) { 230 processAccelerator(action, accelerator); 231 } 232 } 233 234 /** 235 * Creates an instance of PluginAction. Depending on the target part, subclasses 236 * of this class may be created. 237 */ createAction(int targetType, IConfigurationElement actionElement, Object target, String style)238 private PluginAction createAction(int targetType, IConfigurationElement actionElement, Object target, 239 String style) { 240 int actionStyle = IAction.AS_UNSPECIFIED; 241 if (style != null) { 242 switch (style) { 243 case STYLE_RADIO: 244 actionStyle = IAction.AS_RADIO_BUTTON; 245 break; 246 case STYLE_TOGGLE: 247 actionStyle = IAction.AS_CHECK_BOX; 248 break; 249 case STYLE_PULLDOWN: 250 actionStyle = IAction.AS_DROP_DOWN_MENU; 251 break; 252 case STYLE_PUSH: 253 actionStyle = IAction.AS_PUSH_BUTTON; 254 break; 255 default: 256 break; 257 } 258 } 259 260 switch (targetType) { 261 case T_VIEW: 262 return new ViewPluginAction(actionElement, (IViewPart) target, id, actionStyle); 263 case T_EDITOR: 264 return new EditorPluginAction(actionElement, (IEditorPart) target, id, actionStyle); 265 case T_WORKBENCH: 266 return new WWinPluginAction(actionElement, (IWorkbenchWindow) target, id, actionStyle); 267 case T_WORKBENCH_PULLDOWN: 268 actionStyle = IAction.AS_DROP_DOWN_MENU; 269 return new WWinPluginPulldown(actionElement, (IWorkbenchWindow) target, id, actionStyle); 270 case T_POPUP: 271 return new ObjectPluginAction(actionElement, id, actionStyle); 272 default: 273 WorkbenchPlugin.log("Unknown Action Type: " + targetType);//$NON-NLS-1$ 274 return null; 275 } 276 } 277 278 /** 279 * Returns the action object held in this descriptor. 280 * 281 * @return the action 282 */ getAction()283 public PluginAction getAction() { 284 return action; 285 } 286 287 /** 288 * Returns action's id as defined in the registry. 289 * 290 * @return the id 291 */ getId()292 public String getId() { 293 return id; 294 } 295 296 /** 297 * Returns named slot (group) in the menu where this action should be added. 298 * 299 * @return the menu group 300 */ getMenuGroup()301 public String getMenuGroup() { 302 return menuGroup; 303 } 304 305 /** 306 * Returns menu path where this action should be added. If null, the action will 307 * not be added into the menu. 308 * 309 * @return the menubar path 310 */ getMenuPath()311 public String getMenuPath() { 312 return menuPath; 313 } 314 315 /** 316 * Returns the named slot (group) in the tool bar where this action should be 317 * added. 318 * 319 * @return the toolbar group id 320 */ getToolbarGroupId()321 public String getToolbarGroupId() { 322 return toolbarGroupId; 323 } 324 325 /** 326 * Returns id of the tool bar where this action should be added. If null, action 327 * will not be added to the tool bar. 328 * 329 * @return the toolbar id 330 */ getToolbarId()331 public String getToolbarId() { 332 return toolbarId; 333 } 334 335 /** 336 * For debugging only. 337 */ 338 @Override toString()339 public String toString() { 340 return "ActionDescriptor(" + id + ")";//$NON-NLS-2$//$NON-NLS-1$ 341 } 342 343 /** 344 * Process the accelerator definition. If it is a number then process the code 345 * directly - if not then parse it and create the code 346 */ processAccelerator(IAction action, String acceleratorText)347 private void processAccelerator(IAction action, String acceleratorText) { 348 349 if (acceleratorText.length() == 0) { 350 return; 351 } 352 353 // Is it a numeric definition? 354 if (Character.isDigit(acceleratorText.charAt(0))) { 355 try { 356 action.setAccelerator(Integer.valueOf(acceleratorText).intValue()); 357 } catch (NumberFormatException e) { 358 WorkbenchPlugin.log("Invalid accelerator declaration for action: " + id, e); //$NON-NLS-1$ 359 } 360 } else { 361 action.setAccelerator(Action.convertAccelerator(acceleratorText)); 362 } 363 } 364 365 @Override getLocalId()366 public String getLocalId() { 367 return getId(); 368 } 369 370 @Override getPluginId()371 public String getPluginId() { 372 return pluginId; 373 } 374 getMode()375 public int getMode() { 376 return mode; 377 } 378 } 379