1 11 package org.eclipse.ui.internal.intro.impl.model; 12 13 import java.util.Enumeration ; 14 import java.util.Hashtable ; 15 import java.util.Vector ; 16 17 import org.eclipse.core.runtime.CoreException; 18 import org.eclipse.core.runtime.IConfigurationElement; 19 import org.eclipse.core.runtime.IPath; 20 import org.eclipse.core.runtime.ListenerList; 21 import org.eclipse.core.runtime.Path; 22 import org.eclipse.core.runtime.Platform; 23 import org.eclipse.core.runtime.Preferences; 24 import org.eclipse.core.runtime.SafeRunner; 25 import org.eclipse.help.UAContentFilter; 26 import org.eclipse.help.internal.UAElementFactory; 27 import org.eclipse.jface.util.SafeRunnable; 28 import org.eclipse.ui.IPropertyListener; 29 import org.eclipse.ui.internal.intro.impl.IntroPlugin; 30 import org.eclipse.ui.internal.intro.impl.model.loader.IntroContentParser; 31 import org.eclipse.ui.internal.intro.impl.model.loader.ModelLoaderUtil; 32 import org.eclipse.ui.internal.intro.impl.model.util.BundleUtil; 33 import org.eclipse.ui.internal.intro.impl.model.util.ModelUtil; 34 import org.eclipse.ui.internal.intro.impl.util.IntroEvaluationContext; 35 import org.eclipse.ui.internal.intro.impl.util.Log; 36 import org.eclipse.ui.internal.intro.impl.util.StringUtil; 37 import org.eclipse.ui.intro.config.IntroConfigurer; 38 import org.osgi.framework.Bundle; 39 import org.w3c.dom.Document ; 40 import org.w3c.dom.Element ; 41 import org.w3c.dom.Node ; 42 43 99 public class IntroModelRoot extends AbstractIntroContainer { 100 101 105 public static final int CURRENT_PAGE_PROPERTY_ID = 1; 106 107 private static final String ATT_CONTENT = "content"; private static final String ATT_CONFIGURER = "configurer"; private static final String VAR_THEME = "theme"; 111 private boolean hasValidConfig = true; 115 private boolean isdynamicIntro; 116 private IntroConfigurer configurer; 117 private IntroTheme theme; 118 private IntroPartPresentation introPartPresentation; 119 private IntroHomePage homePage; 120 private String currentPageId; 121 private IntroHomePage standbyPage; 122 123 private IConfigurationElement[] configExtensionElements; 125 126 public ListenerList propChangeListeners = new ListenerList(); 128 129 private Hashtable unresolvedConfigExt = new Hashtable (); 134 135 136 141 public IntroModelRoot(IConfigurationElement configElement, 142 IConfigurationElement[] configExtensionElements) { 143 super(configElement); 145 this.configExtensionElements = configExtensionElements; 146 147 } 148 149 public void loadModel() { 150 getChildren(); 151 } 152 153 162 protected void loadChildren() { 163 children = new Vector (); 164 if (Log.logInfo) 165 Log.info("Creating Intro plugin model...."); 167 IConfigurationElement presentationElement = loadPresentation(); 170 if (presentationElement == null) { 171 setModelState(true, false, false); 173 Log.warning("Could not find presentation element in intro config."); return; 175 } 176 177 loadTheme(); 178 loadConfigurer(); 179 180 introPartPresentation = new IntroPartPresentation(presentationElement); 181 children.add(introPartPresentation); 182 introPartPresentation.setParent(this); 184 185 Document document = loadDOM(getCfgElement()); 189 if (document == null) { 190 setModelState(true, false, false); 194 return; 195 } 196 197 this.base = getBase(getCfgElement()); 199 200 loadPages(document, getBundle()); 202 loadSharedGroups(document, getBundle()); 203 204 setModelState(true, true, getHomePage().isDynamic()); 206 } 207 208 216 public void setPresentation(IntroPartPresentation presentation) { 217 this.introPartPresentation = presentation; 218 presentation.setParent(this); 219 children.set(0, presentation); 220 } 221 222 225 protected void resolveChildren() { 226 resolveConfigExtensions(); 228 resolved = true; 229 } 230 231 private IConfigurationElement loadPresentation() { 232 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(ATT_CONFIGURER); 248 if (obj instanceof IntroConfigurer) 249 configurer = (IntroConfigurer)obj; 250 } 251 catch (CoreException e) { 252 Log.error("Error loading intro configurer", e); } 254 } 255 } 256 257 private void loadTheme() { 258 Preferences pref = IntroPlugin.getDefault().getPluginPreferences(); 259 String pid = Platform.getProduct().getId(); 260 String themeId = pref.getString(pid+"_INTRO_THEME"); if (themeId.length()==0) 262 themeId = pref.getString("INTRO_THEME"); IConfigurationElement [] elements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.ui.intro.configExtension"); IConfigurationElement themeElement=null; 265 for (int i=0; i<elements.length; i++) { 266 if (elements[i].getName().equals("theme")) { String id = elements[i].getAttribute("id"); if (themeId!=null) { 269 if (id!=null && themeId.equals(id)) { 270 themeElement = elements[i]; 272 break; 273 } 274 } 275 else { 276 String value = elements[i].getAttribute("default"); if (value!=null && value.equalsIgnoreCase("true")) { themeElement = elements[i]; 280 break; 281 } 282 } 283 } 284 } 285 if (themeElement!=null) { 286 theme = new IntroTheme(themeElement); 287 } 288 } 289 290 293 private void loadPages(Document dom, Bundle bundle) { 294 String homePageId = getPresentation().getHomePageId(); 295 String standbyPageId = getPresentation().getStandbyPageId(); 296 Element[] pages = ModelUtil.getElementsByTagName(dom, 297 AbstractIntroPage.TAG_PAGE); 298 for (int i = 0; i < pages.length; i++) { 299 Element pageElement = pages[i]; 300 if (pageElement.getAttribute(AbstractIntroIdElement.ATT_ID).equals( 301 homePageId)) { 302 homePage = new IntroHomePage(pageElement, bundle, base); 304 homePage.setParent(this); 305 currentPageId = homePage.getId(); 306 children.add(homePage); 307 } else if (pageElement.getAttribute(AbstractIntroIdElement.ATT_ID) 308 .equals(standbyPageId)) { 309 standbyPage = new IntroHomePage(pageElement, bundle, base); 311 standbyPage.setParent(this); 312 standbyPage.setStandbyPage(true); 314 children.add(standbyPage); 315 } else { 316 IntroPage page = new IntroPage(pageElement, bundle, base); 318 page.setParent(this); 319 children.add(page); 320 } 321 } 322 } 323 324 327 private void loadSharedGroups(Document dom, Bundle bundle) { 328 Element[] groups = ModelUtil.getElementsByTagName(dom, 329 IntroGroup.TAG_GROUP); 330 for (int i = 0; i < groups.length; i++) { 331 IntroGroup group = new IntroGroup(groups[i], bundle, base); 332 group.setParent(this); 333 children.add(group); 334 } 335 } 336 337 344 private void resolveConfigExtensions() { 345 for (int i = 0; i < configExtensionElements.length; i++) 346 resolveConfigExtension(configExtensionElements[i]); 347 348 Enumeration keys = unresolvedConfigExt.keys(); 350 while (keys.hasMoreElements()) { 351 Element configExtensionElement = (Element) keys.nextElement(); 352 IConfigurationElement configExtConfigurationElement = (IConfigurationElement) unresolvedConfigExt 353 .get(configExtensionElement); 354 Bundle bundle = BundleUtil 355 .getBundleFromConfigurationElement(configExtConfigurationElement); 356 String base = getBase(configExtConfigurationElement); 357 children.add(new IntroExtensionContent(configExtensionElement, 358 bundle, base, configExtConfigurationElement)); 359 360 Log 362 .warning("Could not resolve the following configExtension: " + ModelLoaderUtil.getLogString(bundle, 364 configExtensionElement, 365 IntroExtensionContent.ATT_PATH)); 366 } 367 } 368 369 private void resolveConfigExtension(IConfigurationElement configExtElement) { 370 Document dom = loadDOM(configExtElement); 372 if (dom == null) 373 return; 377 resolveConfigExtension(dom, configExtElement); 378 } 379 380 381 private void resolveConfigExtension(Document dom, 382 IConfigurationElement configExtElement) { 383 384 String base = getBase(configExtElement); 388 Element extensionContentElement = loadExtensionContent(dom, 389 configExtElement, base); 390 if (extensionContentElement == null) 391 return; 393 394 if (extensionContentElement.hasAttribute("failed")) { if (!unresolvedConfigExt.containsKey(extensionContentElement)) 402 unresolvedConfigExt.put(extensionContentElement, 403 configExtElement); 404 return; 405 } 406 407 Bundle bundle = BundleUtil 412 .getBundleFromConfigurationElement(configExtElement); 413 414 Element[] pages = ModelUtil.getElementsByTagName(dom, 415 AbstractIntroPage.TAG_PAGE); 416 for (int j = 0; j < pages.length; j++) { 417 IntroPage page = new IntroPage(pages[j], bundle, base); 419 page.setParent(this); 420 children.add(page); 421 } 422 423 loadSharedGroups(dom, bundle); 425 426 unresolvedConfigExt.remove(extensionContentElement); 429 tryResolvingExtensions(); 430 } 431 432 433 private void tryResolvingExtensions() { 434 Enumeration keys = unresolvedConfigExt.keys(); 435 while (keys.hasMoreElements()) { 436 Element extensionContentElement = (Element) keys.nextElement(); 437 resolveConfigExtension(extensionContentElement.getOwnerDocument(), 438 (IConfigurationElement) unresolvedConfigExt 439 .get(extensionContentElement)); 440 } 441 } 442 443 444 458 private Element loadExtensionContent(Document dom, 459 IConfigurationElement configExtElement, String base) { 460 461 Bundle bundle = BundleUtil 464 .getBundleFromConfigurationElement(configExtElement); 465 466 Element[] extensionContents = ModelUtil.getElementsByTagName(dom, 467 IntroExtensionContent.TAG_CONTAINER_EXTENSION); 468 if (extensionContents.length == 0) { 469 extensionContents = ModelUtil.getElementsByTagName(dom, 470 IntroExtensionContent.TAG_CONTAINER_REPLACE); 471 } 472 473 Element extensionContentElement = ModelLoaderUtil 477 .validateSingleContribution(bundle, extensionContents, 478 IntroExtensionContent.ATT_PATH); 479 if (extensionContentElement == null) 480 return null; 482 if (UAContentFilter.isFiltered(UAElementFactory.newElement(extensionContentElement), IntroEvaluationContext.getContext())) { 483 return null; 485 } 486 487 IntroExtensionContent extensionContent = new IntroExtensionContent( 489 extensionContentElement, bundle, base, configExtElement); 490 boolean success = false; 491 if (extensionContent.isXHTMLContent()) 492 success = loadXHTMLExtensionContent(extensionContent); 493 else 494 success = load3_0ExtensionContent(extensionContent); 495 496 if (success) { 497 if (extensionContentElement.hasAttribute("failed")) extensionContentElement.removeAttribute("failed"); } else 500 extensionContentElement.setAttribute("failed", "true"); 502 return extensionContentElement; 503 } 504 505 506 507 513 private boolean loadXHTMLExtensionContent( 514 IntroExtensionContent extensionContent) { 515 String path = extensionContent.getPath(); 516 String [] pathSegments = StringUtil.split(path, "/"); if (pathSegments.length != 2) 519 return false; 521 AbstractIntroPage targetPage = (AbstractIntroPage) findChild( 522 pathSegments[0], ABSTRACT_PAGE); 523 if (targetPage == null) 524 return false; 526 527 Document pageDom = targetPage.getDocument(); 531 Element targetElement = targetPage.findDomChild(pathSegments[1], "*"); if (targetElement == null) 533 return false; 534 535 Element[] elements = extensionContent.getElements(); 537 for (int i = 0; i < elements.length; i++) { 539 Node targetNode = pageDom.importNode(elements[i], true); 540 543 ModelUtil.updateResourceAttributes((Element) targetNode, 544 extensionContent); 545 targetElement.getParentNode().insertBefore(targetNode, targetElement); 546 } 547 548 if (extensionContent.getExtensionType() == IntroExtensionContent.TYPE_REPLACEMENT) { 549 targetElement.getParentNode().removeChild(targetElement); 550 } 551 552 String [] styles = extensionContent.getStyles(); 555 if (styles != null) { 556 for (int i = 0; i < styles.length; i++) 557 ModelUtil.insertStyle(pageDom, styles[i]); 558 } 559 560 return true; 561 562 } 563 564 565 566 572 private boolean load3_0ExtensionContent(IntroExtensionContent extensionContent) { 573 String path = extensionContent.getPath(); 574 int type = extensionContent.getExtensionType(); 575 AbstractIntroElement target = findTarget(this, path, extensionContent.getId()); 576 if (target != null && target.isOfType(AbstractIntroElement.ANCHOR) == (type == IntroExtensionContent.TYPE_CONTRIBUTION)) { 577 insertExtensionChildren(target, extensionContent, extensionContent.getBundle(), extensionContent.getBase()); 579 if (type == IntroExtensionContent.TYPE_REPLACEMENT) { 581 AbstractIntroContainer parent = (AbstractIntroContainer)target.getParent(); 582 parent.removeChild(target); 583 } 584 handleExtensionStyleInheritence(target, extensionContent); 585 return true; 586 } 587 return false; 589 } 590 591 private void insertExtensionChildren(AbstractIntroElement target, 592 IntroExtensionContent extensionContent, Bundle bundle, String base) { 593 AbstractIntroContainer parent = (AbstractIntroContainer)target.getParent(); 594 String mixinStyle = getMixinStyle(extensionContent); 596 Element [] children = extensionContent.getChildren(); 597 parent.insertElementsBefore(children, bundle, base, target, mixinStyle); 598 } 599 600 private String getMixinStyle(IntroExtensionContent extensionContent) { 601 String path = extensionContent.getPath(); 602 if (!path.endsWith("/@")) return null; 604 String pageId = path.substring(0, path.length()-2); 605 IntroModelRoot modelRoot = getModelRoot(); 606 if (modelRoot==null) 607 return null; 608 IntroConfigurer configurer = modelRoot.getConfigurer(); 609 if (configurer==null) 610 return null; 611 String extensionId = extensionContent.getId(); 612 if (extensionContent.getExtensionType() == IntroExtensionContent.TYPE_REPLACEMENT) { 614 IPath ipath = new Path(extensionContent.getPath()); 615 String s2 = ipath.segment(1); 616 if (s2 != null && s2.startsWith("@") && s2.length() > 1) { extensionId = s2.substring(1); 618 } 619 } 620 return configurer.getMixinStyle(pageId, extensionId); 621 } 622 623 624 633 private void handleExtensionStyleInheritence(AbstractIntroElement target, 634 IntroExtensionContent extension) { 635 636 AbstractIntroContainer targetContainer = (AbstractIntroContainer)target.getParent(); 637 if (targetContainer.getType() == AbstractIntroElement.GROUP 638 && targetContainer.getParent().getType() == AbstractIntroElement.MODEL_ROOT) 639 return; 642 643 String [] styles = extension.getStyles(); 645 if (styles != null) 646 targetContainer.getParentPage().addStyles(styles); 647 648 Hashtable altStyles = extension.getAltStyles(); 650 if (altStyles != null) 651 targetContainer.getParentPage().addAltStyles(altStyles); 652 } 653 654 659 private void setModelState(boolean loaded, boolean hasValidConfig, 660 boolean isdynamicIntro) { 661 this.loaded = loaded; 662 this.hasValidConfig = hasValidConfig; 663 this.isdynamicIntro = isdynamicIntro; 664 } 665 666 673 public boolean hasValidConfig() { 674 return hasValidConfig; 675 } 676 677 680 public IntroPartPresentation getPresentation() { 681 return introPartPresentation; 682 } 683 684 public IntroConfigurer getConfigurer() { 685 return configurer; 686 } 687 688 691 public IntroHomePage getHomePage() { 692 return homePage; 693 } 694 695 699 public IntroHomePage getStandbyPage() { 700 return standbyPage; 701 } 702 703 708 public IntroPage[] getPages() { 709 return (IntroPage[]) getChildrenOfType(AbstractIntroElement.PAGE); 710 } 711 712 715 public boolean isDynamic() { 716 return isdynamicIntro; 717 } 718 719 722 public String getCurrentPageId() { 723 return currentPageId; 724 } 725 726 727 739 public boolean setCurrentPageId(String pageId, boolean fireEvent) { 740 if (pageId.equals(currentPageId)) 741 return true; 744 745 AbstractIntroPage page = (AbstractIntroPage) findChild(pageId, 746 ABSTRACT_PAGE); 747 if (page == null) { 748 if (!pageId.equals(homePage.getId())) { 750 Log 752 .warning("Could not set current page to Intro page with id: " + pageId); return false; 754 } 755 } 756 757 currentPageId = pageId; 758 if (fireEvent) 759 firePropertyChange(CURRENT_PAGE_PROPERTY_ID); 760 return true; 761 } 762 763 public boolean setCurrentPageId(String pageId) { 764 return setCurrentPageId(pageId, true); 765 } 766 767 public void addPropertyListener(IPropertyListener l) { 768 propChangeListeners.add(l); 769 } 770 771 778 public void firePropertyChange(final int propertyId) { 779 Object [] array = propChangeListeners.getListeners(); 780 for (int i = 0; i < array.length; i++) { 781 final IPropertyListener l = (IPropertyListener) array[i]; 782 SafeRunner.run(new SafeRunnable() { 783 784 public void run() { 785 l.propertyChanged(this, propertyId); 786 } 787 788 public void handleException(Throwable e) { 789 super.handleException(e); 790 propChangeListeners.remove(l); 793 } 794 }); 795 } 796 } 797 798 public void removePropertyListener(IPropertyListener l) { 799 propChangeListeners.remove(l); 800 } 801 802 806 public AbstractIntroPage getCurrentPage() { 807 if (!isdynamicIntro) 808 return null; 809 810 AbstractIntroPage page = (AbstractIntroPage) findChild(currentPageId, 811 ABSTRACT_PAGE); 812 if (page != null) 813 return page; 814 if (currentPageId.equals(homePage.getId())) 816 return homePage; 817 return null; 819 } 820 821 826 public int getType() { 827 return AbstractIntroElement.MODEL_ROOT; 828 } 829 830 831 841 protected Document loadDOM(IConfigurationElement cfgElement) { 842 String content = cfgElement.getAttribute(ATT_CONTENT); 843 844 Bundle domBundle = BundleUtil 849 .getBundleFromConfigurationElement(cfgElement); 850 ModelUtil.ensureFileURLsExist(domBundle, content); 851 852 content = BundleUtil.getResourceLocation(content, cfgElement); 854 Document document = new IntroContentParser(content).getDocument(); 855 856 return document; 857 } 858 859 860 private String getBase(IConfigurationElement configElement) { 861 String content = configElement.getAttribute(ATT_CONTENT); 862 return ModelUtil.getParentFolderToString(content); 863 } 864 865 public String resolveVariables(String text) { 866 if (text==null) return null; 867 if (text.indexOf('$')== -1) 868 return text; 869 boolean inVariable=false; 871 StringBuffer buf = new StringBuffer (); 872 int vindex=0; 873 for (int i=0; i<text.length(); i++) { 874 char c = text.charAt(i); 875 if (c=='$') { 876 if (!inVariable) { 877 inVariable=true; 878 vindex=i+1; 879 continue; 880 } 881 inVariable=false; 882 String variable=text.substring(vindex, i); 883 String value = getVariableValue(variable); 884 if (value==null) 885 value = "$"+variable+"$"; buf.append(value); 887 continue; 888 } 889 else if (!inVariable) 890 buf.append(c); 891 } 892 return buf.toString(); 893 } 894 895 private String getVariableValue(String variable) { 896 if (variable.equals(VAR_THEME)) { 897 if (theme!=null) 898 return theme.getPath(); 899 } 900 if (configurer!=null) 901 return configurer.getVariable(variable); 902 return null; 903 } 904 905 public String resolvePath(String extensionId, String path) { 906 if (configurer==null) return null; 907 return configurer.resolvePath(extensionId, path); 908 } 909 910 911 public IntroTheme getTheme() { 912 return theme; 913 } 914 } | Popular Tags |