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;
011:
012: import java.io.IOException;
013: import java.io.InputStream;
014: import java.net.URL;
015: import com.ibm.icu.text.MessageFormat;
016: import java.util.ArrayList;
017: import java.util.MissingResourceException;
018: import java.util.PropertyResourceBundle;
019:
020: import org.eclipse.core.runtime.IProduct;
021: import org.eclipse.core.runtime.Path;
022: import org.eclipse.core.runtime.Platform;
023: import org.eclipse.jface.resource.ImageDescriptor;
024: import org.eclipse.ui.branding.IProductConstants;
025:
026: /**
027: * A class that converts the strings returned by
028: * <code>org.eclipse.core.runtime.IProduct.getProperty</code> to the
029: * appropriate class. This implementation is tightly bound to the properties
030: * provided in IProductConstants. Clients adding their own properties could
031: * choose to subclass this.
032: *
033: * @see org.eclipse.ui.branding.IProductConstants
034: * @since 3.0
035: */
036: public class ProductProperties extends BrandingProperties implements
037: IProductConstants {
038:
039: private final IProduct product;
040:
041: private String appName;
042:
043: private String aboutText;
044:
045: private ImageDescriptor aboutImageDescriptor;
046:
047: private ImageDescriptor[] windowImageDescriptors;
048:
049: private URL welcomePageUrl;
050:
051: private String productName;
052:
053: private String productId;
054:
055: private static final String ABOUT_MAPPINGS = "$nl$/about.mappings"; //$NON-NLS-1$
056:
057: private static String[] systemPropertiesKeys = new String[0];
058: private static String[] mappings = loadMappings();
059:
060: private static String[] loadMappings() {
061: IProduct product = Platform.getProduct();
062: if (product == null) {
063: return new String[0];
064: }
065: URL location = Platform.find(product.getDefiningBundle(),
066: new Path(ABOUT_MAPPINGS));
067: PropertyResourceBundle bundle = null;
068: InputStream is;
069: if (location != null) {
070: is = null;
071: try {
072: is = location.openStream();
073: bundle = new PropertyResourceBundle(is);
074: } catch (IOException e) {
075: bundle = null;
076: } finally {
077: try {
078: if (is != null) {
079: is.close();
080: }
081: } catch (IOException e) {
082: // do nothing if we fail to close
083: }
084: }
085: }
086:
087: ArrayList mappingsList = new ArrayList();
088: if (bundle != null) {
089: boolean found = true;
090: int i = 0;
091: ArrayList systemPropertiesKeysList = new ArrayList();
092: while (found) {
093: try {
094: String nextString = bundle.getString(Integer
095: .toString(i));
096: int length = nextString.length();
097: /*
098: * Check if the mapping value is a system property, specified
099: * by '$' at the beginning and end of the string. If so, add
100: * the key to the systemPropertiesKeys array and insert array
101: * indices "{i}" to allow the string to be formatted again with
102: * the new system property values.
103: */
104: if (length > 2
105: && nextString.indexOf('$') == 0
106: && nextString.lastIndexOf('$') == length - 1) {
107: int newIndex = systemPropertiesKeysList.size();
108: systemPropertiesKeysList.add(nextString
109: .substring(1, length - 1));
110: nextString = "{" + newIndex + "}"; //$NON-NLS-1$ //$NON-NLS-2$
111: }
112: mappingsList.add(nextString);
113: } catch (MissingResourceException e) {
114: found = false;
115: }
116: i++;
117: }
118: systemPropertiesKeys = (String[]) systemPropertiesKeysList
119: .toArray(new String[systemPropertiesKeysList.size()]);
120: }
121: return (String[]) mappingsList.toArray(new String[mappingsList
122: .size()]);
123: }
124:
125: /**
126: * This instance will return properties from the given product. The properties are
127: * retrieved in a lazy fashion and cached for later retrieval.
128: * @param product must not be null
129: */
130: public ProductProperties(IProduct product) {
131: if (product == null) {
132: throw new IllegalArgumentException();
133: }
134: this .product = product;
135: }
136:
137: /**
138: * The application name, used to initialize the SWT Display. This
139: * value is distinct from the string displayed in the application
140: * title bar.
141: * <p>
142: * E.g., On motif, this can be used to set the name used for
143: * resource lookup.
144: * </p>
145: * @see org.eclipse.swt.widgets.Display#setAppName
146: */
147: public String getAppName() {
148: if (appName == null) {
149: appName = getAppName(product);
150: }
151: return appName;
152: }
153:
154: /**
155: * The text to show in an "about" dialog for this product.
156: * Products designed to run "headless" typically would not
157: * have such text.
158: */
159: public String getAboutText() {
160: if (aboutText == null) {
161: aboutText = getAboutText(product);
162: }
163: return aboutText;
164: }
165:
166: /**
167: * An image which can be shown in an "about" dialog for this
168: * product. Products designed to run "headless" typically would not
169: * have such an image.
170: * <p>
171: * A full-sized product image (no larger than 500x330 pixels) is
172: * shown without the "aboutText" blurb. A half-sized product image
173: * (no larger than 250x330 pixels) is shown with the "aboutText"
174: * blurb beside it.
175: */
176: public ImageDescriptor getAboutImage() {
177: if (aboutImageDescriptor == null) {
178: aboutImageDescriptor = getAboutImage(product);
179: }
180: return aboutImageDescriptor;
181: }
182:
183: /**
184: * An array of one or more images to be used for this product. The
185: * expectation is that the array will contain the same image rendered
186: * at different sizes (16x16 and 32x32).
187: * Products designed to run "headless" typically would not have such images.
188: * <p>
189: * If this property is given, then it supercedes <code>WINDOW_IMAGE</code>.
190: * </p>
191: */
192: public ImageDescriptor[] getWindowImages() {
193: if (windowImageDescriptors == null) {
194: windowImageDescriptors = getWindowImages(product);
195: }
196: return windowImageDescriptors;
197: }
198:
199: /**
200: * Location of the product's welcome page (special XML-based format), either
201: * a fully qualified valid URL or a path relative to the product's defining
202: * bundle. Products designed to run "headless" typically would not have such
203: * a page. Use of this property is discouraged in 3.0, the new
204: * org.eclipse.ui.intro extension point should be used instead.
205: */
206: public URL getWelcomePageUrl() {
207: if (welcomePageUrl == null) {
208: welcomePageUrl = getWelcomePageUrl(product);
209: }
210: return welcomePageUrl;
211: }
212:
213: /**
214: * Returns the product name or <code>null</code>.
215: * This is shown in the window title and the About action.
216: */
217: public String getProductName() {
218: if (productName == null) {
219: productName = getProductName(product);
220: }
221: return productName;
222: }
223:
224: /**
225: * Returns the id for the product or <code>null</code> if none.
226: */
227: public String getProductId() {
228: if (productId == null) {
229: productId = getProductId(product);
230: }
231: return productId;
232: }
233:
234: /**
235: * The application name, used to initialize the SWT Display. This
236: * value is distinct from the string displayed in the application
237: * title bar.
238: * <p>
239: * E.g., On motif, this can be used to set the name used for
240: * resource lookup.
241: * </p>
242: * <p>
243: * The returned value will have {n} values substituted based on the
244: * current product's mappings regardless of the given product argument.
245: * </p>
246: * @see org.eclipse.swt.widgets.Display#setAppName
247: */
248: public static String getAppName(IProduct product) {
249: String property = product.getProperty(APP_NAME);
250: if (property == null) {
251: return ""; //$NON-NLS-1$
252: }
253: if (property.indexOf('{') == -1) {
254: return property;
255: }
256: return MessageFormat.format(property, mappings);
257: }
258:
259: /**
260: * The text to show in an "about" dialog for this product.
261: * Products designed to run "headless" typically would not
262: * have such text.
263: * <p>
264: * The returned value will have {n} values substituted based on the
265: * current product's mappings regardless of the given product argument.
266: * </p>
267: */
268: public static String getAboutText(IProduct product) {
269: String property = product.getProperty(ABOUT_TEXT);
270: if (property == null) {
271: return ""; //$NON-NLS-1$
272: }
273: if (property.indexOf('{') == -1) {
274: return property;
275: }
276: property = MessageFormat.format(property, mappings);
277:
278: /*
279: * If there is still a "{" character, check if there are
280: * System properties in the systemPropertiesKeys array that
281: * need to be loaded.
282: */
283: if (property.indexOf('{') == -1) {
284: return property;
285: }
286:
287: if (systemPropertiesKeys.length == 0)
288: return property;
289:
290: /*
291: * Create a String array of the actual values to be mapped
292: * to the system properties keys.
293: */
294: String[] systemPropertiesMappings = new String[systemPropertiesKeys.length];
295: for (int i = 0; i < systemPropertiesKeys.length; i++) {
296: String systemProperty = systemPropertiesKeys[i];
297: // If system property is not set, insert an empty String
298: systemPropertiesMappings[i] = System.getProperty(
299: systemProperty, ""); //$NON-NLS-1$
300: }
301: /*
302: * Format string with the system properties values.
303: */
304: return MessageFormat.format(property, systemPropertiesMappings);
305: }
306:
307: /**
308: * An image which can be shown in an "about" dialog for this
309: * product. Products designed to run "headless" typically would not
310: * have such an image.
311: * <p>
312: * A full-sized product image (no larger than 500x330 pixels) is
313: * shown without the "aboutText" blurb. A half-sized product image
314: * (no larger than 250x330 pixels) is shown with the "aboutText"
315: * blurb beside it.
316: */
317: public static ImageDescriptor getAboutImage(IProduct product) {
318: return getImage(product.getProperty(ABOUT_IMAGE), product
319: .getDefiningBundle());
320: }
321:
322: /**
323: * An array of one or more images to be used for this product. The
324: * expectation is that the array will contain the same image rendered
325: * at different sizes (16x16 and 32x32).
326: * Products designed to run "headless" typically would not have such images.
327: * <p>
328: * If this property is given, then it supercedes <code>WINDOW_IMAGE</code>.
329: * </p>
330: */
331: public static ImageDescriptor[] getWindowImages(IProduct product) {
332: String property = product.getProperty(WINDOW_IMAGES);
333:
334: // for compatibility with pre-3.0 plugins that may still use WINDOW_IMAGE
335: if (property == null) {
336: property = product.getProperty(WINDOW_IMAGE);
337: }
338:
339: return getImages(property, product.getDefiningBundle());
340: }
341:
342: /**
343: * Location of the product's welcome page (special XML-based format), either
344: * a fully qualified valid URL or a path relative to the product's defining
345: * bundle. Products designed to run "headless" typically would not have such
346: * a page. Use of this property is discouraged in 3.0, the new
347: * org.eclipse.ui.intro extension point should be used instead.
348: */
349: public static URL getWelcomePageUrl(IProduct product) {
350: return getUrl(product.getProperty(WELCOME_PAGE), product
351: .getDefiningBundle());
352: }
353:
354: /**
355: * Returns the product name or <code>null</code>.
356: * This is shown in the window title and the About action.
357: */
358: public static String getProductName(IProduct product) {
359: return product.getName();
360: }
361:
362: /**
363: * Returns the id for the product.
364: */
365: public static String getProductId(IProduct product) {
366: return product.getId();
367: }
368: }
|