001: /*******************************************************************************
002: * Copyright (c) 2004, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.intro.impl.model;
011:
012: import org.eclipse.core.runtime.IConfigurationElement;
013: import org.eclipse.ui.internal.intro.impl.model.util.BundleUtil;
014: import org.eclipse.ui.internal.intro.impl.util.StringUtil;
015: import org.osgi.framework.Bundle;
016: import org.w3c.dom.Element;
017:
018: /**
019: * An intro config component. All config components can get to their defining
020: * config element or bundle depending from where the element was loaded.
021: * <p>
022: * Class Rules:
023: * <ul>
024: * <li>If an element does not appear as a child under any node, then that
025: * element does not need a type to be defined.</li>
026: * <li>Each subclass must ensure that it properly supports cloning. This means
027: * that if a deep copy is needed, the subclass must override the base behavior
028: * here.</li>
029: * <li>if cloning is not needed, override clone method and throw an unsupported
030: * cloning exception. For now, only pages and targets of includes are cloneable.
031: * </li>
032: * </ul>
033: * <p>
034: * Note: This is an abstract base class for all classes in the Intro Model. <br>
035: * Clients are not expected to implement or subclass this class, or any of its
036: * subclasses.
037: */
038: public abstract class AbstractIntroElement implements Cloneable {
039:
040: /**
041: * Type constant which identifies an IntroModelRoot element.
042: */
043: public static final int MODEL_ROOT = 1;
044:
045: /**
046: * Type constant which identifies an IntroPartPresentation element.
047: */
048: public static final int PRESENTATION = 1 << 1;
049:
050: /**
051: * Type constant which identifies an IntroHomePage element.
052: */
053: public static final int HOME_PAGE = 1 << 2;
054:
055: /**
056: * Type constant which identifies the IntroPage element.
057: */
058: public static final int PAGE = 1 << 3;
059:
060: /**
061: * Type constant which identifies the AbstractIntroPage element.
062: */
063: public static final int ABSTRACT_PAGE = HOME_PAGE | PAGE;
064:
065: /**
066: * Type constant which identifies an IntroDiv element.
067: */
068: public static final int GROUP = 1 << 4;
069:
070: /**
071: * Type constant which identifies the AbstractIntroContainer element.
072: */
073: public static final int ABSTRACT_CONTAINER = ABSTRACT_PAGE | GROUP
074: | MODEL_ROOT;
075:
076: /**
077: * Type constant which identifies the IntroHtml element.
078: */
079: public static final int HTML = 1 << 5;
080:
081: /**
082: * Type constant which identifies the IntroLink element.
083: */
084: public static final int LINK = 1 << 6;
085:
086: /**
087: * Type constant which identifies the IntroImage element.
088: */
089: public static final int IMAGE = 1 << 7;
090:
091: /**
092: * Type constant which identifies the IntroInclude element.
093: */
094: public static final int INCLUDE = 1 << 8;
095:
096: /**
097: * Type constant which identifies the IntroText element.
098: */
099: public static final int TEXT = 1 << 9;
100:
101: /**
102: * Type constant which identifies the IntroContainerExtension element.
103: */
104: public static final int CONTAINER_EXTENSION = 1 << 10;
105:
106: /**
107: * Type constant which identifies the IntroHead element.
108: */
109: public static final int HEAD = 1 << 11;
110:
111: /**
112: * Type constant which identifies the IntroHead element.
113: */
114: public static final int PAGE_TITLE = 1 << 12;
115:
116: /**
117: * Type constant which identifies the IntroAnchor element.
118: */
119: public static final int ANCHOR = 1 << 13;
120:
121: /**
122: * Type constant which identifies the IntroContentProvider element.
123: */
124: public static final int CONTENT_PROVIDER = 1 << 14;
125:
126: /**
127: * Type constant which identifies the LaunchBarElement.
128: */
129: public static final int LAUNCH_BAR = 1 << 15;
130:
131: /**
132: * Type constant which identifies the launch bar shortcut.
133: */
134: public static final int LAUNCH_BAR_SHORTCUT = 1 << 16;
135:
136: /**
137: * Type constant which identifies am injected IFrame model element.
138: */
139: public static final int INJECTED_IFRAME = 1 << 17;
140:
141: /**
142: * Type constant for the theme element.
143: */
144: public static final int THEME = 1 << 18;
145:
146: /**
147: * Type constant for the hr element.
148: */
149: public static final int HR = 1 << 19;
150:
151: /**
152: * Type constant which identifies the AbstractText element.
153: */
154: public static final int ABSTRACT_TEXT = HTML | LINK
155: | CONTENT_PROVIDER;
156:
157: /**
158: * Type constant which identifies the AbstractCommonIntroElement element.
159: */
160: public static final int BASE_ELEMENT = ABSTRACT_CONTAINER
161: | ABSTRACT_TEXT | IMAGE | TEXT | PAGE_TITLE;
162:
163: /**
164: * Type constant which identifies any element in the Intro Model which can
165: * have an id. Note: eventhough IntroStandbyContentPart has an id, it does
166: * not appear as a child in the model, and so it does not have a type.
167: */
168: public static final int ID_ELEMENT = BASE_ELEMENT | ANCHOR;
169:
170: /**
171: * Type constant which identifies any element in the Intro Model.
172: */
173: public static final int ELEMENT = ID_ELEMENT | CONTAINER_EXTENSION
174: | HEAD | INCLUDE | PRESENTATION | LAUNCH_BAR
175: | LAUNCH_BAR_SHORTCUT;
176:
177: private AbstractIntroElement parent;
178: private Object cfgElement;
179: private Bundle bundle;
180: private String mixinStyle;
181:
182: /**
183: * Constructor used when model elements are being loaded from plugin.xml.
184: */
185: AbstractIntroElement(IConfigurationElement element) {
186: cfgElement = element;
187: bundle = BundleUtil.getBundleFromConfigurationElement(element);
188: }
189:
190: /**
191: * Constructor used when model elements are being loaded from an xml content
192: * file. Bundle is propagated down the model to enable resolving resources
193: * relative to the base of the bundle.
194: *
195: * @param element
196: * @param pd
197: */
198: AbstractIntroElement(Element element, Bundle bundle) {
199: this .cfgElement = element;
200: this .bundle = bundle;
201: }
202:
203: /**
204: * Constructor used when model elements are being loaded from an xml content
205: * file. Bundle AND base is propagated down the model to enable resolving
206: * resources relative to the xml content file. The base is set to point to
207: * the relative location of the parent folder that holds the content file.
208: * In the case of a configExtension, it is set to point to the relative
209: * position of the parent folder that holds the extension. Only when needed,
210: * the base field is stored in a model element. This saves memory.
211: *
212: * @param element
213: * @param pd
214: */
215: AbstractIntroElement(Element element, Bundle bundle, String base) {
216: this (element, bundle);
217: }
218:
219: /**
220: * Returns the configuration element from which this intro element was
221: * loaded. In the case of extension, returns the configuration element of
222: * the defining extension.
223: *
224: * @return
225: */
226: public IConfigurationElement getCfgElement() {
227: return cfgElement instanceof IConfigurationElement ? (IConfigurationElement) cfgElement
228: : null;
229: }
230:
231: public Element getElement() {
232: return cfgElement instanceof Element ? (Element) cfgElement
233: : null;
234: }
235:
236: /**
237: * DOM getAttribute retruns an empty string (not null) if attribute is not
238: * defined. Override this behavior to be consistent with Intro Model, and
239: * IConfiguration element.
240: *
241: * @param element
242: * @param att
243: * @return
244: */
245: protected String getAttribute(Element element, String att) {
246: if (element.hasAttribute(att)) {
247: String value = element.getAttribute(att);
248: if (value != null) {
249: IntroModelRoot root = getModelRoot();
250: if (root != null)
251: return root.resolveVariables(value);
252: return value;
253: }
254: }
255: return null;
256: }
257:
258: /**
259: * Util method to parse a comma separated list of values
260: *
261: * @param element
262: * @param att
263: * @return
264: */
265: protected String[] getAttributeList(Element element, String att) {
266: if (element.hasAttribute(att)) {
267: String value = element.getAttribute(att);
268: if (value != null) {
269: IntroModelRoot root = getModelRoot();
270: if (root != null)
271: value = root.resolveVariables(value);
272: return StringUtil.split(value, ","); //$NON-NLS-1$
273: }
274: }
275: /*
276: if (element.hasAttribute(att))
277: return element.getAttribute(att).split(","); //$NON-NLS-1$
278: */
279: return null;
280: }
281:
282: protected void loadFromParent() {
283: }
284:
285: /**
286: * Returns the plugin descriptor of the plugin from which this intro element
287: * was loaded. In the case of extension, returns the plugin descriptor of
288: * the plugin defining the extension.
289: *
290: * @return
291: */
292: public Bundle getBundle() {
293: return bundle;
294: }
295:
296: /**
297: * Returns the specific model type of this intro element. To be implemented
298: * by all subclasses.
299: *
300: * @return returns one of the model class types defined in this class.
301: */
302: public abstract int getType();
303:
304: /**
305: * Returns the parent of this intro element.
306: * <p>
307: * Rules:
308: * <ul>
309: * <li>For the model root, it retruns null.</li>
310: * <li>For the introPart presentation it returns a model root.</li>
311: * <li>For Pages, it returns an intro model root.</li>
312: * <li>For all other elements, it retruns a subclass of abstract container.
313: * </li>
314: * <li>for divs that are children of configs (shared divs), it returns the
315: * holding model root.</li>
316: * <li>for Head elements that are children of Implementation elements
317: * (shared Heads), it returns the holding presentation element.</li>
318: * </ul>
319: *
320: * @return returns the parent of this intro element. Null only for model
321: * root.
322: */
323: public AbstractIntroElement getParent() {
324: return parent;
325: }
326:
327: /**
328: * @param parent
329: * The parent to set.
330: */
331: public void setParent(AbstractIntroElement parent) {
332: this .parent = parent;
333: if (parent != null)
334: loadFromParent();
335: }
336:
337: public void setBundle(Bundle bundle) {
338: this .bundle = bundle;
339: }
340:
341: /**
342: * Returns the parent page holding this intro element. For the model root
343: * and the introPart presentation it returns null. For Pages, it returns the
344: * page itself. For all other element, returns the holding page.
345: * <p>
346: * Exceptions:
347: * <ul>
348: * <li>for divs that are children of configs (shared divs), it returns
349: * null.</li>
350: * <li>for Head elements that are children of Implementation elements
351: * (shared Heads), it returns null.</li>
352: * </ul>
353: */
354: public AbstractIntroPage getParentPage() {
355: // return yourself if you are a page.
356: if (isOfType(AbstractIntroElement.ABSTRACT_PAGE))
357: return (AbstractIntroPage) this ;
358:
359: AbstractIntroElement parent = getParent();
360: if (parent == null)
361: return null;
362:
363: while (parent != null && parent.getParent() != null
364: && !parent.isOfType(AbstractIntroElement.ABSTRACT_PAGE))
365: parent = parent.getParent();
366: if (parent.isOfType(ABSTRACT_PAGE))
367: return (AbstractIntroPage) parent;
368: return null;
369: }
370:
371: public IntroModelRoot getModelRoot() {
372: // return yourself if you are a model root.
373: if (isOfType(AbstractIntroElement.MODEL_ROOT))
374: return (IntroModelRoot) this ;
375:
376: AbstractIntroElement parent = getParent();
377: if (parent == null)
378: return null;
379:
380: while (parent != null && parent.getParent() != null
381: && !parent.isOfType(AbstractIntroElement.MODEL_ROOT))
382: parent = parent.getParent();
383: if (parent.isOfType(MODEL_ROOT))
384: return (IntroModelRoot) parent;
385: return null;
386: }
387:
388: /**
389: * Returns whether the element is among the specified element types. An
390: * example of an element mask is as follows:
391: * <p>
392: * <code>
393: * int elementMask = IntroElement.ABSTRACT_CONTAINER;
394: * int elementMask = IntroElement.DIV | IntroElement.DEFAULT_LINK;
395: * </code>
396: *
397: * @param elementMask
398: * element mask formed by bitwise OR of element type constants
399: * defined in this class.
400: * @return <code>true</code> if this element has a matching type, and
401: * <code>false</code> otherwise.
402: */
403: public boolean isOfType(int elementMask) {
404: return (getType() & elementMask) != 0;
405: }
406:
407: /**
408: * Returns whether the types of all the elements in the given array are
409: * among the specified element types. <br>
410: * An example of an element mask is as follows:
411: * <p>
412: * <code>
413: * int elementMask = IntroElement.DIV | IntroElement.DEFAULT_LINK;
414: * </code>
415: *
416: * @return <code>true</code> if all elements are of the right type, and
417: * <code>false</code> if the list is empty, or at least one
418: * element is not of the specified types.
419: */
420: public static final boolean allElementsAreOfType(
421: AbstractIntroElement[] elements, int elementMask) {
422: // if we have an empty list, no point going on.
423: if (elements.length == 0)
424: return false;
425:
426: for (int i = 0; i < elements.length; i++) {
427: AbstractIntroElement element = elements[i];
428: if (!element.isOfType(elementMask))
429: return false;
430: }
431: return true;
432: }
433:
434: /**
435: * Shallow copy. The design of cloning this model assumes that when a
436: * container is cloned, all its children must be cloned and reparented to
437: * it, hence one clone of this container object. This is why we have a
438: * shallow copy here.
439: */
440: public Object clone() throws CloneNotSupportedException {
441: return super .clone();
442: }
443:
444: public String getMixinStyle() {
445: return mixinStyle;
446: }
447:
448: public void setMixinStyle(String mixinStyle) {
449: this.mixinStyle = mixinStyle;
450: }
451:
452: }
|