| /******************************************************************************* |
| * Copyright (c) 2004, 2016 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.intro.impl.model; |
| |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.ui.internal.intro.impl.model.util.BundleUtil; |
| import org.eclipse.ui.internal.intro.impl.util.StringUtil; |
| import org.osgi.framework.Bundle; |
| import org.w3c.dom.Element; |
| |
| /** |
| * An intro config component. All config components can get to their defining |
| * config element or bundle depending from where the element was loaded. |
| * <p> |
| * Class Rules: |
| * <ul> |
| * <li>If an element does not appear as a child under any node, then that |
| * element does not need a type to be defined.</li> |
| * <li>Each subclass must ensure that it properly supports cloning. This means |
| * that if a deep copy is needed, the subclass must override the base behavior |
| * here.</li> |
| * <li>if cloning is not needed, override clone method and throw an unsupported |
| * cloning exception. For now, only pages and targets of includes are cloneable. |
| * </li> |
| * </ul> |
| * <p> |
| * Note: This is an abstract base class for all classes in the Intro Model. <br> |
| * Clients are not expected to implement or subclass this class, or any of its |
| * subclasses. |
| */ |
| public abstract class AbstractIntroElement implements Cloneable { |
| |
| /** |
| * Type constant which identifies an IntroModelRoot element. |
| */ |
| public static final int MODEL_ROOT = 1; |
| |
| /** |
| * Type constant which identifies an IntroPartPresentation element. |
| */ |
| public static final int PRESENTATION = 1 << 1; |
| |
| /** |
| * Type constant which identifies an IntroHomePage element. |
| */ |
| public static final int HOME_PAGE = 1 << 2; |
| |
| /** |
| * Type constant which identifies the IntroPage element. |
| */ |
| public static final int PAGE = 1 << 3; |
| |
| /** |
| * Type constant which identifies the AbstractIntroPage element. |
| */ |
| public static final int ABSTRACT_PAGE = HOME_PAGE | PAGE; |
| |
| /** |
| * Type constant which identifies an IntroDiv element. |
| */ |
| public static final int GROUP = 1 << 4; |
| |
| /** |
| * Type constant which identifies the AbstractIntroContainer element. |
| */ |
| public static final int ABSTRACT_CONTAINER = ABSTRACT_PAGE | GROUP |
| | MODEL_ROOT; |
| |
| /** |
| * Type constant which identifies the IntroHtml element. |
| */ |
| public static final int HTML = 1 << 5; |
| |
| /** |
| * Type constant which identifies the IntroLink element. |
| */ |
| public static final int LINK = 1 << 6; |
| |
| /** |
| * Type constant which identifies the IntroImage element. |
| */ |
| public static final int IMAGE = 1 << 7; |
| |
| /** |
| * Type constant which identifies the IntroInclude element. |
| */ |
| public static final int INCLUDE = 1 << 8; |
| |
| /** |
| * Type constant which identifies the IntroText element. |
| */ |
| public static final int TEXT = 1 << 9; |
| |
| /** |
| * Type constant which identifies the IntroContainerExtension element. |
| */ |
| public static final int CONTAINER_EXTENSION = 1 << 10; |
| |
| /** |
| * Type constant which identifies the IntroHead element. |
| */ |
| public static final int HEAD = 1 << 11; |
| |
| /** |
| * Type constant which identifies the IntroHead element. |
| */ |
| public static final int PAGE_TITLE = 1 << 12; |
| |
| /** |
| * Type constant which identifies the IntroAnchor element. |
| */ |
| public static final int ANCHOR = 1 << 13; |
| |
| /** |
| * Type constant which identifies the IntroContentProvider element. |
| */ |
| public static final int CONTENT_PROVIDER = 1 << 14; |
| |
| /** |
| * Type constant which identifies the LaunchBarElement. |
| */ |
| public static final int LAUNCH_BAR = 1 << 15; |
| |
| /** |
| * Type constant which identifies the launch bar shortcut. |
| */ |
| public static final int LAUNCH_BAR_SHORTCUT = 1 << 16; |
| |
| /** |
| * Type constant which identifies am injected IFrame model element. |
| */ |
| public static final int INJECTED_IFRAME = 1 << 17; |
| |
| /** |
| * Type constant for the theme element. |
| */ |
| public static final int THEME = 1 << 18; |
| |
| /** |
| * Type constant for the hr element. |
| */ |
| public static final int HR = 1 << 19; |
| |
| |
| /** |
| * Type constant which identifies the AbstractText element. |
| */ |
| public static final int ABSTRACT_TEXT = HTML | LINK | CONTENT_PROVIDER; |
| |
| /** |
| * Type constant which identifies the AbstractCommonIntroElement element. |
| */ |
| public static final int BASE_ELEMENT = ABSTRACT_CONTAINER | ABSTRACT_TEXT |
| | IMAGE | TEXT | PAGE_TITLE; |
| |
| /** |
| * Type constant which identifies any element in the Intro Model which can |
| * have an id. Note: eventhough IntroStandbyContentPart has an id, it does |
| * not appear as a child in the model, and so it does not have a type. |
| */ |
| public static final int ID_ELEMENT = BASE_ELEMENT | ANCHOR; |
| |
| /** |
| * Type constant which identifies any element in the Intro Model. |
| */ |
| public static final int ELEMENT = ID_ELEMENT | CONTAINER_EXTENSION | HEAD |
| | INCLUDE | PRESENTATION | LAUNCH_BAR | LAUNCH_BAR_SHORTCUT; |
| |
| |
| |
| private AbstractIntroElement parent; |
| private Object cfgElement; |
| private Bundle bundle; |
| private String mixinStyle; |
| |
| |
| /** |
| * Constructor used when model elements are being loaded from plugin.xml. |
| */ |
| AbstractIntroElement(IConfigurationElement element) { |
| cfgElement = element; |
| bundle = BundleUtil.getBundleFromConfigurationElement(element); |
| } |
| |
| |
| /** |
| * Constructor used when model elements are being loaded from an xml content |
| * file. Bundle is propagated down the model to enable resolving resources |
| * relative to the base of the bundle. |
| * |
| * @param element |
| * @param pd |
| */ |
| AbstractIntroElement(Element element, Bundle bundle) { |
| this.cfgElement = element; |
| this.bundle = bundle; |
| } |
| |
| |
| /** |
| * Constructor used when model elements are being loaded from an xml content |
| * file. Bundle AND base is propagated down the model to enable resolving |
| * resources relative to the xml content file. The base is set to point to |
| * the relative location of the parent folder that holds the content file. |
| * In the case of a configExtension, it is set to point to the relative |
| * position of the parent folder that holds the extension. Only when needed, |
| * the base field is stored in a model element. This saves memory. |
| * |
| * @param element |
| * @param pd |
| */ |
| AbstractIntroElement(Element element, Bundle bundle, String base) { |
| this(element, bundle); |
| } |
| |
| |
| |
| |
| /** |
| * Returns the configuration element from which this intro element was |
| * loaded. In the case of extension, returns the configuration element of |
| * the defining extension. |
| * |
| * @return |
| */ |
| public IConfigurationElement getCfgElement() { |
| return cfgElement instanceof IConfigurationElement?(IConfigurationElement)cfgElement:null; |
| } |
| |
| public Element getElement() { |
| return cfgElement instanceof Element?(Element)cfgElement:null; |
| } |
| |
| /** |
| * DOM getAttribute retruns an empty string (not null) if attribute is not |
| * defined. Override this behavior to be consistent with Intro Model, and |
| * IConfiguration element. |
| * |
| * @param element |
| * @param att |
| * @return |
| */ |
| protected String getAttribute(Element element, String att) { |
| if (element.hasAttribute(att)) { |
| String value = element.getAttribute(att); |
| if (value!=null) { |
| IntroModelRoot root = getModelRoot(); |
| if (root!=null) |
| return root.resolveVariables(value); |
| return value; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Util method to parse a comma separated list of values |
| * |
| * @param element |
| * @param att |
| * @return |
| */ |
| protected String[] getAttributeList(Element element, String att) { |
| if (element.hasAttribute(att)) { |
| String value = element.getAttribute(att); |
| if (value!=null) { |
| String[] splitValues = StringUtil.split(value, ","); //$NON-NLS-1$ |
| IntroModelRoot root = getModelRoot(); |
| if (root!=null) { |
| for (int i = 0; i < splitValues.length; i++) { |
| splitValues[i] = root.resolveVariables(splitValues[i]); |
| } |
| } |
| return splitValues; |
| } |
| } |
| /* |
| if (element.hasAttribute(att)) |
| return element.getAttribute(att).split(","); //$NON-NLS-1$ |
| */ |
| return null; |
| } |
| |
| protected void loadFromParent() { |
| } |
| |
| |
| /** |
| * Returns the plugin descriptor of the plugin from which this intro element |
| * was loaded. In the case of extension, returns the plugin descriptor of |
| * the plugin defining the extension. |
| * |
| * @return |
| */ |
| public Bundle getBundle() { |
| return bundle; |
| } |
| |
| |
| |
| /** |
| * Returns the specific model type of this intro element. To be implemented |
| * by all subclasses. |
| * |
| * @return returns one of the model class types defined in this class. |
| */ |
| public abstract int getType(); |
| |
| |
| /** |
| * Returns the parent of this intro element. |
| * <p> |
| * Rules: |
| * <ul> |
| * <li>For the model root, it retruns null.</li> |
| * <li>For the introPart presentation it returns a model root.</li> |
| * <li>For Pages, it returns an intro model root.</li> |
| * <li>For all other elements, it retruns a subclass of abstract container. |
| * </li> |
| * <li>for divs that are children of configs (shared divs), it returns the |
| * holding model root.</li> |
| * <li>for Head elements that are children of Implementation elements |
| * (shared Heads), it returns the holding presentation element.</li> |
| * </ul> |
| * |
| * @return returns the parent of this intro element. Null only for model |
| * root. |
| */ |
| public AbstractIntroElement getParent() { |
| return parent; |
| } |
| |
| /** |
| * @param parent |
| * The parent to set. |
| */ |
| public void setParent(AbstractIntroElement parent) { |
| this.parent = parent; |
| if (parent!=null) |
| loadFromParent(); |
| } |
| |
| public void setBundle(Bundle bundle) { |
| this.bundle = bundle; |
| } |
| |
| /** |
| * Returns the parent page holding this intro element. For the model root |
| * and the introPart presentation it returns null. For Pages, it returns the |
| * page itself. For all other element, returns the holding page. |
| * <p> |
| * Exceptions: |
| * <ul> |
| * <li>for divs that are children of configs (shared divs), it returns |
| * null.</li> |
| * <li>for Head elements that are children of Implementation elements |
| * (shared Heads), it returns null.</li> |
| * </ul> |
| */ |
| public AbstractIntroPage getParentPage() { |
| // return yourself if you are a page. |
| if (isOfType(AbstractIntroElement.ABSTRACT_PAGE)) |
| return (AbstractIntroPage) this; |
| |
| AbstractIntroElement parent = getParent(); |
| if (parent == null) |
| return null; |
| |
| while (parent != null && parent.getParent() != null |
| && !parent.isOfType(AbstractIntroElement.ABSTRACT_PAGE)) |
| parent = parent.getParent(); |
| if (parent.isOfType(ABSTRACT_PAGE)) |
| return (AbstractIntroPage) parent; |
| return null; |
| } |
| |
| public IntroModelRoot getModelRoot() { |
| // return yourself if you are a model root. |
| if (isOfType(AbstractIntroElement.MODEL_ROOT)) |
| return (IntroModelRoot) this; |
| |
| AbstractIntroElement parent = getParent(); |
| if (parent == null) |
| return null; |
| |
| while (parent != null && parent.getParent() != null |
| && !parent.isOfType(AbstractIntroElement.MODEL_ROOT)) |
| parent = parent.getParent(); |
| if (parent.isOfType(MODEL_ROOT)) |
| return (IntroModelRoot) parent; |
| return null; |
| } |
| |
| |
| /** |
| * Returns whether the element is among the specified element types. An |
| * example of an element mask is as follows: |
| * <p> |
| * <code> |
| * int elementMask = IntroElement.ABSTRACT_CONTAINER; |
| * int elementMask = IntroElement.DIV | IntroElement.DEFAULT_LINK; |
| * </code> |
| * |
| * @param elementMask |
| * element mask formed by bitwise OR of element type constants |
| * defined in this class. |
| * @return <code>true</code> if this element has a matching type, and |
| * <code>false</code> otherwise. |
| */ |
| public boolean isOfType(int elementMask) { |
| return (getType() & elementMask) != 0; |
| } |
| |
| /** |
| * Returns whether the types of all the elements in the given array are |
| * among the specified element types. <br> |
| * An example of an element mask is as follows: |
| * <p> |
| * <code> |
| * int elementMask = IntroElement.DIV | IntroElement.DEFAULT_LINK; |
| * </code> |
| * |
| * @return <code>true</code> if all elements are of the right type, and |
| * <code>false</code> if the list is empty, or at least one |
| * element is not of the specified types. |
| */ |
| public static final boolean allElementsAreOfType( |
| AbstractIntroElement[] elements, int elementMask) { |
| // if we have an empty list, no point going on. |
| if (elements.length == 0) |
| return false; |
| |
| for (int i = 0; i < elements.length; i++) { |
| AbstractIntroElement element = elements[i]; |
| if (!element.isOfType(elementMask)) |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Shallow copy. The design of cloning this model assumes that when a |
| * container is cloned, all its children must be cloned and reparented to |
| * it, hence one clone of this container object. This is why we have a |
| * shallow copy here. |
| */ |
| @Override |
| public Object clone() throws CloneNotSupportedException { |
| return super.clone(); |
| } |
| |
| |
| |
| public String getMixinStyle() { |
| return mixinStyle; |
| } |
| |
| |
| |
| public void setMixinStyle(String mixinStyle) { |
| this.mixinStyle = mixinStyle; |
| } |
| |
| |
| |
| } |