/******************************************************************************* * 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.swt; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Path; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.internal.intro.impl.model.AbstractBaseIntroElement; import org.eclipse.ui.internal.intro.impl.model.AbstractIntroContainer; import org.eclipse.ui.internal.intro.impl.model.AbstractIntroElement; import org.eclipse.ui.internal.intro.impl.model.AbstractIntroIdElement; import org.eclipse.ui.internal.intro.impl.model.AbstractIntroPage; import org.eclipse.ui.internal.intro.impl.model.IntroGroup; import org.eclipse.ui.internal.intro.impl.model.IntroImage; import org.eclipse.ui.internal.intro.impl.model.IntroLink; import org.eclipse.ui.internal.intro.impl.model.IntroModelRoot; import org.eclipse.ui.internal.intro.impl.model.IntroText; import org.eclipse.ui.internal.intro.impl.model.loader.ModelLoaderUtil; import org.eclipse.ui.internal.intro.impl.util.ImageUtil; import org.eclipse.ui.internal.intro.impl.util.Log; import org.osgi.framework.Bundle; public class PageStyleManager extends SharedStyleManager { private AbstractIntroPage page; private Map<Properties, StyleContext> altStyleContexts = new HashMap<>(); private IntroModelRoot root; /** * Constructor used when page styles need to be loaded. The plugin's bundle * is retrieved from the page model class. The default properties are * assumed to be the presentation shared properties. The inherrited * properties are properties that we got from included and extension styles. * * @param modelRoot */ public PageStyleManager(AbstractIntroPage page, Properties sharedProperties) { this.page = page; context = new StyleContext(); context.bundle = page.getBundle(); // honor shared-style. if (page.injectSharedStyle()) properties = new Properties(sharedProperties); else properties = new Properties(); String altStyle = page.getAltStyle(); if (altStyle != null) { load(properties, altStyle, context); } // AltStyles Hashtable has alt-styles as keys, the bundles as // values. Map<String, Bundle> altStyles = page.getAltStyles(); if (altStyles != null) { for (Entry<String, Bundle> entry : altStyles.entrySet()) { String style = entry.getKey(); Properties inheritedProperties = new Properties(); Bundle bundle = entry.getValue(); StyleContext sc = new StyleContext(); sc.bundle = bundle; load(inheritedProperties, style, sc); altStyleContexts.put(inheritedProperties, sc); } } // cache root root = (IntroModelRoot) page.getParentPage().getParent(); } // Override parent method to include alt-styles. Use implicit keys as well. @Override public String getProperty(String key) { return getProperty(key, true); } // Override parent method to include alt-styles. If useImplicit is true, we // try to resolve a key without its pageId. private String getProperty(String key, boolean useImplicitKey) { Properties aProperties = findPropertyOwner(key); String value = super.doGetProperty(aProperties, key); if (useImplicitKey) { if (value == null && page.getId() != null && key.startsWith(page.getId())) { // did not find the key as-is. Trim pageId and try again. String relativeKey = key.substring(page.getId().length()); return getProperty(relativeKey); } } return value; } /** * Finds a Properties that represents an inherited shared style, or this * current pages style. If the given key is not found, the pageId is trimmed * from the begining of the key, and the key is looked up again. If key does * not start with a pageId, lookup only the key as is. * * @param key * @return */ private Properties findPropertyOwner(String key) { // search for the key in this page's properties first. if (properties.containsKey(key)) return properties; // search inherited properties second. for (Properties aProperties : altStyleContexts.keySet()) { if (aProperties.containsKey(key)) return aProperties; } // we did not find the key. Return the local properties anyway. return properties; } /** * Finds the context from which this key was loaded. If the key is not from * an inherited alt style, then use the context corresponding to this page. * * @param key * @return */ @Override protected StyleContext getAssociatedContext(String key) { Properties aProperties = findPropertyOwner(key); StyleContext context = (StyleContext) altStyleContexts.get(aProperties); if (context != null) return context; return super.getAssociatedContext(key); } /* * For number of columns, do not return 1 as the default, to allow for * further processing. At the root page level, getting a 0 as ncolumns means * that the number of columns is the number of children. At the page level, * default is 1. */ public int getPageNumberOfColumns() { return getIntProperty(page, ".layout.ncolumns", 0); //$NON-NLS-1$ } public int getNumberOfColumns(IntroGroup group) { return getIntProperty(group, ".layout.ncolumns", 0); //$NON-NLS-1$ } public boolean getEqualWidth(IntroGroup group) { return getBooleanProperty(group, ".layout.equalWidth", false); //$NON-NLS-1$ } public int getPageVerticalSpacing() { return getIntProperty(page, ".layout.vspacing", 5); //$NON-NLS-1$ } public int getVerticalSpacing(IntroGroup group) { return getIntProperty(group, ".layout.vspacing", 5); //$NON-NLS-1$ } public int getPageHorizantalSpacing() { return getIntProperty(page, ".layout.hspacing", 5); //$NON-NLS-1$ } public int getHorizantalSpacing(IntroGroup group) { return getIntProperty(group, ".layout.hspacing", 5); //$NON-NLS-1$ } public int getColSpan(AbstractBaseIntroElement element) { return getIntProperty(element, ".layout.colspan", 1); //$NON-NLS-1$ } public int getRowSpan(AbstractBaseIntroElement element) { return getIntProperty(element, ".layout.rowspan", 1); //$NON-NLS-1$ } private int getIntProperty(AbstractBaseIntroElement element, String qualifier, int defaultValue) { StringBuffer buff = ModelLoaderUtil.createPathToElementKey(element, true); if (buff == null) return defaultValue; String key = buff.append(qualifier).toString(); return getIntProperty(key, defaultValue); } private boolean getBooleanProperty(AbstractBaseIntroElement element, String qualifier, boolean defaultValue) { StringBuffer buff = ModelLoaderUtil.createPathToElementKey(element, true); if (buff == null) return defaultValue; String key = buff.append(qualifier).toString(); return getBooleanProperty(key, defaultValue); } private int getIntProperty(String key, int defaulValue) { int intValue = defaulValue; String value = getProperty(key); if (value == null) return intValue; try { intValue = Integer.parseInt(value); } catch (NumberFormatException e) { Log.error("Failed to parse key: " + key + " as an integer.", e); //$NON-NLS-1$ //$NON-NLS-2$ } return intValue; } private boolean getBooleanProperty(String key, boolean defaultValue) { boolean booleanValue = defaultValue; String value = getProperty(key); if (value != null) booleanValue = value.equalsIgnoreCase("true"); //$NON-NLS-1$ return booleanValue; } /** * Finds the description text of the given group. Looks for the Text child * element whos id is specified as follows: * <p> * <pageId>. <path_to_group>.description-id= <id of child description Text * element> * </p> * If not found, use the default description style. * * Returns null if no default style found, or any id in path is null. * * @param group * @return */ public String getDescription(IntroGroup group) { StringBuffer buff = ModelLoaderUtil.createPathToElementKey(group, true); if (buff == null) return null; String key = buff.append(".description-id").toString(); //$NON-NLS-1$ return doGetDescription(group, key); } /** * Finds the description text of the associated page. Looks for the Text * child element whos id is specified as follows: * <p> * <pageId>.description-id= <id of child description Text element> * </p> * If not found, use the default description style. * * Returns null if no default style found, or any id in path is null. * * @param group * @return */ public String getPageDescription() { if (page.getId() == null) return null; String key = page.getId() + ".description-id"; //$NON-NLS-1$ return doGetDescription(page, key); } private String doGetDescription(AbstractIntroContainer parent, String key) { String path = getProperty(key); String description = null; if (path != null) description = findTextFromPath(parent, path); if (description != null) return description; return findTextFromStyleId(parent, getDescriptionStyleId()); } private String getDescriptionStyleId() { String key = "description-style-id"; //$NON-NLS-1$ return getProperty(key); } /** * Finds the subtitle of the associated page. Looks for the Text child * element whose id is specified as follows: * <p> * <pageId>.description-id= <id of child description Text element> * </p> * If not found, use the default description style. * * @param group * @return */ public String getPageSubTitle() { String key = page.getId() + ".subtitle-id"; //$NON-NLS-1$ String path = getProperty(key); String description = null; if (path != null) description = findTextFromPath(page, path); if (description != null) return description; return findTextFromStyleId(page, getPageSubTitleStyleId()); } private String getPageSubTitleStyleId() { String key = "subtitle-style-id"; //$NON-NLS-1$ return getProperty(key); } private String findTextFromPath(AbstractIntroContainer parent, String path) { AbstractIntroElement child = parent.findTarget(root, path); if (child != null && child.isOfType(AbstractIntroElement.TEXT)) { makeFiltered(child); return ((IntroText) child).getText(); } return null; } /** * Returns the first direct child text element with the given style-id. * * @return */ private String findTextFromStyleId(AbstractIntroContainer parent, String styleId) { IntroText[] allText = (IntroText[]) parent .getChildrenOfType(AbstractIntroElement.TEXT); for (int i = 0; i < allText.length; i++) { if (allText[i].getStyleId() == null) // not all elements have style id. continue; if (allText[i].getStyleId().equals(styleId)) { makeFiltered(allText[i]); return allText[i].getText(); } } return null; } /** * Util method to check model type, and filter model element out if it is of * the correct type. * * @param element */ private AbstractIntroElement makeFiltered(AbstractIntroElement element) { if (element.isOfType(AbstractIntroElement.BASE_ELEMENT)) ((AbstractBaseIntroElement) element).setFilterState(true); return element; } public boolean getShowLinkDescription() { String key = page.getId() + ".show-link-description"; //$NON-NLS-1$ String value = getProperty(key); if (value == null) { key = ".show-link-description"; //$NON-NLS-1$ value = getProperty(key); } if (value == null) value = "true"; //$NON-NLS-1$ return value.toLowerCase().equals("true"); //$NON-NLS-1$ } public boolean showHomePageNavigation() { String key = page.getId() + ".show-home-page-navigation"; //$NON-NLS-1$ String value = getProperty(key); if (value == null) { key = ".show-home-page-navigation"; //$NON-NLS-1$ value = getProperty(key); } if (value == null) value = "true"; //$NON-NLS-1$ return value.equalsIgnoreCase("true"); //$NON-NLS-1$ } public Color getColor(FormToolkit toolkit, AbstractBaseIntroElement element) { StringBuffer buff = ModelLoaderUtil.createPathToElementKey(element, true); if (buff == null) return null; String key = buff.append(".font.fg").toString(); //$NON-NLS-1$ return getColor(toolkit, key); } public Color getBackgrond(FormToolkit toolkit, AbstractBaseIntroElement element) { StringBuffer buff = ModelLoaderUtil.createPathToElementKey(element, true); if (buff == null) return null; String key = buff.append(".bg").toString(); //$NON-NLS-1$ return getColor(toolkit, key); } public boolean isBold(IntroText text) { String value = null; /* StringBuffer buff = ModelLoaderUtil.createPathToElementKey(text, true); if (buff != null) { String key = buff.append(".font.bold").toString(); //$NON-NLS-1$ value = getProperty(key); if (value != null) return value.toLowerCase().equals("true"); //$NON-NLS-1$ else { buff = ModelLoaderUtil.createPathToElementKey(text, true); } } */ value = getPropertyValue(text, ".font.bold"); //$NON-NLS-1$ if (value == null) { // bold is not specified by ID. Check to see if there is a style-id // specified for bold. value = getProperty("bold-style-id"); //$NON-NLS-1$ if (value != null && text.getStyleId() != null) return text.getStyleId().equals(value); } return false; } private String getPropertyValue(AbstractIntroIdElement element, String suffix) { StringBuffer buff = ModelLoaderUtil.createPathToElementKey(element, true); if (buff != null) { String key = buff.append(suffix).toString(); String value = getProperty(key); if (value != null) return value; // try the page.id key buff = ModelLoaderUtil.createPathToElementKey(element, false); if (buff!= null) { key = buff.append(suffix).toString(); value = getProperty(key); return value; } } return null; } public static Font getBannerFont() { return JFaceResources.getBannerFont(); } public static Font getHeaderFont() { return JFaceResources.getHeaderFont(); } /** * Retrieves an image for a link in a page. If not found, uses the page's * default link image. If still not found, uses the passed default. * * @param link * @param qualifier * @return */ public Image getImage(IntroLink link, String qualifier, String defaultKey) { // try the Id first String key = createImageByIdKey(page, link, qualifier); String value = getProperty(key, false); if (value==null) { key = createImageKey(page, link, qualifier); // special case where we have to handle this because extended code does // not go through getProperty() in this method. value = getProperty(key, false); } if (value == null && page.getId() != null && key.startsWith(page.getId())) // did not use the key as-is. Trim pageId and try again. key = key.substring(page.getId().length()); // pageKey can not become an implicit key. String pageKey = createImageKey(page, null, qualifier); return getImage(key, pageKey, defaultKey); } private String createImageKey(AbstractIntroPage page, IntroLink link, String qualifier) { StringBuffer buff = null; if (link != null) { buff = ModelLoaderUtil.createPathToElementKey(link, true); if (buff == null) return ""; //$NON-NLS-1$ } else { buff = new StringBuffer(); buff.append(page.getId()); } buff.append("."); //$NON-NLS-1$ buff.append(qualifier); return buff.toString(); } private String createImageByIdKey(AbstractIntroPage page, IntroLink link, String qualifier) { if (link==null || link.getId()==null) return ""; //$NON-NLS-1$ StringBuffer buff = new StringBuffer(); buff.append(page.getId()); buff.append("."); //$NON-NLS-1$ buff.append(link.getId()); buff.append("."); //$NON-NLS-1$ buff.append(qualifier); return buff.toString(); } public Image getImage(IntroImage introImage) { String imageLocation = introImage.getSrcAsIs(); StringBuffer buff = ModelLoaderUtil.createPathToElementKey(introImage, true); String key; if (buff == null) { key = "//" + imageLocation; //$NON-NLS-1$ } else { key = buff!=null?buff.toString():null; } if (ImageUtil.hasImage(key)) return ImageUtil.getImage(key); // key not already registered. if (buff != null) { StyleContext acontext = getAssociatedContext(key); if (acontext.inTheme) { ImageUtil.registerImage(key, acontext.path, imageLocation); return ImageUtil.getImage(key); } } Bundle bundle = introImage.getBundle(); if (FileLocator.find(bundle, new Path(imageLocation), null) == null) { return null; } ImageUtil.registerImage(key, bundle, imageLocation); return ImageUtil.getImage(key); } }