blob: 31d0baa24e6c3ec45124700a43aa3addded70ef9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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 = 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$
StringBuilder buff = new StringBuilder();
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);
}
}