001: /*******************************************************************************
002: * Copyright (c) 2004, 2006 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.themes;
011:
012: import java.util.Collection;
013: import java.util.HashMap;
014: import java.util.HashSet;
015: import java.util.Map;
016: import java.util.ResourceBundle;
017:
018: import org.eclipse.core.runtime.IConfigurationElement;
019: import org.eclipse.core.runtime.IExtensionRegistry;
020: import org.eclipse.core.runtime.Platform;
021: import org.eclipse.jface.resource.StringConverter;
022: import org.eclipse.ui.PlatformUI;
023: import org.eclipse.ui.internal.WorkbenchPlugin;
024: import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
025: import org.eclipse.ui.internal.registry.RegistryReader;
026: import org.eclipse.ui.themes.IColorFactory;
027:
028: /**
029: * Registry reader for themes.
030: *
031: * @since 3.0
032: */
033: public class ThemeRegistryReader extends RegistryReader {
034:
035: /**
036: * The translation bundle in which to look up internationalized text.
037: */
038: private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
039: .getBundle(ThemeRegistryReader.class.getName());
040:
041: private Collection categoryDefinitions = new HashSet();
042:
043: private Collection colorDefinitions = new HashSet();
044:
045: private Collection fontDefinitions = new HashSet();
046:
047: private ThemeDescriptor themeDescriptor = null;
048:
049: private ThemeRegistry themeRegistry;
050:
051: private Map dataMap = new HashMap();
052:
053: /**
054: * ThemeRegistryReader constructor comment.
055: */
056: public ThemeRegistryReader() {
057: super ();
058: }
059:
060: /**
061: * Returns the category definitions.
062: *
063: * @return the category definitions
064: */
065: public Collection getCategoryDefinitions() {
066: return categoryDefinitions;
067: }
068:
069: /**
070: * Returns the color definitions.
071: *
072: * @return the color definitions
073: */
074: public Collection getColorDefinitions() {
075: return colorDefinitions;
076: }
077:
078: /**
079: * Returns the data map.
080: *
081: * @return the data map
082: */
083: public Map getData() {
084: return dataMap;
085: }
086:
087: /**
088: * Returns the font definitions.
089: *
090: * @return the font definitions
091: */
092: public Collection getFontDefinitions() {
093: return fontDefinitions;
094: }
095:
096: /**
097: * Read a category.
098: *
099: * @param element the element to read
100: * @return the new category
101: */
102: private ThemeElementCategory readCategory(
103: IConfigurationElement element) {
104: String name = element
105: .getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
106:
107: String id = element
108: .getAttribute(IWorkbenchRegistryConstants.ATT_ID);
109: String parentId = element
110: .getAttribute(IWorkbenchRegistryConstants.ATT_PARENT_ID);
111:
112: String description = null;
113:
114: IConfigurationElement[] descriptions = element
115: .getChildren(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
116:
117: if (descriptions.length > 0) {
118: description = descriptions[0].getValue();
119: }
120:
121: return new ThemeElementCategory(name, id, parentId,
122: description, element.getNamespace(), element);
123: }
124:
125: /**
126: * Read a color.
127: *
128: * @param element the element to read
129: * @return the new color
130: */
131: private ColorDefinition readColor(IConfigurationElement element) {
132: String name = element
133: .getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
134:
135: String id = element
136: .getAttribute(IWorkbenchRegistryConstants.ATT_ID);
137:
138: String defaultMapping = element
139: .getAttribute(IWorkbenchRegistryConstants.ATT_DEFAULTS_TO);
140:
141: String value = getPlatformSpecificColorValue(element
142: .getChildren(IWorkbenchRegistryConstants.TAG_COLORVALUE));
143:
144: if (value == null) {
145: value = getColorValue(element);
146: }
147:
148: if ((value == null && defaultMapping == null)
149: || (value != null && defaultMapping != null)) {
150: logError(element, RESOURCE_BUNDLE
151: .getString("Colors.badDefault")); //$NON-NLS-1$
152: return null;
153: }
154:
155: String categoryId = element
156: .getAttribute(IWorkbenchRegistryConstants.ATT_CATEGORY_ID);
157:
158: String description = null;
159: boolean isEditable = true;
160: String isEditableString = element
161: .getAttribute(IWorkbenchRegistryConstants.ATT_IS_EDITABLE);
162: if (isEditableString != null) {
163: isEditable = Boolean.valueOf(isEditableString)
164: .booleanValue();
165: }
166:
167: IConfigurationElement[] descriptions = element
168: .getChildren(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
169:
170: if (descriptions.length > 0) {
171: description = descriptions[0].getValue();
172: }
173:
174: return new ColorDefinition(name, id, defaultMapping, value,
175: categoryId, isEditable, description, element
176: .getDeclaringExtension().getNamespace());
177: }
178:
179: /**
180: * Gets the color value, either via the value attribute or from a color
181: * factory.
182: *
183: * @param element the element to check
184: * @return the color string
185: */
186: private String getColorValue(IConfigurationElement element) {
187: if (element == null) {
188: return null;
189: }
190:
191: String value = element
192: .getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
193: if (value == null) {
194: value = checkColorFactory(element);
195: }
196: return value;
197: }
198:
199: /**
200: * Check for platform specific color values. This will return the
201: * "best match" for the current platform.
202: *
203: * @param elements the elements to check
204: * @return the platform specific color, if any
205: */
206: private String getPlatformSpecificColorValue(
207: IConfigurationElement[] elements) {
208: return getColorValue(getBestPlatformMatch(elements));
209: }
210:
211: /**
212: * Get the element that has os/ws attributes that best match the current
213: * platform.
214: *
215: * @param elements the elements to check
216: * @return the best match, if any
217: */
218: private IConfigurationElement getBestPlatformMatch(
219: IConfigurationElement[] elements) {
220: IConfigurationElement match = null;
221:
222: String osname = Platform.getOS();
223: String wsname = Platform.getWS();
224:
225: for (int i = 0; i < elements.length; i++) {
226: IConfigurationElement element = elements[i];
227: String elementOs = element
228: .getAttribute(IWorkbenchRegistryConstants.ATT_OS);
229: String elementWs = element
230: .getAttribute(IWorkbenchRegistryConstants.ATT_WS);
231:
232: if (osname.equalsIgnoreCase(elementOs)) {
233: if (wsname.equalsIgnoreCase(elementWs)) {
234: // best possible match. Return
235: return element;
236: }
237: match = element;
238: } else if (wsname.equalsIgnoreCase(elementWs)) {
239: match = element;
240: }
241: }
242:
243: return match;
244: }
245:
246: /* (non-Javadoc)
247: * @see org.eclipse.ui.internal.registry.RegistryReader#readElement(org.eclipse.core.runtime.IConfigurationElement)
248: */
249: public boolean readElement(IConfigurationElement element) {
250: String elementName = element.getName();
251: if (themeDescriptor == null
252: && elementName
253: .equals(IWorkbenchRegistryConstants.TAG_COLORDEFINITION)) {
254: ColorDefinition definition = readColor(element);
255: if (definition != null) {
256: if (!colorDefinitions.contains(definition)) {
257: colorDefinitions.add(definition);
258: themeRegistry.add(definition);
259: }
260: }
261: return true;
262: } else if (themeDescriptor != null
263: && elementName
264: .equals(IWorkbenchRegistryConstants.TAG_COLOROVERRIDE)) {
265: ColorDefinition definition = readColor(element);
266: if (definition != null) {
267: themeDescriptor.add(definition);
268: }
269: return true;
270: } else if (themeDescriptor == null
271: && elementName
272: .equals(IWorkbenchRegistryConstants.TAG_FONTDEFINITION)) {
273: FontDefinition definition = readFont(element);
274: if (definition != null) {
275: if (!fontDefinitions.contains(definition)) {
276: fontDefinitions.add(definition);
277: themeRegistry.add(definition);
278: }
279: }
280: return true;
281: } else if (themeDescriptor != null
282: && elementName
283: .equals(IWorkbenchRegistryConstants.TAG_FONTOVERRIDE)) {
284: FontDefinition definition = readFont(element);
285: if (definition != null) {
286: themeDescriptor.add(definition);
287: }
288: return true;
289: } else if (themeDescriptor == null
290: && elementName
291: .equals(IWorkbenchRegistryConstants.TAG_CATEGORYDEFINITION)) {
292: ThemeElementCategory definition = readCategory(element);
293: if (definition != null) {
294: if (!categoryDefinitions.contains(definition)) {
295: categoryDefinitions.add(definition);
296: themeRegistry.add(definition);
297: }
298: }
299: return true;
300: } else if (element.getName().equals(
301: IWorkbenchRegistryConstants.TAG_THEME)) {
302: if (themeDescriptor != null) {
303: logError(element, RESOURCE_BUNDLE
304: .getString("Themes.badNesting")); //$NON-NLS-1$
305: } else {
306: themeDescriptor = readTheme(element);
307: if (themeDescriptor != null) {
308: readElementChildren(element);
309: themeDescriptor = null;
310: }
311: return true;
312: }
313: } else if (themeDescriptor != null
314: && elementName
315: .equals(IWorkbenchRegistryConstants.TAG_DESCRIPTION)) {
316: themeDescriptor.setDescription(element.getValue());
317: return true;
318: } else if (elementName
319: .equals(IWorkbenchRegistryConstants.TAG_DATA)) {
320: String name = element
321: .getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
322: String value = element
323: .getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
324: if (name == null || value == null) {
325: logError(element, RESOURCE_BUNDLE
326: .getString("Data.badData")); //$NON-NLS-1$
327: } else {
328: if (themeDescriptor != null) {
329: themeDescriptor.setData(name, value);
330: } else {
331: themeRegistry.setData(name, value);
332: if (!dataMap.containsKey(name)) {
333: dataMap.put(name, value);
334: }
335: }
336: }
337: return true;
338: } else if (elementName
339: .equals(IWorkbenchRegistryConstants.TAG_CATEGORYPRESENTATIONBINDING)) {
340: String categoryId = element
341: .getAttribute(IWorkbenchRegistryConstants.ATT_CATEGORY_ID);
342: String presentationId = element
343: .getAttribute(IWorkbenchRegistryConstants.ATT_PRESENTATIONID);
344: themeRegistry.addCategoryPresentationBinding(categoryId,
345: presentationId);
346: return true;
347: }
348:
349: return false;
350: }
351:
352: /**
353: * Read a font.
354: *
355: * @param element the element to read
356: * @return the new font
357: */
358: private FontDefinition readFont(IConfigurationElement element) {
359: String name = element
360: .getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
361:
362: String id = element
363: .getAttribute(IWorkbenchRegistryConstants.ATT_ID);
364:
365: String defaultMapping = element
366: .getAttribute(IWorkbenchRegistryConstants.ATT_DEFAULTS_TO);
367:
368: String value = getPlatformSpecificFontValue(element
369: .getChildren(IWorkbenchRegistryConstants.TAG_FONTVALUE));
370: if (value == null) {
371: value = element
372: .getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
373: }
374:
375: if (value != null && defaultMapping != null) {
376: logError(element, RESOURCE_BUNDLE
377: .getString("Fonts.badDefault")); //$NON-NLS-1$
378: return null;
379: }
380:
381: String categoryId = element
382: .getAttribute(IWorkbenchRegistryConstants.ATT_CATEGORY_ID);
383:
384: boolean isEditable = true;
385: String isEditableString = element
386: .getAttribute(IWorkbenchRegistryConstants.ATT_IS_EDITABLE);
387: if (isEditableString != null) {
388: isEditable = Boolean.valueOf(isEditableString)
389: .booleanValue();
390: }
391:
392: String description = null;
393:
394: IConfigurationElement[] descriptions = element
395: .getChildren(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
396:
397: if (descriptions.length > 0) {
398: description = descriptions[0].getValue();
399: }
400:
401: return new FontDefinition(name, id, defaultMapping, value,
402: categoryId, isEditable, description);
403: }
404:
405: /**
406: * Check for platform specific font values. This will return the
407: * "best match" for the current platform.
408: *
409: * @param elements the elements to check
410: * @return the platform specific font, if any
411: */
412: private String getPlatformSpecificFontValue(
413: IConfigurationElement[] elements) {
414: return getFontValue(getBestPlatformMatch(elements));
415: }
416:
417: /**
418: * Gets the font valu from the value attribute.
419: *
420: * @param element the element to check
421: * @return the font string
422: */
423: private String getFontValue(IConfigurationElement element) {
424: if (element == null) {
425: return null;
426: }
427:
428: return element
429: .getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
430: }
431:
432: /**
433: * Attempt to load the color value from the colorFactory attribute.
434: *
435: * @param element the element to load from
436: * @return the value, or null if it could not be obtained
437: */
438: private String checkColorFactory(IConfigurationElement element) {
439: String value = null;
440: if (element
441: .getAttribute(IWorkbenchRegistryConstants.ATT_COLORFACTORY) != null
442: || element
443: .getChildren(IWorkbenchRegistryConstants.ATT_COLORFACTORY).length > 0) {
444: try {
445: IColorFactory factory = (IColorFactory) element
446: .createExecutableExtension(IWorkbenchRegistryConstants.ATT_COLORFACTORY);
447: value = StringConverter.asString(factory.createColor());
448: } catch (Exception e) {
449: WorkbenchPlugin.log(RESOURCE_BUNDLE
450: .getString("Colors.badFactory"), //$NON-NLS-1$
451: WorkbenchPlugin.getStatus(e));
452: }
453: }
454: return value;
455: }
456:
457: /**
458: * Read a theme.
459: *
460: * @param element the element to read
461: * @return the new theme
462: */
463: protected ThemeDescriptor readTheme(IConfigurationElement element) {
464: ThemeDescriptor desc = null;
465:
466: String id = element.getAttribute(ThemeDescriptor.ATT_ID);
467: if (id == null) {
468: return null;
469: }
470: //see if the theme has already been created in another extension
471: desc = (ThemeDescriptor) themeRegistry.findTheme(id);
472: //if not, create it
473: if (desc == null) {
474: desc = new ThemeDescriptor(id);
475: themeRegistry.add(desc);
476: }
477: //set the name as applicable
478: desc.extractName(element);
479:
480: return desc;
481: }
482:
483: /**
484: * Read the theme extensions within a registry.
485: *
486: * @param in the registry to read
487: * @param out the registry to write to
488: */
489: public void readThemes(IExtensionRegistry in, ThemeRegistry out) {
490: // this does not seem to really ever be throwing an the exception
491: setRegistry(out);
492: readRegistry(in, PlatformUI.PLUGIN_ID,
493: IWorkbenchRegistryConstants.PL_THEMES);
494:
495: // support for old font definitions
496: readRegistry(in, PlatformUI.PLUGIN_ID,
497: IWorkbenchRegistryConstants.PL_FONT_DEFINITIONS);
498: }
499:
500: /**
501: * Set the output registry.
502: *
503: * @param out the output registry
504: */
505: public void setRegistry(ThemeRegistry out) {
506: themeRegistry = out;
507: }
508: }
|