Source Code Cross Referenced for IntroModelRoot.java in  » IDE-Eclipse » ui » org » eclipse » ui » internal » intro » impl » model » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » ui » org.eclipse.ui.internal.intro.impl.model 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*******************************************************************************
002:         * Copyright (c) 2004, 2007 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 java.util.Enumeration;
013:        import java.util.Hashtable;
014:        import java.util.Vector;
015:
016:        import org.eclipse.core.runtime.CoreException;
017:        import org.eclipse.core.runtime.IConfigurationElement;
018:        import org.eclipse.core.runtime.IPath;
019:        import org.eclipse.core.runtime.ListenerList;
020:        import org.eclipse.core.runtime.Path;
021:        import org.eclipse.core.runtime.Platform;
022:        import org.eclipse.core.runtime.Preferences;
023:        import org.eclipse.core.runtime.SafeRunner;
024:        import org.eclipse.help.UAContentFilter;
025:        import org.eclipse.help.internal.UAElementFactory;
026:        import org.eclipse.jface.util.SafeRunnable;
027:        import org.eclipse.ui.IPropertyListener;
028:        import org.eclipse.ui.internal.intro.impl.IntroPlugin;
029:        import org.eclipse.ui.internal.intro.impl.model.loader.IntroContentParser;
030:        import org.eclipse.ui.internal.intro.impl.model.loader.ModelLoaderUtil;
031:        import org.eclipse.ui.internal.intro.impl.model.util.BundleUtil;
032:        import org.eclipse.ui.internal.intro.impl.model.util.ModelUtil;
033:        import org.eclipse.ui.internal.intro.impl.util.IntroEvaluationContext;
034:        import org.eclipse.ui.internal.intro.impl.util.Log;
035:        import org.eclipse.ui.internal.intro.impl.util.StringUtil;
036:        import org.eclipse.ui.intro.config.IntroConfigurer;
037:        import org.osgi.framework.Bundle;
038:        import org.w3c.dom.Document;
039:        import org.w3c.dom.Element;
040:        import org.w3c.dom.Node;
041:
042:        /**
043:         * The root class for the OOBE model. It loads the configuration into the
044:         * appropriate classes.
045:         * 
046:         * Model rules:
047:         * <ol>
048:         * <li>if an attribute is not included in the markup, its value will be null in
049:         * the model.</li>
050:         * <li>Resources in plugin.xml are not implicitly resolved against $nl$.
051:         * Resources in pages are implicitly resolved against $nl$
052:         * <li>the current page id is set silently when loading the model. You do not
053:         * need the event notification on model load.</li>
054:         * <li>Children of a given parent (ie: model root, page, or group) *must* have
055:         * distinctive IDs otherwise resolving includes and extensions may fail.</li>
056:         * <li>Containers have the concept of loading children and resolving children.
057:         * At the model root level, resolving children means resolving ALL extensions of
058:         * model. At the container level, resolving children means resolving includes.
059:         * </li>
060:         * <li>Extensions are resolved before includes at the container level to avoid
061:         * race conditions. eg: if a page includes a shared group and an extension
062:         * extends this shared group, you want the include to get the extended group and
063:         * not the original group.</li>
064:         * <li>Resolving extensions should not resolve includes. No need to load other
065:         * models when we dont have to. Plus, extensions can only reference anchors, and
066:         * so no need to resolve includes.</li>
067:         * <li>Extensions can not target containers *after* they are resolved. For
068:         * example, an extension can not target a shared group after it has been
069:         * included in a page. It can target the initial shared group as a path, but not
070:         * the group in the page as a path. Again this is because extensions extends
071:         * anchors that already have a path, not a resolved path.</li>
072:         * <li>Pages and shared groups that are contributed through extensions become
073:         * children of the atrget configuration, and so any includes they may have will
074:         * be resolved correctly.</li>
075:         * <li>An infinite loop can occur if page A includes from page B and page B in
076:         * turn includes from page A. ie: cyclic includes. For performnace, accept.
077:         * </li>
078:         * <li>When resolving includes, if the target is a container, it must be
079:         * resolved to resolve its includes correctly. Otherwise, included includes will
080:         * fail due to reparenting.</li>
081:         * <li>unresolved includes are left as children of the parent container.</li>
082:         * <li>Unresolved extensions are left as children of the targetted model.</li>
083:         * <li>For dynamic awarness, the model is nulled and then reloaded. However, we
084:         * need to preserve the presentation instance since the UI is already loaded.
085:         * This is done by reloading the model, and directly resetting the presentation
086:         * to what it was.</li>
087:         * <li>Model classes should not have DOM classes as instance vars, and if this
088:         * is a must, null the DOM class instance the minute you are done. This is
089:         * because you want the VM to garbage collect the DOM model. Keeping a reference
090:         * to the DOM model from the Intro model will prevent that.</li>
091:         * </ol>
092:         * <li>(since 3.0.2) several passes are used to resolve contributions to
093:         * anchors that themselves where contributed through an extension. Each time a
094:         * contribution is resolved, the model tries to resolve all unresolved
095:         * contribution, recursively.
096:         * </ul>
097:         */
098:        public class IntroModelRoot extends AbstractIntroContainer {
099:
100:            /**
101:             * Model constants that fire property change event when they are changed in
102:             * the model.
103:             */
104:            public static final int CURRENT_PAGE_PROPERTY_ID = 1;
105:
106:            private static final String ATT_CONTENT = "content"; //$NON-NLS-1$
107:            private static final String ATT_CONFIGURER = "configurer"; //$NON-NLS-1$
108:            private static final String VAR_THEME = "theme"; //$NON-NLS-1$
109:
110:            // False if there is no valid contribution to the
111:            // org.eclipse.ui.into.config extension point. Start off with true, and set
112:            // to false whenever something bad happens.
113:            private boolean hasValidConfig = true;
114:            private boolean isdynamicIntro;
115:            private IntroConfigurer configurer;
116:            private IntroTheme theme;
117:            private IntroPartPresentation introPartPresentation;
118:            private IntroHomePage homePage;
119:            private String currentPageId;
120:            private IntroHomePage standbyPage;
121:
122:            // the config extensions for this model.
123:            private IConfigurationElement[] configExtensionElements;
124:
125:            // maintain listener list for model changes.
126:            public ListenerList propChangeListeners = new ListenerList();
127:
128:            // a hashtable to hold all loaded DOMs until resolving all configExtensions
129:            // is done. Key is one extensionContent DOM element, while value is the
130:            // IConfigurationElement from where it was loaded. This is needed to extract
131:            // the base for the xml content file.
132:            private Hashtable unresolvedConfigExt = new Hashtable();
133:
134:            /**
135:             * Model root. Takes a configElement that represents <config>in the
136:             * plugin.xml markup AND all the extension contributed to this model through
137:             * the configExtension point.
138:             */
139:            public IntroModelRoot(IConfigurationElement configElement,
140:                    IConfigurationElement[] configExtensionElements) {
141:                // the config element that represents the correct model root.
142:                super (configElement);
143:                this .configExtensionElements = configExtensionElements;
144:
145:            }
146:
147:            public void loadModel() {
148:                getChildren();
149:            }
150:
151:            /**
152:             * Loads the full model. The children of a model root are the presentation,
153:             * followed by all pages, and all shared groups. Then if the model has
154:             * extension, its the unresolved container extensions, followed by all
155:             * extension pages and groups. The presentation is loaded from the
156:             * IConfiguration element representing the config. All else is loaded from
157:             * xml content file.
158:             * 
159:             */
160:            protected void loadChildren() {
161:                children = new Vector();
162:                if (Log.logInfo)
163:                    Log.info("Creating Intro plugin model...."); //$NON-NLS-1$
164:
165:                // load presentation first and create the model class for it. If there
166:                // is more than one presentation, load first one, and log rest.
167:                IConfigurationElement presentationElement = loadPresentation();
168:                if (presentationElement == null) {
169:                    // no presentations at all, exit.
170:                    setModelState(true, false, false);
171:                    Log
172:                            .warning("Could not find presentation element in intro config."); //$NON-NLS-1$
173:                    return;
174:                }
175:
176:                loadTheme();
177:                loadConfigurer();
178:
179:                introPartPresentation = new IntroPartPresentation(
180:                        presentationElement);
181:                children.add(introPartPresentation);
182:                // set parent.
183:                introPartPresentation.setParent(this );
184:
185:                // now load all children of the config. There should only be pages and
186:                // groups here. And order is not important. These elements are loaded
187:                // from the content file DOM.
188:                Document document = loadDOM(getCfgElement());
189:                if (document == null) {
190:                    // we failed to parse the content file. Intro Parser would have
191:                    // logged the fact. Parser would also have checked to see if the
192:                    // content file has the correct root tag.
193:                    setModelState(true, false, false);
194:                    return;
195:                }
196:
197:                // set base for this model.
198:                this .base = getBase(getCfgElement());
199:
200:                // now load content.
201:                loadPages(document, getBundle());
202:                loadSharedGroups(document, getBundle());
203:
204:                // Attributes of root page decide if we have a static or dynamic case.
205:                setModelState(true, true, getHomePage().isDynamic());
206:            }
207:
208:            /**
209:             * Sets the presentation to the given presentation. The model always has the
210:             * presentation as the first child, so use that fact. This method is used
211:             * for dynamic awarness to enable replacing the new presentation with the
212:             * existing one after a model refresh.
213:             * 
214:             * @param presentation
215:             */
216:            public void setPresentation(IntroPartPresentation presentation) {
217:                this .introPartPresentation = presentation;
218:                presentation.setParent(this );
219:                children.set(0, presentation);
220:            }
221:
222:            /**
223:             * Resolve contributions into this container's children.
224:             */
225:            protected void resolveChildren() {
226:                // now handle config extension.
227:                resolveConfigExtensions();
228:                resolved = true;
229:            }
230:
231:            private IConfigurationElement loadPresentation() {
232:                // If there is more than one presentation, load first one, and log
233:                // rest.
234:                IConfigurationElement[] presentationElements = getCfgElement()
235:                        .getChildren(IntroPartPresentation.TAG_PRESENTATION);
236:
237:                IConfigurationElement presentationElement = ModelLoaderUtil
238:                        .validateSingleContribution(presentationElements,
239:                                IntroPartPresentation.ATT_HOME_PAGE_ID);
240:                return presentationElement;
241:            }
242:
243:            private void loadConfigurer() {
244:                String cname = getCfgElement().getAttribute(ATT_CONFIGURER);
245:                if (cname != null) {
246:                    try {
247:                        Object obj = getCfgElement().createExecutableExtension(
248:                                ATT_CONFIGURER);
249:                        if (obj instanceof  IntroConfigurer)
250:                            configurer = (IntroConfigurer) obj;
251:                    } catch (CoreException e) {
252:                        Log.error("Error loading intro configurer", e); //$NON-NLS-1$
253:                    }
254:                }
255:            }
256:
257:            private void loadTheme() {
258:                Preferences pref = IntroPlugin.getDefault()
259:                        .getPluginPreferences();
260:                String pid = Platform.getProduct().getId();
261:                String themeId = pref.getString(pid + "_INTRO_THEME"); //$NON-NLS-1$
262:                if (themeId.length() == 0)
263:                    themeId = pref.getString("INTRO_THEME"); //$NON-NLS-1$
264:                IConfigurationElement[] elements = Platform
265:                        .getExtensionRegistry().getConfigurationElementsFor(
266:                                "org.eclipse.ui.intro.configExtension"); //$NON-NLS-1$
267:                IConfigurationElement themeElement = null;
268:                for (int i = 0; i < elements.length; i++) {
269:                    if (elements[i].getName().equals("theme")) { //$NON-NLS-1$
270:                        String id = elements[i].getAttribute("id"); //$NON-NLS-1$
271:                        if (themeId != null) {
272:                            if (id != null && themeId.equals(id)) {
273:                                // use this one
274:                                themeElement = elements[i];
275:                                break;
276:                            }
277:                        } else {
278:                            // see if this one is the default
279:                            String value = elements[i].getAttribute("default"); //$NON-NLS-1$
280:                            if (value != null && value.equalsIgnoreCase("true")) { //$NON-NLS-1$
281:                                themeElement = elements[i];
282:                                break;
283:                            }
284:                        }
285:                    }
286:                }
287:                if (themeElement != null) {
288:                    theme = new IntroTheme(themeElement);
289:                }
290:            }
291:
292:            /**
293:             * Loads all pages defined in this config from the xml content file.
294:             */
295:            private void loadPages(Document dom, Bundle bundle) {
296:                String homePageId = getPresentation().getHomePageId();
297:                String standbyPageId = getPresentation().getStandbyPageId();
298:                Element[] pages = ModelUtil.getElementsByTagName(dom,
299:                        AbstractIntroPage.TAG_PAGE);
300:                for (int i = 0; i < pages.length; i++) {
301:                    Element pageElement = pages[i];
302:                    if (pageElement.getAttribute(AbstractIntroIdElement.ATT_ID)
303:                            .equals(homePageId)) {
304:                        // Create the model class for the Root Page.
305:                        homePage = new IntroHomePage(pageElement, bundle, base);
306:                        homePage.setParent(this );
307:                        currentPageId = homePage.getId();
308:                        children.add(homePage);
309:                    } else if (pageElement.getAttribute(
310:                            AbstractIntroIdElement.ATT_ID)
311:                            .equals(standbyPageId)) {
312:                        // Create the model class for the standby Page.
313:                        standbyPage = new IntroHomePage(pageElement, bundle,
314:                                base);
315:                        standbyPage.setParent(this );
316:                        // signal that it is a standby page.
317:                        standbyPage.setStandbyPage(true);
318:                        children.add(standbyPage);
319:                    } else {
320:                        // Create the model class for an intro Page.
321:                        IntroPage page = new IntroPage(pageElement, bundle,
322:                                base);
323:                        page.setParent(this );
324:                        children.add(page);
325:                    }
326:                }
327:            }
328:
329:            /**
330:             * Loads all shared groups defined in this config, from the DOM.
331:             */
332:            private void loadSharedGroups(Document dom, Bundle bundle) {
333:                Element[] groups = ModelUtil.getElementsByTagName(dom,
334:                        IntroGroup.TAG_GROUP);
335:                for (int i = 0; i < groups.length; i++) {
336:                    IntroGroup group = new IntroGroup(groups[i], bundle, base);
337:                    group.setParent(this );
338:                    children.add(group);
339:                }
340:            }
341:
342:            /**
343:             * Handles all the configExtensions to this current model. Resolving
344:             * configExts means finding target anchor and inserting extension content at
345:             * target. Also, several passes are used to resolve as many extensions as
346:             * possible. This allows for resolving nested anchors (ie: anchors to
347:             * anchors in contributions).
348:             */
349:            private void resolveConfigExtensions() {
350:                for (int i = 0; i < configExtensionElements.length; i++)
351:                    resolveConfigExtension(configExtensionElements[i]);
352:
353:                // now add all unresolved extensions as model children and log fact.
354:                Enumeration keys = unresolvedConfigExt.keys();
355:                while (keys.hasMoreElements()) {
356:                    Element configExtensionElement = (Element) keys
357:                            .nextElement();
358:                    IConfigurationElement configExtConfigurationElement = (IConfigurationElement) unresolvedConfigExt
359:                            .get(configExtensionElement);
360:                    Bundle bundle = BundleUtil
361:                            .getBundleFromConfigurationElement(configExtConfigurationElement);
362:                    String base = getBase(configExtConfigurationElement);
363:                    children.add(new IntroExtensionContent(
364:                            configExtensionElement, bundle, base,
365:                            configExtConfigurationElement));
366:
367:                    // INTRO: fix log strings.
368:                    Log
369:                            .warning("Could not resolve the following configExtension: " //$NON-NLS-1$
370:                                    + ModelLoaderUtil.getLogString(bundle,
371:                                            configExtensionElement,
372:                                            IntroExtensionContent.ATT_PATH));
373:                }
374:            }
375:
376:            private void resolveConfigExtension(
377:                    IConfigurationElement configExtElement) {
378:                // This call will extract the parent folder if needed.
379:                Document dom = loadDOM(configExtElement);
380:                if (dom == null)
381:                    // we failed to parse the content file. Intro Parser would
382:                    // have logged the fact. Parser would also have checked to
383:                    // see if the content file has the correct root tag.
384:                    return;
385:                resolveConfigExtension(dom, configExtElement);
386:            }
387:
388:            private void resolveConfigExtension(Document dom,
389:                    IConfigurationElement configExtElement) {
390:
391:                // Find the target of this container extension, and add all its
392:                // children to target. Make sure to pass correct bundle and base to
393:                // propagate to all children.
394:                String base = getBase(configExtElement);
395:                Element extensionContentElement = loadExtensionContent(dom,
396:                        configExtElement, base);
397:                if (extensionContentElement == null)
398:                    // no extension content defined, ignore extension completely.
399:                    return;
400:
401:                if (extensionContentElement.hasAttribute("failed")) { //$NON-NLS-1$
402:                    // we failed to resolve this configExtension, because target
403:                    // could not be found or is not an anchor, add the extension to the
404:                    // list of unresolved configExtensions.
405:                    // INTRO: an extensionContent is used as a key, instead of the whole
406:                    // DOM. This is usefull if we need to support multiple extension
407:                    // contents in one file.
408:                    if (!unresolvedConfigExt
409:                            .containsKey(extensionContentElement))
410:                        unresolvedConfigExt.put(extensionContentElement,
411:                                configExtElement);
412:                    return;
413:                }
414:
415:                // We resolved a contribution. Now load all pages and shared groups
416:                // from this config extension. No point adding pages that will never
417:                // be referenced. Get the bundle from the extensions since they are
418:                // defined in other plugins.
419:                Bundle bundle = BundleUtil
420:                        .getBundleFromConfigurationElement(configExtElement);
421:
422:                Element[] pages = ModelUtil.getElementsByTagName(dom,
423:                        AbstractIntroPage.TAG_PAGE);
424:                for (int j = 0; j < pages.length; j++) {
425:                    // Create the model class for an intro Page.
426:                    IntroPage page = new IntroPage(pages[j], bundle, base);
427:                    page.setParent(this );
428:                    children.add(page);
429:                }
430:
431:                // load all shared groups from all configExtensions to this model.
432:                loadSharedGroups(dom, bundle);
433:
434:                // since we resolved a contribution, try resolving some of the
435:                // unresolved ones before going on.
436:                unresolvedConfigExt.remove(extensionContentElement);
437:                tryResolvingExtensions();
438:            }
439:
440:            private void tryResolvingExtensions() {
441:                Enumeration keys = unresolvedConfigExt.keys();
442:                while (keys.hasMoreElements()) {
443:                    Element extensionContentElement = (Element) keys
444:                            .nextElement();
445:                    resolveConfigExtension(extensionContentElement
446:                            .getOwnerDocument(),
447:                            (IConfigurationElement) unresolvedConfigExt
448:                                    .get(extensionContentElement));
449:                }
450:            }
451:
452:            /**
453:             * load the extension content of this configExtension into model classes,
454:             * and insert them at target. A config extension can have only ONE extension
455:             * content. This is because if the extension fails, we need to be able to
456:             * not include the page and group contributions as part of the model. If
457:             * extension content has XHTML content (ie: content attribute is defined) we
458:             * load extension DOM into target page dom.
459:             * 
460:             * note: the extension Element is returned to enable creating a child model
461:             * element on failure.
462:             * 
463:             * @param
464:             * @return
465:             */
466:            private Element loadExtensionContent(Document dom,
467:                    IConfigurationElement configExtElement, String base) {
468:
469:                // get the bundle from the extensions since they are defined in
470:                // other plugins.
471:                Bundle bundle = BundleUtil
472:                        .getBundleFromConfigurationElement(configExtElement);
473:
474:                Element[] extensionContents = ModelUtil.getElementsByTagName(
475:                        dom, IntroExtensionContent.TAG_CONTAINER_EXTENSION);
476:                if (extensionContents.length == 0) {
477:                    extensionContents = ModelUtil.getElementsByTagName(dom,
478:                            IntroExtensionContent.TAG_CONTAINER_REPLACE);
479:                }
480:
481:                // INTRO: change this. we may need to load more than one extension
482:                // content here.
483:                // There should only be one container extension. (ver3.0)
484:                Element extensionContentElement = ModelLoaderUtil
485:                        .validateSingleContribution(bundle, extensionContents,
486:                                IntroExtensionContent.ATT_PATH);
487:                if (extensionContentElement == null)
488:                    // no extensionContent defined.
489:                    return null;
490:                if (UAContentFilter.isFiltered(UAElementFactory
491:                        .newElement(extensionContentElement),
492:                        IntroEvaluationContext.getContext())) {
493:                    // whole extension was filtered
494:                    return null;
495:                }
496:
497:                // Create the model class for extension content.
498:                IntroExtensionContent extensionContent = new IntroExtensionContent(
499:                        extensionContentElement, bundle, base, configExtElement);
500:                boolean success = false;
501:                if (extensionContent.isXHTMLContent())
502:                    success = loadXHTMLExtensionContent(extensionContent);
503:                else
504:                    success = load3_0ExtensionContent(extensionContent);
505:
506:                if (success) {
507:                    if (extensionContentElement.hasAttribute("failed")) //$NON-NLS-1$
508:                        extensionContentElement.removeAttribute("failed"); //$NON-NLS-1$
509:                } else
510:                    extensionContentElement.setAttribute("failed", "true"); //$NON-NLS-1$ //$NON-NLS-2$
511:
512:                return extensionContentElement;
513:            }
514:
515:            /**
516:             * Insert the extension content into the target.
517:             * 
518:             * @param extensionContent
519:             * @return
520:             */
521:            private boolean loadXHTMLExtensionContent(
522:                    IntroExtensionContent extensionContent) {
523:                String path = extensionContent.getPath();
524:                // path must be pageId/anchorID in the case of anchors in XHTML pages.
525:                String[] pathSegments = StringUtil.split(path, "/"); //$NON-NLS-1$
526:                if (pathSegments.length != 2)
527:                    // path does not have correct format.
528:                    return false;
529:                AbstractIntroPage targetPage = (AbstractIntroPage) findChild(
530:                        pathSegments[0], ABSTRACT_PAGE);
531:                if (targetPage == null)
532:                    // target could not be found. Signal failure.
533:                    return false;
534:
535:                // Insert all children of this extension before the target element. Anchors need
536:                // to stay in DOM, even after all extensions have been resolved, to enable other
537:                // plugins to contribute. Find the target node.
538:                Document pageDom = targetPage.getDocument();
539:                Element targetElement = targetPage.findDomChild(
540:                        pathSegments[1], "*"); //$NON-NLS-1$
541:                if (targetElement == null)
542:                    return false;
543:
544:                // get extension content
545:                Element[] elements = extensionContent.getElements();
546:                // insert all children before anchor in page body.
547:                for (int i = 0; i < elements.length; i++) {
548:                    Node targetNode = pageDom.importNode(elements[i], true);
549:                    // update the src attribute of this node, if defined by w3
550:                    // specs.
551:
552:                    ModelUtil.updateResourceAttributes((Element) targetNode,
553:                            extensionContent);
554:                    targetElement.getParentNode().insertBefore(targetNode,
555:                            targetElement);
556:                }
557:
558:                if (extensionContent.getExtensionType() == IntroExtensionContent.TYPE_REPLACEMENT) {
559:                    targetElement.getParentNode().removeChild(targetElement);
560:                }
561:
562:                // now handle style inheritance.
563:                // Update the parent page styles. skip style if it is null;
564:                String[] styles = extensionContent.getStyles();
565:                if (styles != null) {
566:                    for (int i = 0; i < styles.length; i++)
567:                        ModelUtil.insertStyle(pageDom, styles[i]);
568:                }
569:
570:                return true;
571:
572:            }
573:
574:            /**
575:             * Insert the extension content (3.0 format) into the target.
576:             * 
577:             * @param extensionContent
578:             * @return
579:             */
580:            private boolean load3_0ExtensionContent(
581:                    IntroExtensionContent extensionContent) {
582:                String path = extensionContent.getPath();
583:                int type = extensionContent.getExtensionType();
584:                AbstractIntroElement target = findTarget(this , path,
585:                        extensionContent.getId());
586:                if (target != null
587:                        && target.isOfType(AbstractIntroElement.ANCHOR) == (type == IntroExtensionContent.TYPE_CONTRIBUTION)) {
588:                    // insert all children of this extension before the target element/anchor.
589:                    insertExtensionChildren(target, extensionContent,
590:                            extensionContent.getBundle(), extensionContent
591:                                    .getBase());
592:                    // anchors need to stay around to receive other contributions
593:                    if (type == IntroExtensionContent.TYPE_REPLACEMENT) {
594:                        AbstractIntroContainer parent = (AbstractIntroContainer) target
595:                                .getParent();
596:                        parent.removeChild(target);
597:                    }
598:                    handleExtensionStyleInheritence(target, extensionContent);
599:                    return true;
600:                }
601:                // appropriate target could not be found. Signal failure.
602:                return false;
603:            }
604:
605:            private void insertExtensionChildren(AbstractIntroElement target,
606:                    IntroExtensionContent extensionContent, Bundle bundle,
607:                    String base) {
608:                AbstractIntroContainer parent = (AbstractIntroContainer) target
609:                        .getParent();
610:                // insert the elements of the extension before the target
611:                String mixinStyle = getMixinStyle(extensionContent);
612:                Element[] children = extensionContent.getChildren();
613:                parent.insertElementsBefore(children, bundle, base, target,
614:                        mixinStyle);
615:            }
616:
617:            private String getMixinStyle(IntroExtensionContent extensionContent) {
618:                String path = extensionContent.getPath();
619:                if (!path.endsWith("/@")) //$NON-NLS-1$
620:                    return null;
621:                String pageId = path.substring(0, path.length() - 2);
622:                IntroModelRoot modelRoot = getModelRoot();
623:                if (modelRoot == null)
624:                    return null;
625:                IntroConfigurer configurer = modelRoot.getConfigurer();
626:                if (configurer == null)
627:                    return null;
628:                String extensionId = extensionContent.getId();
629:                // if this is a replace, take the mixin style as what is being replaced
630:                if (extensionContent.getExtensionType() == IntroExtensionContent.TYPE_REPLACEMENT) {
631:                    IPath ipath = new Path(extensionContent.getPath());
632:                    String s2 = ipath.segment(1);
633:                    if (s2 != null && s2.startsWith("@") && s2.length() > 1) { //$NON-NLS-1$
634:                        extensionId = s2.substring(1);
635:                    }
636:                }
637:                return configurer.getMixinStyle(pageId, extensionId);
638:            }
639:
640:            /**
641:             * Updates the inherited styles based on the style attribtes defined in the
642:             * configExtension. If we are extending a shared group do nothing. For
643:             * inherited alt-styles, we have to cache the bundle from which we inherited
644:             * the styles to be able to access resources in that plugin.
645:             * 
646:             * @param include
647:             * @param target
648:             */
649:            private void handleExtensionStyleInheritence(
650:                    AbstractIntroElement target, IntroExtensionContent extension) {
651:
652:                AbstractIntroContainer targetContainer = (AbstractIntroContainer) target
653:                        .getParent();
654:                if (targetContainer.getType() == AbstractIntroElement.GROUP
655:                        && targetContainer.getParent().getType() == AbstractIntroElement.MODEL_ROOT)
656:                    // if we are extending a shared group, defined under a config, we
657:                    // can not include styles.
658:                    return;
659:
660:                // Update the parent page styles. skip style if it is null;
661:                String[] styles = extension.getStyles();
662:                if (styles != null)
663:                    targetContainer.getParentPage().addStyles(styles);
664:
665:                // for alt-style cache bundle for loading resources.
666:                Hashtable altStyles = extension.getAltStyles();
667:                if (altStyles != null)
668:                    targetContainer.getParentPage().addAltStyles(altStyles);
669:            }
670:
671:            /**
672:             * Sets the model state based on all the model classes. Dynamic nature of
673:             * the model is always setto false when we fail to load model for any
674:             * reason.
675:             */
676:            private void setModelState(boolean loaded, boolean hasValidConfig,
677:                    boolean isdynamicIntro) {
678:                this .loaded = loaded;
679:                this .hasValidConfig = hasValidConfig;
680:                this .isdynamicIntro = isdynamicIntro;
681:            }
682:
683:            /**
684:             * Returns true if there is a valid contribution to
685:             * org.eclipse.ui.intro.config extension point, with a valid Presentation,
686:             * and pages.
687:             * 
688:             * @return Returns the hasValidConfig.
689:             */
690:            public boolean hasValidConfig() {
691:                return hasValidConfig;
692:            }
693:
694:            /**
695:             * @return Returns the introPartPresentation.
696:             */
697:            public IntroPartPresentation getPresentation() {
698:                return introPartPresentation;
699:            }
700:
701:            public IntroConfigurer getConfigurer() {
702:                return configurer;
703:            }
704:
705:            /**
706:             * @return Returns the rootPage.
707:             */
708:            public IntroHomePage getHomePage() {
709:                return homePage;
710:            }
711:
712:            /**
713:             * @return Returns the standby Page. May return null if standby page is not
714:             *         defined.
715:             */
716:            public IntroHomePage getStandbyPage() {
717:                return standbyPage;
718:            }
719:
720:            /**
721:             * @return all pages *excluding* the Home Page. If all pages are needed,
722:             *         call <code>(AbstractIntroPage[])
723:             *         getChildrenOfType(IntroElement.ABSTRACT_PAGE);</code>
724:             */
725:            public IntroPage[] getPages() {
726:                return (IntroPage[]) getChildrenOfType(AbstractIntroElement.PAGE);
727:            }
728:
729:            /**
730:             * @return Returns the isdynamicIntro.
731:             */
732:            public boolean isDynamic() {
733:                return isdynamicIntro;
734:            }
735:
736:            /**
737:             * @return Returns the currentPageId.
738:             */
739:            public String getCurrentPageId() {
740:                return currentPageId;
741:            }
742:
743:            /**
744:             * Sets the current page. If the model does not have a page with the passed
745:             * id, the message is logged, and the model retains its old current page.
746:             * 
747:             * @param currentPageId
748:             *            The currentPageId to set. *
749:             * @param fireEvent
750:             *            flag to indicate if event notification is needed.
751:             * @return true if the model has a page with the passed id, false otherwise.
752:             *         If the method fails, the current page remains the same as the
753:             *         last state.
754:             */
755:            public boolean setCurrentPageId(String pageId, boolean fireEvent) {
756:                if (pageId.equals(currentPageId))
757:                    // setting to the same page does nothing. Return true because we did
758:                    // not actually fail. just a no op.
759:                    return true;
760:
761:                AbstractIntroPage page = (AbstractIntroPage) findChild(pageId,
762:                        ABSTRACT_PAGE);
763:                if (page == null) {
764:                    // not a page. Test for root page.
765:                    if (!pageId.equals(homePage.getId())) {
766:                        // not a page nor the home page.
767:                        Log
768:                                .warning("Could not set current page to Intro page with id: " + pageId); //$NON-NLS-1$
769:                        return false;
770:                    }
771:                }
772:
773:                currentPageId = pageId;
774:                if (fireEvent)
775:                    firePropertyChange(CURRENT_PAGE_PROPERTY_ID);
776:                return true;
777:            }
778:
779:            public boolean setCurrentPageId(String pageId) {
780:                return setCurrentPageId(pageId, true);
781:            }
782:
783:            public void addPropertyListener(IPropertyListener l) {
784:                propChangeListeners.add(l);
785:            }
786:
787:            /**
788:             * Fires a property changed event. Made public because it can be used to
789:             * trigger a UI refresh.
790:             * 
791:             * @param propertyId
792:             *            the id of the property that changed
793:             */
794:            public void firePropertyChange(final int propertyId) {
795:                Object[] array = propChangeListeners.getListeners();
796:                for (int i = 0; i < array.length; i++) {
797:                    final IPropertyListener l = (IPropertyListener) array[i];
798:                    SafeRunner.run(new SafeRunnable() {
799:
800:                        public void run() {
801:                            l.propertyChanged(this , propertyId);
802:                        }
803:
804:                        public void handleException(Throwable e) {
805:                            super .handleException(e);
806:                            // If an unexpected exception happens, remove it
807:                            // to make sure the workbench keeps running.
808:                            propChangeListeners.remove(l);
809:                        }
810:                    });
811:                }
812:            }
813:
814:            public void removePropertyListener(IPropertyListener l) {
815:                propChangeListeners.remove(l);
816:            }
817:
818:            /**
819:             * @return Returns the currentPage. return null if page is not found, or if
820:             *         we are not in a dynamic intro mode.
821:             */
822:            public AbstractIntroPage getCurrentPage() {
823:                if (!isdynamicIntro)
824:                    return null;
825:
826:                AbstractIntroPage page = (AbstractIntroPage) findChild(
827:                        currentPageId, ABSTRACT_PAGE);
828:                if (page != null)
829:                    return page;
830:                // not a page. Test for root page.
831:                if (currentPageId.equals(homePage.getId()))
832:                    return homePage;
833:                // return null if page is not found.
834:                return null;
835:            }
836:
837:            /*
838:             * (non-Javadoc)
839:             * 
840:             * @see org.eclipse.ui.internal.intro.impl.model.IntroElement#getType()
841:             */
842:            public int getType() {
843:                return AbstractIntroElement.MODEL_ROOT;
844:            }
845:
846:            /**
847:             * Assumes that the passed config element has a "content" attribute. Reads
848:             * it and loads a DOM based on that attribute value. It does not explicitly
849:             * resolve the resource because this method only loads the introContent and
850:             * the configExt content files. ie: in plugin.xml. <br>
851:             * This method also sets the base attribute on the root element in the DOM
852:             * to enable resolving all resources relative to this DOM.
853:             * 
854:             * @return
855:             */
856:            protected Document loadDOM(IConfigurationElement cfgElement) {
857:                String content = cfgElement.getAttribute(ATT_CONTENT);
858:
859:                // To support jarring, extract parent folder of where the intro content
860:                // file is. It is expected that all intro content is in that one parent
861:                // folder. This works for both content files and configExtension content
862:                // files.
863:                Bundle domBundle = BundleUtil
864:                        .getBundleFromConfigurationElement(cfgElement);
865:                ModelUtil.ensureFileURLsExist(domBundle, content);
866:
867:                // Resolve.
868:                content = BundleUtil.getResourceLocation(content, cfgElement);
869:                Document document = new IntroContentParser(content)
870:                        .getDocument();
871:
872:                return document;
873:            }
874:
875:            private String getBase(IConfigurationElement configElement) {
876:                String content = configElement.getAttribute(ATT_CONTENT);
877:                return ModelUtil.getParentFolderToString(content);
878:            }
879:
880:            public String resolveVariables(String text) {
881:                if (text == null)
882:                    return null;
883:                if (text.indexOf('$') == -1)
884:                    return text;
885:                // resolve
886:                boolean inVariable = false;
887:                StringBuffer buf = new StringBuffer();
888:                int vindex = 0;
889:                for (int i = 0; i < text.length(); i++) {
890:                    char c = text.charAt(i);
891:                    if (c == '$') {
892:                        if (!inVariable) {
893:                            inVariable = true;
894:                            vindex = i + 1;
895:                            continue;
896:                        }
897:                        inVariable = false;
898:                        String variable = text.substring(vindex, i);
899:                        String value = getVariableValue(variable);
900:                        if (value == null)
901:                            value = "$" + variable + "$"; //$NON-NLS-1$ //$NON-NLS-2$
902:                        buf.append(value);
903:                        continue;
904:                    } else if (!inVariable)
905:                        buf.append(c);
906:                }
907:                return buf.toString();
908:            }
909:
910:            private String getVariableValue(String variable) {
911:                if (variable.equals(VAR_THEME)) {
912:                    if (theme != null)
913:                        return theme.getPath();
914:                }
915:                if (configurer != null)
916:                    return configurer.getVariable(variable);
917:                return null;
918:            }
919:
920:            public String resolvePath(String extensionId, String path) {
921:                if (configurer == null)
922:                    return null;
923:                return configurer.resolvePath(extensionId, path);
924:            }
925:
926:            public IntroTheme getTheme() {
927:                return theme;
928:            }
929:        }
w_ww__.__j___a_v__a__2___s__.___c__o__m__ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.