| /******************************************************************************* |
| * Copyright (c) 2013, 2018 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.internal; |
| |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.Set; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker; |
| import org.eclipse.ui.IPageLayout; |
| import org.eclipse.ui.IViewLayout; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout; |
| import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; |
| import org.eclipse.ui.internal.registry.RegistryReader; |
| |
| /** |
| * A strategy to read perspective extension from the registry. A pespective |
| * extension is one of a view, viewAction, perspAction, newWizardAction, or |
| * actionSet. |
| */ |
| public class PerspectiveExtensionReader extends RegistryReader { |
| private String targetID; |
| |
| private ModeledPageLayout pageLayout; |
| |
| private Set<String> includeOnlyTags = null; |
| |
| private static final String VAL_LEFT = "left";//$NON-NLS-1$ |
| |
| private static final String VAL_RIGHT = "right";//$NON-NLS-1$ |
| |
| private static final String VAL_TOP = "top";//$NON-NLS-1$ |
| |
| private static final String VAL_BOTTOM = "bottom";//$NON-NLS-1$ |
| |
| private static final String VAL_STACK = "stack";//$NON-NLS-1$ |
| |
| private static final String VAL_FAST = "fast";//$NON-NLS-1$ |
| |
| private static final String VAL_TRUE = "true";//$NON-NLS-1$ |
| |
| // VAL_FALSE added by dan_rubel@instantiations.com |
| // TODO: this logic is backwards... we should be checking for true, but |
| // technically this is API now... |
| private static final String VAL_FALSE = "false";//$NON-NLS-1$ |
| |
| private IExtensionTracker tracker; |
| |
| /** |
| * PerspectiveExtensionReader constructor.. |
| */ |
| public PerspectiveExtensionReader() { |
| // do nothing |
| } |
| |
| /** |
| * Read the view extensions within a registry. |
| * |
| * @param extensionTracker the tracker |
| * @param id the id |
| * @param out the layout |
| */ |
| public void extendLayout(IExtensionTracker extensionTracker, String id, ModeledPageLayout out) { |
| tracker = extensionTracker; |
| targetID = id; |
| pageLayout = out; |
| readRegistry(Platform.getExtensionRegistry(), PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_PERSPECTIVE_EXTENSIONS); |
| } |
| |
| /** |
| * Returns whether the given tag should be included. |
| */ |
| private boolean includeTag(String tag) { |
| return includeOnlyTags == null || includeOnlyTags.contains(tag); |
| } |
| |
| /** |
| * Process an action set. |
| */ |
| private boolean processActionSet(IConfigurationElement element) { |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID); |
| if (id != null) { |
| pageLayout.addActionSet(id); |
| } |
| return true; |
| } |
| |
| /** |
| * Process an extension. Assumption: Extension is for current perspective. |
| */ |
| private boolean processExtension(IConfigurationElement element) { |
| IConfigurationElement[] children = element.getChildren(); |
| for (IConfigurationElement child : children) { |
| String type = child.getName(); |
| if (includeTag(type)) { |
| boolean result = false; |
| switch (type) { |
| case IWorkbenchRegistryConstants.TAG_ACTION_SET: |
| result = processActionSet(child); |
| break; |
| case IWorkbenchRegistryConstants.TAG_VIEW: |
| result = processView(child); |
| break; |
| case IWorkbenchRegistryConstants.TAG_VIEW_SHORTCUT: |
| result = processViewShortcut(child); |
| break; |
| case IWorkbenchRegistryConstants.TAG_NEW_WIZARD_SHORTCUT: |
| result = processWizardShortcut(child); |
| break; |
| case IWorkbenchRegistryConstants.TAG_PERSP_SHORTCUT: |
| result = processPerspectiveShortcut(child); |
| break; |
| case IWorkbenchRegistryConstants.TAG_SHOW_IN_PART: |
| result = processShowInPart(child); |
| break; |
| case IWorkbenchRegistryConstants.TAG_HIDDEN_MENU_ITEM: |
| result = processHiddenMenuItem(child); |
| break; |
| case IWorkbenchRegistryConstants.TAG_HIDDEN_TOOLBAR_ITEM: |
| result = processHiddenToolBarItem(child); |
| break; |
| default: |
| break; |
| } |
| if (!result) { |
| WorkbenchPlugin.log("Unable to process element: " + //$NON-NLS-1$ |
| type + " in perspective extension: " + //$NON-NLS-1$ |
| element.getDeclaringExtension().getUniqueIdentifier()); |
| } |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Process a perspective shortcut |
| */ |
| private boolean processPerspectiveShortcut(IConfigurationElement element) { |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID); |
| if (id != null) { |
| pageLayout.addPerspectiveShortcut(id); |
| } |
| return true; |
| } |
| |
| /** |
| * Process a show in element. |
| */ |
| private boolean processShowInPart(IConfigurationElement element) { |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID); |
| if (id != null) { |
| pageLayout.addShowInPart(id); |
| } |
| return true; |
| } |
| |
| /** |
| * Process a hidden menu item |
| */ |
| private boolean processHiddenMenuItem(IConfigurationElement element) { |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID); |
| if (id != null) { |
| pageLayout.addHiddenMenuItemId(id); |
| } |
| return true; |
| } |
| |
| /** |
| * Process a hidden toolbar item |
| */ |
| private boolean processHiddenToolBarItem(IConfigurationElement element) { |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID); |
| if (id != null) { |
| pageLayout.addHiddenToolBarItemId(id); |
| } |
| return true; |
| } |
| |
| // processView(IConfigurationElement) modified by dan_rubel@instantiations.com |
| /** |
| * Process a view |
| */ |
| private boolean processView(IConfigurationElement element) { |
| // Get id, relative, and relationship. |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID); |
| String relative = element.getAttribute(IWorkbenchRegistryConstants.ATT_RELATIVE); |
| String relationship = element.getAttribute(IWorkbenchRegistryConstants.ATT_RELATIONSHIP); |
| String ratioString = element.getAttribute(IWorkbenchRegistryConstants.ATT_RATIO); |
| boolean visible = !VAL_FALSE.equals(element.getAttribute(IWorkbenchRegistryConstants.ATT_VISIBLE)); |
| String closeable = element.getAttribute(IWorkbenchRegistryConstants.ATT_CLOSEABLE); |
| String moveable = element.getAttribute(IWorkbenchRegistryConstants.ATT_MOVEABLE); |
| String standalone = element.getAttribute(IWorkbenchRegistryConstants.ATT_STANDALONE); |
| String showTitle = element.getAttribute(IWorkbenchRegistryConstants.ATT_SHOW_TITLE); |
| |
| // Default to 'false' |
| String minVal = element.getAttribute(IWorkbenchRegistryConstants.ATT_MINIMIZED); |
| boolean minimized = minVal != null && VAL_TRUE.equals(minVal); |
| |
| float ratio; |
| |
| if (id == null) { |
| logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_ID); |
| return false; |
| } |
| if (relationship == null) { |
| logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_RELATIONSHIP); |
| return false; |
| } |
| if (!VAL_FAST.equals(relationship) && relative == null) { |
| logError(element, "Attribute '" + IWorkbenchRegistryConstants.ATT_RELATIVE //$NON-NLS-1$ |
| + "' not defined. This attribute is required when " //$NON-NLS-1$ |
| + IWorkbenchRegistryConstants.ATT_RELATIONSHIP + "=\"" + relationship + "\"."); //$NON-NLS-1$ //$NON-NLS-2$ |
| return false; |
| } |
| // Get the ratio. |
| if (ratioString == null) { |
| // The ratio has not been specified. |
| ratio = IPageLayout.NULL_RATIO; |
| } else { |
| try { |
| ratio = Float.parseFloat(ratioString); |
| } catch (NumberFormatException e) { |
| return false; |
| } |
| // If the ratio is outside the allowable range, mark it as invalid. |
| if (ratio < IPageLayout.RATIO_MIN || ratio > IPageLayout.RATIO_MAX) { |
| ratio = IPageLayout.INVALID_RATIO; |
| } |
| } |
| |
| // Get relationship details. |
| boolean stack = false; |
| int intRelation = 0; |
| boolean fast = false; |
| switch (relationship) { |
| case VAL_LEFT: |
| intRelation = IPageLayout.LEFT; |
| break; |
| case VAL_RIGHT: |
| intRelation = IPageLayout.RIGHT; |
| break; |
| case VAL_TOP: |
| intRelation = IPageLayout.TOP; |
| break; |
| case VAL_BOTTOM: |
| intRelation = IPageLayout.BOTTOM; |
| break; |
| case VAL_STACK: |
| stack = true; |
| break; |
| case VAL_FAST: |
| fast = true; |
| break; |
| default: |
| return false; |
| } |
| |
| if (visible) { |
| // If adding a view (not just a placeholder), remove any existing placeholder. |
| // See bug 85948 [Perspectives] Adding register & expressions view by default to |
| // debug perspective fails |
| pageLayout.removePlaceholder(id); |
| } |
| |
| // If stack .. |
| if (stack) { |
| if (visible) { |
| pageLayout.stackView(id, relative, true); |
| } else { |
| pageLayout.stackView(id, relative, false); |
| } |
| } |
| // If the view is a fast view... |
| else if (fast) { |
| if (ratio == IPageLayout.NULL_RATIO) { |
| // The ratio has not been specified. |
| pageLayout.addFastView(id); |
| } else { |
| pageLayout.addFastView(id, ratio); |
| } |
| } else { |
| |
| // The view is a regular view. |
| // If the ratio is not specified or is invalid, use the default ratio. |
| if (ratio == IPageLayout.NULL_RATIO || ratio == IPageLayout.INVALID_RATIO) { |
| ratio = IPageLayout.DEFAULT_VIEW_RATIO; |
| } |
| |
| if (visible) { |
| if (VAL_TRUE.equals(standalone)) { |
| pageLayout.addStandaloneView(id, !VAL_FALSE.equals(showTitle), intRelation, ratio, relative); |
| } else { |
| pageLayout.addView(id, intRelation, ratio, relative, minimized); |
| } |
| } else // Fix for 99155, CGross (schtoo@schtoo.com) |
| // Adding standalone placeholder for standalone views |
| if (VAL_TRUE.equals(standalone)) { |
| pageLayout.addStandaloneViewPlaceholder(id, intRelation, ratio, relative, |
| !VAL_FALSE.equals(showTitle)); |
| } else { |
| pageLayout.addPlaceholder(id, intRelation, ratio, relative); |
| } |
| } |
| IViewLayout viewLayout = pageLayout.getViewLayout(id); |
| // may be null if it's been filtered by activity |
| if (viewLayout != null) { |
| if (closeable != null) { |
| viewLayout.setCloseable(!VAL_FALSE.equals(closeable)); |
| } |
| if (moveable != null) { |
| viewLayout.setMoveable(!VAL_FALSE.equals(moveable)); |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Process a view shortcut |
| */ |
| private boolean processViewShortcut(IConfigurationElement element) { |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID); |
| if (id != null) { |
| pageLayout.addShowViewShortcut(id); |
| } |
| return true; |
| } |
| |
| /** |
| * Process a wizard shortcut |
| */ |
| private boolean processWizardShortcut(IConfigurationElement element) { |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID); |
| if (id != null) { |
| pageLayout.addNewWizardShortcut(id); |
| } |
| return true; |
| } |
| |
| @Override |
| protected boolean readElement(IConfigurationElement element) { |
| String type = element.getName(); |
| if (type.equals(IWorkbenchRegistryConstants.TAG_PERSPECTIVE_EXTENSION)) { |
| String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID); |
| if (targetID.equals(id) || "*".equals(id)) { //$NON-NLS-1$ |
| if (tracker != null) { |
| tracker.registerObject(element.getDeclaringExtension(), new DirtyPerspectiveMarker(id), |
| IExtensionTracker.REF_STRONG); |
| } |
| return processExtension(element); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Sets the tags to include. All others are ignored. |
| * |
| * @param tags the tags to include |
| */ |
| public void setIncludeOnlyTags(String[] tags) { |
| includeOnlyTags = new HashSet<>(); |
| includeOnlyTags.addAll(Arrays.asList(tags)); |
| } |
| } |