0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.ui.internal.registry;
0011:
0012: import java.io.BufferedReader;
0013: import java.io.FileInputStream;
0014: import java.io.IOException;
0015: import java.io.InputStreamReader;
0016: import java.io.Reader;
0017: import java.io.StringReader;
0018: import java.io.StringWriter;
0019: import java.io.Writer;
0020: import java.util.ArrayList;
0021: import java.util.Arrays;
0022: import java.util.Collection;
0023: import java.util.Collections;
0024: import java.util.Comparator;
0025: import java.util.HashMap;
0026: import java.util.Iterator;
0027: import java.util.List;
0028: import java.util.Map;
0029: import java.util.StringTokenizer;
0030:
0031: import org.eclipse.core.commands.common.EventManager;
0032: import org.eclipse.core.runtime.IConfigurationElement;
0033: import org.eclipse.core.runtime.IExtension;
0034: import org.eclipse.core.runtime.IExtensionPoint;
0035: import org.eclipse.core.runtime.IPath;
0036: import org.eclipse.core.runtime.Platform;
0037: import org.eclipse.core.runtime.content.IContentType;
0038: import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
0039: import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
0040: import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
0041: import org.eclipse.jface.dialogs.ErrorDialog;
0042: import org.eclipse.jface.dialogs.MessageDialog;
0043: import org.eclipse.jface.preference.IPreferenceStore;
0044: import org.eclipse.jface.resource.ImageDescriptor;
0045: import org.eclipse.jface.util.SafeRunnable;
0046: import org.eclipse.swt.program.Program;
0047: import org.eclipse.swt.widgets.Shell;
0048: import org.eclipse.ui.IEditorDescriptor;
0049: import org.eclipse.ui.IEditorRegistry;
0050: import org.eclipse.ui.IFileEditorMapping;
0051: import org.eclipse.ui.IMemento;
0052: import org.eclipse.ui.IPropertyListener;
0053: import org.eclipse.ui.ISharedImages;
0054: import org.eclipse.ui.PlatformUI;
0055: import org.eclipse.ui.WorkbenchException;
0056: import org.eclipse.ui.XMLMemento;
0057: import org.eclipse.ui.activities.WorkbenchActivityHelper;
0058: import org.eclipse.ui.internal.IPreferenceConstants;
0059: import org.eclipse.ui.internal.IWorkbenchConstants;
0060: import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
0061: import org.eclipse.ui.internal.WorkbenchImages;
0062: import org.eclipse.ui.internal.WorkbenchMessages;
0063: import org.eclipse.ui.internal.WorkbenchPlugin;
0064: import org.eclipse.ui.internal.editorsupport.ComponentSupport;
0065: import org.eclipse.ui.internal.misc.ExternalProgramImageDescriptor;
0066: import org.eclipse.ui.internal.misc.ProgramImageDescriptor;
0067: import org.eclipse.ui.internal.util.Util;
0068:
0069: import com.ibm.icu.text.Collator;
0070:
0071: /**
0072: * Provides access to the collection of defined editors for resource types.
0073: */
0074: public class EditorRegistry extends EventManager implements
0075: IEditorRegistry, IExtensionChangeHandler {
0076:
0077: private final static IEditorDescriptor[] EMPTY = new IEditorDescriptor[0];
0078:
0079: class RelatedRegistry {
0080:
0081: /**
0082: * Return the objects related to the type.
0083: *
0084: * @param type
0085: * @return the objects related to the type
0086: */
0087: public IEditorDescriptor[] getRelatedObjects(IContentType type) {
0088: IEditorDescriptor[] relatedObjects = (IEditorDescriptor[]) contentTypeToEditorMappings
0089: .get(type);
0090: if (relatedObjects == null) {
0091: return EMPTY;
0092: }
0093: return relatedObjects;
0094: }
0095:
0096: /**
0097: * Return the objects related to the filename
0098: * @param fileName
0099: * @return the objects related to the filename
0100: */
0101: public IEditorDescriptor[] getRelatedObjects(String fileName) {
0102: IFileEditorMapping mapping = getMappingFor(fileName);
0103: if (mapping == null) {
0104: return EMPTY;
0105: }
0106:
0107: return mapping.getEditors();
0108: }
0109:
0110: }
0111:
0112: private Map contentTypeToEditorMappings = new HashMap();
0113:
0114: /*
0115: * Cached images - these include images from registered editors (via
0116: * plugins) and others hence this table is not one to one with the mappings
0117: * table. It is in fact a superset of the keys one would find in
0118: * typeEditorMappings
0119: */
0120: private Map extensionImages = new HashMap();
0121:
0122: /**
0123: * Vector of EditorDescriptor - all the editors loaded from plugin files.
0124: * The list is kept in order to be able to show in the editor selection
0125: * dialog of the resource associations page. This list is sorted based on the
0126: * human readable label of the editor descriptor.
0127: *
0128: * @see #comparer
0129: */
0130: private List sortedEditorsFromPlugins = new ArrayList();
0131:
0132: // Map of EditorDescriptor - map editor id to editor.
0133: private Map mapIDtoEditor = initialIdToEditorMap(10);
0134:
0135: // Map of FileEditorMapping (extension to FileEditorMapping)
0136: private EditorMap typeEditorMappings;
0137:
0138: /*
0139: * Compares the labels from two IEditorDescriptor objects
0140: */
0141: private static final Comparator comparer = new Comparator() {
0142: private Collator collator = Collator.getInstance();
0143:
0144: public int compare(Object arg0, Object arg1) {
0145: String s1 = ((IEditorDescriptor) arg0).getLabel();
0146: String s2 = ((IEditorDescriptor) arg1).getLabel();
0147: return collator.compare(s1, s2);
0148: }
0149: };
0150:
0151: private RelatedRegistry relatedRegistry;
0152:
0153: public static final String EMPTY_EDITOR_ID = "org.eclipse.ui.internal.emptyEditorTab"; //$NON-NLS-1$
0154:
0155: /**
0156: * Return an instance of the receiver. Adds listeners into the extension
0157: * registry for dynamic UI purposes.
0158: */
0159: public EditorRegistry() {
0160: super ();
0161: initializeFromStorage();
0162: IExtensionTracker tracker = PlatformUI.getWorkbench()
0163: .getExtensionTracker();
0164: tracker.registerHandler(this , ExtensionTracker
0165: .createExtensionPointFilter(getExtensionPointFilter()));
0166: relatedRegistry = new RelatedRegistry();
0167: }
0168:
0169: /**
0170: * Add an editor for the given extensions with the specified (possibly null)
0171: * extended type. The editor is being registered from a plugin
0172: *
0173: * @param editor
0174: * The description of the editor (as obtained from the plugin
0175: * file and built by the registry reader)
0176: * @param extensions
0177: * Collection of file extensions the editor applies to
0178: * @param filenames
0179: * Collection of filenames the editor applies to
0180: * @param contentTypeVector
0181: * @param bDefault
0182: * Indicates whether the editor should be made the default editor
0183: * and hence appear first inside a FileEditorMapping
0184: *
0185: * This method is not API and should not be called outside the workbench
0186: * code.
0187: */
0188: public void addEditorFromPlugin(EditorDescriptor editor,
0189: List extensions, List filenames, List contentTypeVector,
0190: boolean bDefault) {
0191:
0192: PlatformUI.getWorkbench().getExtensionTracker().registerObject(
0193: editor.getConfigurationElement()
0194: .getDeclaringExtension(), editor,
0195: IExtensionTracker.REF_WEAK);
0196: // record it in our quick reference list
0197: sortedEditorsFromPlugins.add(editor);
0198:
0199: // add it to the table of mappings
0200: Iterator itr = extensions.iterator();
0201: while (itr.hasNext()) {
0202: String fileExtension = (String) itr.next();
0203:
0204: if (fileExtension != null && fileExtension.length() > 0) {
0205: FileEditorMapping mapping = getMappingFor("*." + fileExtension); //$NON-NLS-1$
0206: if (mapping == null) { // no mapping for that extension
0207: mapping = new FileEditorMapping(fileExtension);
0208: typeEditorMappings.putDefault(
0209: mappingKeyFor(mapping), mapping);
0210: }
0211: mapping.addEditor(editor);
0212: if (bDefault) {
0213: mapping.setDefaultEditor(editor);
0214: }
0215: }
0216: }
0217:
0218: // add it to the table of mappings
0219: itr = filenames.iterator();
0220: while (itr.hasNext()) {
0221: String filename = (String) itr.next();
0222:
0223: if (filename != null && filename.length() > 0) {
0224: FileEditorMapping mapping = getMappingFor(filename);
0225: if (mapping == null) { // no mapping for that extension
0226: String name;
0227: String extension;
0228: int index = filename.indexOf('.');
0229: if (index < 0) {
0230: name = filename;
0231: extension = ""; //$NON-NLS-1$
0232: } else {
0233: name = filename.substring(0, index);
0234: extension = filename.substring(index + 1);
0235: }
0236: mapping = new FileEditorMapping(name, extension);
0237: typeEditorMappings.putDefault(
0238: mappingKeyFor(mapping), mapping);
0239: }
0240: mapping.addEditor(editor);
0241: if (bDefault) {
0242: mapping.setDefaultEditor(editor);
0243: }
0244: }
0245: }
0246:
0247: itr = contentTypeVector.iterator();
0248: while (itr.hasNext()) {
0249: String contentTypeId = (String) itr.next();
0250: if (contentTypeId != null && contentTypeId.length() > 0) {
0251: IContentType contentType = Platform
0252: .getContentTypeManager().getContentType(
0253: contentTypeId);
0254: if (contentType != null) {
0255: IEditorDescriptor[] editorArray = (IEditorDescriptor[]) contentTypeToEditorMappings
0256: .get(contentType);
0257: if (editorArray == null) {
0258: editorArray = new IEditorDescriptor[] { editor };
0259: contentTypeToEditorMappings.put(contentType,
0260: editorArray);
0261: } else {
0262: IEditorDescriptor[] newArray = new IEditorDescriptor[editorArray.length + 1];
0263: if (bDefault) { // default editors go to the front of the line
0264: newArray[0] = editor;
0265: System.arraycopy(editorArray, 0, newArray,
0266: 1, editorArray.length);
0267: } else {
0268: newArray[editorArray.length] = editor;
0269: System.arraycopy(editorArray, 0, newArray,
0270: 0, editorArray.length);
0271: }
0272: contentTypeToEditorMappings.put(contentType,
0273: newArray);
0274: }
0275: }
0276: }
0277: }
0278:
0279: // Update editor map.
0280: mapIDtoEditor.put(editor.getId(), editor);
0281: }
0282:
0283: /**
0284: * Add external editors to the editor mapping.
0285: */
0286: private void addExternalEditorsToEditorMap() {
0287: IEditorDescriptor desc = null;
0288:
0289: // Add registered editors (may include external editors).
0290: FileEditorMapping maps[] = typeEditorMappings.allMappings();
0291: for (int i = 0; i < maps.length; i++) {
0292: FileEditorMapping map = maps[i];
0293: IEditorDescriptor[] descArray = map.getEditors();
0294: for (int n = 0; n < descArray.length; n++) {
0295: desc = descArray[n];
0296: mapIDtoEditor.put(desc.getId(), desc);
0297: }
0298: }
0299: }
0300:
0301: /*
0302: * (non-Javadoc) Method declared on IEditorRegistry.
0303: */
0304: public void addPropertyListener(IPropertyListener l) {
0305: addListenerObject(l);
0306: }
0307:
0308: /*
0309: * (non-Javadoc) Method declared on IEditorRegistry.
0310: */
0311: public IEditorDescriptor findEditor(String id) {
0312: return (IEditorDescriptor) mapIDtoEditor.get(id);
0313: }
0314:
0315: /**
0316: * Fires a property changed event to all registered listeners.
0317: *
0318: * @param type the type of event
0319: * @see IEditorRegistry#PROP_CONTENTS
0320: */
0321: private void firePropertyChange(final int type) {
0322: Object[] array = getListeners();
0323: for (int nX = 0; nX < array.length; nX++) {
0324: final IPropertyListener l = (IPropertyListener) array[nX];
0325: Platform.run(new SafeRunnable() {
0326: public void run() {
0327: l.propertyChanged(EditorRegistry.this , type);
0328: }
0329: });
0330: }
0331: }
0332:
0333: /*
0334: * (non-Javadoc) Method declared on IEditorRegistry.
0335: *
0336: * @deprecated
0337: */
0338: public IEditorDescriptor getDefaultEditor() {
0339: // the default editor will always be the system external editor
0340: // this should never return null
0341: return findEditor(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID);
0342: }
0343:
0344: /*
0345: * (non-Javadoc) Method declared on IEditorRegistry.
0346: */
0347: public IEditorDescriptor getDefaultEditor(String filename) {
0348: return getDefaultEditor(filename, guessAtContentType(filename));
0349: }
0350:
0351: /**
0352: * Return the (approximated) content type for a file with the given name.
0353: *
0354: * @param filename the filename
0355: * @return the content type or <code>null</code> if it could not be determined
0356: * @since 3.1
0357: */
0358: private IContentType guessAtContentType(String filename) {
0359: return Platform.getContentTypeManager().findContentTypeFor(
0360: filename);
0361: }
0362:
0363: /**
0364: * Returns the default file image descriptor.
0365: *
0366: * @return the image descriptor
0367: */
0368: private ImageDescriptor getDefaultImage() {
0369: // @issue what should be the default image?
0370: return WorkbenchImages
0371: .getImageDescriptor(ISharedImages.IMG_OBJ_FILE);
0372: }
0373:
0374: /*
0375: * (non-Javadoc) Method declared on IEditorRegistry.
0376: */
0377: public IEditorDescriptor[] getEditors(String filename) {
0378: return getEditors(filename, guessAtContentType(filename));
0379: }
0380:
0381: /*
0382: * (non-Javadoc) Method declared on IEditorRegistry.
0383: */
0384: public IFileEditorMapping[] getFileEditorMappings() {
0385: FileEditorMapping[] array = typeEditorMappings.allMappings();
0386: final Collator collator = Collator.getInstance();
0387: Arrays.sort(array, new Comparator() {
0388:
0389: /* (non-Javadoc)
0390: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
0391: */
0392: public int compare(Object o1, Object o2) {
0393: String s1 = ((FileEditorMapping) o1).getLabel();
0394: String s2 = ((FileEditorMapping) o2).getLabel();
0395: return collator.compare(s1, s2);
0396: }
0397: });
0398: return array;
0399: }
0400:
0401: /*
0402: * (non-Javadoc) Method declared on IEditorRegistry.
0403: */
0404: public ImageDescriptor getImageDescriptor(String filename) {
0405: return getImageDescriptor(filename,
0406: guessAtContentType(filename));
0407: }
0408:
0409: /**
0410: * Find the file editor mapping for the file extension. Returns
0411: * <code>null</code> if not found.
0412: *
0413: * @param ext
0414: * the file extension
0415: * @return the mapping, or <code>null</code>
0416: */
0417: private FileEditorMapping getMappingFor(String ext) {
0418: if (ext == null) {
0419: return null;
0420: }
0421: String key = mappingKeyFor(ext);
0422: return typeEditorMappings.get(key);
0423: }
0424:
0425: /**
0426: * Find the file editor mappings for the given filename.
0427: * <p>
0428: * Return an array of two FileEditorMapping items, where the first mapping
0429: * is for the entire filename, and the second mapping is for the filename's
0430: * extension only. These items can be null if no mapping exist on the
0431: * filename and/or filename's extension.</p>
0432: *
0433: * @param filename the filename
0434: * @return the mappings
0435: */
0436: private FileEditorMapping[] getMappingForFilename(String filename) {
0437: FileEditorMapping[] mapping = new FileEditorMapping[2];
0438:
0439: // Lookup on entire filename
0440: mapping[0] = getMappingFor(filename);
0441:
0442: // Lookup on filename's extension
0443: int index = filename.lastIndexOf('.');
0444: if (index > -1) {
0445: String extension = filename.substring(index);
0446: mapping[1] = getMappingFor("*" + extension); //$NON-NLS-1$
0447: }
0448:
0449: return mapping;
0450: }
0451:
0452: /**
0453: * Return the editor descriptors pulled from the OS.
0454: * <p>
0455: * WARNING! The image described by each editor descriptor is *not* known by
0456: * the workbench's graphic registry. Therefore clients must take care to
0457: * ensure that if they access any of the images held by these editors that
0458: * they also dispose them
0459: * </p>
0460: * @return the editor descriptors
0461: */
0462: public IEditorDescriptor[] getSortedEditorsFromOS() {
0463: List externalEditors = new ArrayList();
0464: Program[] programs = Program.getPrograms();
0465:
0466: for (int i = 0; i < programs.length; i++) {
0467: //1FPLRL2: ITPUI:WINNT - NOTEPAD editor cannot be launched
0468: //Some entries start with %SystemRoot%
0469: //For such cases just use the file name as they are generally
0470: //in directories which are on the path
0471: /*
0472: * if (fileName.charAt(0) == '%') { fileName = name + ".exe"; }
0473: */
0474:
0475: EditorDescriptor editor = new EditorDescriptor();
0476: editor.setOpenMode(EditorDescriptor.OPEN_EXTERNAL);
0477: editor.setProgram(programs[i]);
0478:
0479: // determine the program icon this editor would need (do not let it
0480: // be cached in the workbench registry)
0481: ImageDescriptor desc = new ExternalProgramImageDescriptor(
0482: programs[i]);
0483: editor.setImageDescriptor(desc);
0484: externalEditors.add(editor);
0485: }
0486:
0487: Object[] tempArray = sortEditors(externalEditors);
0488: IEditorDescriptor[] array = new IEditorDescriptor[externalEditors
0489: .size()];
0490: for (int i = 0; i < tempArray.length; i++) {
0491: array[i] = (IEditorDescriptor) tempArray[i];
0492: }
0493: return array;
0494: }
0495:
0496: /**
0497: * Return the editors loaded from plugins.
0498: *
0499: * @return the sorted array of editors declared in plugins
0500: * @see #comparer
0501: */
0502: public IEditorDescriptor[] getSortedEditorsFromPlugins() {
0503: IEditorDescriptor[] array = new IEditorDescriptor[sortedEditorsFromPlugins
0504: .size()];
0505: sortedEditorsFromPlugins.toArray(array);
0506: return array;
0507: }
0508:
0509: /**
0510: * Answer an intial id to editor map. This will create a new map and
0511: * populate it with the default system editors.
0512: *
0513: * @param initialSize
0514: * the initial size of the map
0515: * @return the new map
0516: */
0517: private HashMap initialIdToEditorMap(int initialSize) {
0518: HashMap map = new HashMap(initialSize);
0519: addSystemEditors(map);
0520: return map;
0521: }
0522:
0523: /**
0524: * Add the system editors to the provided map. This will always add an
0525: * editor with an id of {@link #SYSTEM_EXTERNAL_EDITOR_ID} and may also add
0526: * an editor with id of {@link #SYSTEM_INPLACE_EDITOR_ID} if the system
0527: * configuration supports it.
0528: *
0529: * @param map the map to augment
0530: */
0531: private void addSystemEditors(HashMap map) {
0532: // there will always be a system external editor descriptor
0533: EditorDescriptor editor = new EditorDescriptor();
0534: editor.setID(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID);
0535: editor.setName(WorkbenchMessages.SystemEditorDescription_name);
0536: editor.setOpenMode(EditorDescriptor.OPEN_EXTERNAL);
0537: // @issue we need a real icon for this editor?
0538: map.put(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID, editor);
0539:
0540: // there may be a system in-place editor if supported by platform
0541: if (ComponentSupport.inPlaceEditorSupported()) {
0542: editor = new EditorDescriptor();
0543: editor.setID(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID);
0544: editor
0545: .setName(WorkbenchMessages.SystemInPlaceDescription_name);
0546: editor.setOpenMode(EditorDescriptor.OPEN_INPLACE);
0547: // @issue we need a real icon for this editor?
0548: map.put(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID, editor);
0549: }
0550:
0551: EditorDescriptor emptyEditorDescriptor = new EditorDescriptor();
0552: emptyEditorDescriptor.setID(EMPTY_EDITOR_ID);
0553: emptyEditorDescriptor.setName("(Empty)"); //$NON-NLS-1$
0554: emptyEditorDescriptor
0555: .setImageDescriptor(WorkbenchImages
0556: .getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_ELEMENT));
0557: map.put(EMPTY_EDITOR_ID, emptyEditorDescriptor);
0558: }
0559:
0560: /**
0561: * Initialize the registry state from plugin declarations and preference
0562: * overrides.
0563: */
0564: private void initializeFromStorage() {
0565: typeEditorMappings = new EditorMap();
0566: extensionImages = new HashMap();
0567:
0568: //Get editors from the registry
0569: EditorRegistryReader registryReader = new EditorRegistryReader();
0570: registryReader.addEditors(this );
0571: sortInternalEditors();
0572: rebuildInternalEditorMap();
0573:
0574: IPreferenceStore store = PlatformUI.getPreferenceStore();
0575: String defaultEditors = store
0576: .getString(IPreferenceConstants.DEFAULT_EDITORS);
0577: String chachedDefaultEditors = store
0578: .getString(IPreferenceConstants.DEFAULT_EDITORS_CACHE);
0579:
0580: //If defaults has changed load it afterwards so it overrides the users
0581: // associations.
0582: if (defaultEditors == null
0583: || defaultEditors.equals(chachedDefaultEditors)) {
0584: setProductDefaults(defaultEditors);
0585: loadAssociations(); //get saved earlier state
0586: } else {
0587: loadAssociations(); //get saved earlier state
0588: setProductDefaults(defaultEditors);
0589: store.putValue(IPreferenceConstants.DEFAULT_EDITORS_CACHE,
0590: defaultEditors);
0591: }
0592: addExternalEditorsToEditorMap();
0593: }
0594:
0595: /**
0596: * Set the default editors according to the preference store which can be
0597: * overwritten in the file properties.ini. In the form:
0598: * <p>
0599: * <code>ext1:id1;ext2:id2;...</code>
0600: * </p>
0601: *
0602: * @param defaultEditors the default editors to set
0603: */
0604: private void setProductDefaults(String defaultEditors) {
0605: if (defaultEditors == null || defaultEditors.length() == 0) {
0606: return;
0607: }
0608:
0609: StringTokenizer extEditors = new StringTokenizer(
0610: defaultEditors, new Character(
0611: IPreferenceConstants.SEPARATOR).toString());
0612: while (extEditors.hasMoreTokens()) {
0613: String extEditor = extEditors.nextToken().trim();
0614: int index = extEditor.indexOf(':');
0615: if (extEditor.length() < 3 || index <= 0
0616: || index >= (extEditor.length() - 1)) {
0617: //Extension and id must have at least one char.
0618: WorkbenchPlugin
0619: .log("Error setting default editor. Could not parse '" + extEditor + "'. Default editors should be specified as '*.ext1:editorId1;*.ext2:editorId2'"); //$NON-NLS-1$ //$NON-NLS-2$
0620: return;
0621: }
0622: String ext = extEditor.substring(0, index).trim();
0623: String editorId = extEditor.substring(index + 1).trim();
0624: FileEditorMapping mapping = getMappingFor(ext);
0625: if (mapping == null) {
0626: WorkbenchPlugin
0627: .log("Error setting default editor. Could not find mapping for '" + ext + "'."); //$NON-NLS-1$ //$NON-NLS-2$
0628: continue;
0629: }
0630: EditorDescriptor editor = (EditorDescriptor) findEditor(editorId);
0631: if (editor == null) {
0632: WorkbenchPlugin
0633: .log("Error setting default editor. Could not find editor: '" + editorId + "'."); //$NON-NLS-1$ //$NON-NLS-2$
0634: continue;
0635: }
0636: mapping.setDefaultEditor(editor);
0637: }
0638: }
0639:
0640: /**
0641: * Read the editors defined in the preferences store.
0642: *
0643: * @param editorTable
0644: * Editor table to store the editor definitions.
0645: * @return true if the table is built succesfully.
0646: */
0647: private boolean readEditors(Map editorTable) {
0648: //Get the workbench plugin's working directory
0649: IPath workbenchStatePath = WorkbenchPlugin.getDefault()
0650: .getDataLocation();
0651: if (workbenchStatePath == null) {
0652: return false;
0653: }
0654: IPreferenceStore store = WorkbenchPlugin.getDefault()
0655: .getPreferenceStore();
0656: Reader reader = null;
0657: try {
0658: // Get the editors defined in the preferences store
0659: String xmlString = store
0660: .getString(IPreferenceConstants.EDITORS);
0661: if (xmlString == null || xmlString.length() == 0) {
0662: FileInputStream stream = new FileInputStream(
0663: workbenchStatePath.append(
0664: IWorkbenchConstants.EDITOR_FILE_NAME)
0665: .toOSString());
0666: reader = new BufferedReader(new InputStreamReader(
0667: stream, "utf-8")); //$NON-NLS-1$
0668: } else {
0669: reader = new StringReader(xmlString);
0670: }
0671: XMLMemento memento = XMLMemento.createReadRoot(reader);
0672: EditorDescriptor editor;
0673: IMemento[] edMementos = memento
0674: .getChildren(IWorkbenchConstants.TAG_DESCRIPTOR);
0675: // Get the editors and validate each one
0676: for (int i = 0; i < edMementos.length; i++) {
0677: editor = new EditorDescriptor();
0678: boolean valid = editor.loadValues(edMementos[i]);
0679: if (!valid) {
0680: continue;
0681: }
0682: if (editor.getPluginID() != null) {
0683: //If the editor is from a plugin we use its ID to look it
0684: // up in the mapping of editors we
0685: //have obtained from plugins. This allows us to verify that
0686: // the editor is still valid
0687: //and allows us to get the editor description from the
0688: // mapping table which has
0689: //a valid config element field.
0690: EditorDescriptor validEditorDescritor = (EditorDescriptor) mapIDtoEditor
0691: .get(editor.getId());
0692: if (validEditorDescritor != null) {
0693: editorTable.put(validEditorDescritor.getId(),
0694: validEditorDescritor);
0695: }
0696: } else { //This is either from a program or a user defined
0697: // editor
0698: ImageDescriptor descriptor;
0699: if (editor.getProgram() == null) {
0700: descriptor = new ProgramImageDescriptor(editor
0701: .getFileName(), 0);
0702: } else {
0703: descriptor = new ExternalProgramImageDescriptor(
0704: editor.getProgram());
0705: }
0706: editor.setImageDescriptor(descriptor);
0707: editorTable.put(editor.getId(), editor);
0708: }
0709: }
0710: } catch (IOException e) {
0711: try {
0712: if (reader != null) {
0713: reader.close();
0714: }
0715: } catch (IOException ex) {
0716: e.printStackTrace();
0717: }
0718: //Ignore this as the workbench may not yet have saved any state
0719: return false;
0720: } catch (WorkbenchException e) {
0721: ErrorDialog.openError((Shell) null,
0722: WorkbenchMessages.EditorRegistry_errorTitle,
0723: WorkbenchMessages.EditorRegistry_errorMessage, e
0724: .getStatus());
0725: return false;
0726: }
0727:
0728: return true;
0729: }
0730:
0731: /**
0732: * Read the file types and associate them to their defined editor(s).
0733: *
0734: * @param editorTable
0735: * The editor table containing the defined editors.
0736: * @param reader
0737: * Reader containing the preferences content for the resources.
0738: *
0739: * @throws WorkbenchException
0740: */
0741: public void readResources(Map editorTable, Reader reader)
0742: throws WorkbenchException {
0743: XMLMemento memento = XMLMemento.createReadRoot(reader);
0744: String versionString = memento
0745: .getString(IWorkbenchConstants.TAG_VERSION);
0746: boolean versionIs31 = "3.1".equals(versionString); //$NON-NLS-1$
0747:
0748: IMemento[] extMementos = memento
0749: .getChildren(IWorkbenchConstants.TAG_INFO);
0750: for (int i = 0; i < extMementos.length; i++) {
0751: String name = extMementos[i]
0752: .getString(IWorkbenchConstants.TAG_NAME);
0753: if (name == null) {
0754: name = "*"; //$NON-NLS-1$
0755: }
0756: String extension = extMementos[i]
0757: .getString(IWorkbenchConstants.TAG_EXTENSION);
0758: IMemento[] idMementos = extMementos[i]
0759: .getChildren(IWorkbenchConstants.TAG_EDITOR);
0760: String[] editorIDs = new String[idMementos.length];
0761: for (int j = 0; j < idMementos.length; j++) {
0762: editorIDs[j] = idMementos[j]
0763: .getString(IWorkbenchConstants.TAG_ID);
0764: }
0765: idMementos = extMementos[i]
0766: .getChildren(IWorkbenchConstants.TAG_DELETED_EDITOR);
0767: String[] deletedEditorIDs = new String[idMementos.length];
0768: for (int j = 0; j < idMementos.length; j++) {
0769: deletedEditorIDs[j] = idMementos[j]
0770: .getString(IWorkbenchConstants.TAG_ID);
0771: }
0772: FileEditorMapping mapping = getMappingFor(name
0773: + "." + extension); //$NON-NLS-1$
0774: if (mapping == null) {
0775: mapping = new FileEditorMapping(name, extension);
0776: }
0777: List editors = new ArrayList();
0778: for (int j = 0; j < editorIDs.length; j++) {
0779: if (editorIDs[j] != null) {
0780: EditorDescriptor editor = (EditorDescriptor) editorTable
0781: .get(editorIDs[j]);
0782: if (editor != null) {
0783: editors.add(editor);
0784: }
0785: }
0786: }
0787: List deletedEditors = new ArrayList();
0788: for (int j = 0; j < deletedEditorIDs.length; j++) {
0789: if (deletedEditorIDs[j] != null) {
0790: EditorDescriptor editor = (EditorDescriptor) editorTable
0791: .get(deletedEditorIDs[j]);
0792: if (editor != null) {
0793: deletedEditors.add(editor);
0794: }
0795: }
0796: }
0797:
0798: List defaultEditors = new ArrayList();
0799:
0800: if (versionIs31) { // parse the new format
0801: idMementos = extMementos[i]
0802: .getChildren(IWorkbenchConstants.TAG_DEFAULT_EDITOR);
0803: String[] defaultEditorIds = new String[idMementos.length];
0804: for (int j = 0; j < idMementos.length; j++) {
0805: defaultEditorIds[j] = idMementos[j]
0806: .getString(IWorkbenchConstants.TAG_ID);
0807: }
0808: for (int j = 0; j < defaultEditorIds.length; j++) {
0809: if (defaultEditorIds[j] != null) {
0810: EditorDescriptor editor = (EditorDescriptor) editorTable
0811: .get(defaultEditorIds[j]);
0812: if (editor != null) {
0813: defaultEditors.add(editor);
0814: }
0815: }
0816: }
0817: } else { // guess at pre 3.1 format defaults
0818: if (!editors.isEmpty()) {
0819: EditorDescriptor editor = (EditorDescriptor) editors
0820: .get(0);
0821: if (editor != null) {
0822: defaultEditors.add(editor);
0823: }
0824: }
0825: defaultEditors.addAll(Arrays.asList(mapping
0826: .getDeclaredDefaultEditors()));
0827: }
0828:
0829: // Add any new editors that have already been read from the registry
0830: // which were not deleted.
0831: IEditorDescriptor[] editorsArray = mapping.getEditors();
0832: for (int j = 0; j < editorsArray.length; j++) {
0833: if (!contains(editors, editorsArray[j])
0834: && !deletedEditors.contains(editorsArray[j])) {
0835: editors.add(editorsArray[j]);
0836: }
0837: }
0838: // Map the editor(s) to the file type
0839: mapping.setEditorsList(editors);
0840: mapping.setDeletedEditorsList(deletedEditors);
0841: mapping.setDefaultEditors(defaultEditors);
0842: typeEditorMappings.put(mappingKeyFor(mapping), mapping);
0843: }
0844: }
0845:
0846: /**
0847: * Determine if the editors list contains the editor descriptor.
0848: *
0849: * @param editorsArray
0850: * The list of editors
0851: * @param editorDescriptor
0852: * The editor descriptor
0853: * @return <code>true</code> if the editors list contains the editor descriptor
0854: */
0855: private boolean contains(List editorsArray,
0856: IEditorDescriptor editorDescriptor) {
0857: IEditorDescriptor currentEditorDescriptor = null;
0858: Iterator i = editorsArray.iterator();
0859: while (i.hasNext()) {
0860: currentEditorDescriptor = (IEditorDescriptor) i.next();
0861: if (currentEditorDescriptor.getId().equals(
0862: editorDescriptor.getId())) {
0863: return true;
0864: }
0865: }
0866: return false;
0867:
0868: }
0869:
0870: /**
0871: * Creates the reader for the resources preferences defined in the
0872: * preference store.
0873: *
0874: * @param editorTable
0875: * The editor table containing the defined editors.
0876: * @return true if the resources are read succesfully.
0877: */
0878: private boolean readResources(Map editorTable) {
0879: //Get the workbench plugin's working directory
0880: IPath workbenchStatePath = WorkbenchPlugin.getDefault()
0881: .getDataLocation();
0882: // XXX: nobody cares about this return value
0883: if (workbenchStatePath == null) {
0884: return false;
0885: }
0886: IPreferenceStore store = WorkbenchPlugin.getDefault()
0887: .getPreferenceStore();
0888: Reader reader = null;
0889: try {
0890: // Get the resource types
0891: String xmlString = store
0892: .getString(IPreferenceConstants.RESOURCES);
0893: if (xmlString == null || xmlString.length() == 0) {
0894: FileInputStream stream = new FileInputStream(
0895: workbenchStatePath
0896: .append(
0897: IWorkbenchConstants.RESOURCE_TYPE_FILE_NAME)
0898: .toOSString());
0899: reader = new BufferedReader(new InputStreamReader(
0900: stream, "utf-8")); //$NON-NLS-1$
0901: } else {
0902: reader = new StringReader(xmlString);
0903: }
0904: // Read the defined resources into the table
0905: readResources(editorTable, reader);
0906: } catch (IOException e) {
0907: try {
0908: if (reader != null) {
0909: reader.close();
0910: }
0911: } catch (IOException ex) {
0912: ex.printStackTrace();
0913: }
0914: MessageDialog.openError((Shell) null,
0915: WorkbenchMessages.EditorRegistry_errorTitle,
0916: WorkbenchMessages.EditorRegistry_errorMessage);
0917: return false;
0918: } catch (WorkbenchException e) {
0919: ErrorDialog.openError((Shell) null,
0920: WorkbenchMessages.EditorRegistry_errorTitle,
0921: WorkbenchMessages.EditorRegistry_errorMessage, e
0922: .getStatus());
0923: return false;
0924: }
0925: return true;
0926:
0927: }
0928:
0929: /**
0930: * Load the serialized resource associations Return true if the operation
0931: * was successful, false otherwise
0932: */
0933: private boolean loadAssociations() {
0934: Map editorTable = new HashMap();
0935: if (!readEditors(editorTable)) {
0936: return false;
0937: }
0938: return readResources(editorTable);
0939: }
0940:
0941: /**
0942: * Return a friendly version of the given key suitable for use in the editor
0943: * map.
0944: */
0945: private String mappingKeyFor(String type) {
0946: // keep everyting lower case for case-sensitive platforms
0947: return type.toLowerCase();
0948: }
0949:
0950: /**
0951: * Return a key that combines the file's name and extension of the given
0952: * mapping
0953: *
0954: * @param mapping the mapping to generate a key for
0955: */
0956: private String mappingKeyFor(FileEditorMapping mapping) {
0957: return mappingKeyFor(mapping.getName()
0958: + (mapping.getExtension().length() == 0 ? "" : "." + mapping.getExtension())); //$NON-NLS-1$ //$NON-NLS-2$
0959: }
0960:
0961: /**
0962: * Rebuild the editor map
0963: */
0964: private void rebuildEditorMap() {
0965: rebuildInternalEditorMap();
0966: addExternalEditorsToEditorMap();
0967: }
0968:
0969: /**
0970: * Rebuild the internal editor mapping.
0971: */
0972: private void rebuildInternalEditorMap() {
0973: Iterator itr = null;
0974: IEditorDescriptor desc = null;
0975:
0976: // Allocate a new map.
0977: mapIDtoEditor = initialIdToEditorMap(mapIDtoEditor.size());
0978:
0979: // Add plugin editors.
0980: itr = sortedEditorsFromPlugins.iterator();
0981: while (itr.hasNext()) {
0982: desc = (IEditorDescriptor) itr.next();
0983: mapIDtoEditor.put(desc.getId(), desc);
0984: }
0985: }
0986:
0987: /*
0988: * (non-Javadoc) Method declared on IEditorRegistry.
0989: */
0990: public void removePropertyListener(IPropertyListener l) {
0991: removeListenerObject(l);
0992: }
0993:
0994: /**
0995: * Save the registry to the filesystem by serializing the current resource
0996: * associations.
0997: */
0998: public void saveAssociations() {
0999: //Save the resource type descriptions
1000: List editors = new ArrayList();
1001: IPreferenceStore store = WorkbenchPlugin.getDefault()
1002: .getPreferenceStore();
1003:
1004: XMLMemento memento = XMLMemento
1005: .createWriteRoot(IWorkbenchConstants.TAG_EDITORS);
1006: memento.putString(IWorkbenchConstants.TAG_VERSION, "3.1"); //$NON-NLS-1$
1007: FileEditorMapping maps[] = typeEditorMappings.userMappings();
1008: for (int mapsIndex = 0; mapsIndex < maps.length; mapsIndex++) {
1009: FileEditorMapping type = maps[mapsIndex];
1010: IMemento editorMemento = memento
1011: .createChild(IWorkbenchConstants.TAG_INFO);
1012: editorMemento.putString(IWorkbenchConstants.TAG_NAME, type
1013: .getName());
1014: editorMemento.putString(IWorkbenchConstants.TAG_EXTENSION,
1015: type.getExtension());
1016: IEditorDescriptor[] editorArray = type.getEditors();
1017: for (int i = 0; i < editorArray.length; i++) {
1018: EditorDescriptor editor = (EditorDescriptor) editorArray[i];
1019: if (!editors.contains(editor)) {
1020: editors.add(editor);
1021: }
1022: IMemento idMemento = editorMemento
1023: .createChild(IWorkbenchConstants.TAG_EDITOR);
1024: idMemento.putString(IWorkbenchConstants.TAG_ID,
1025: editorArray[i].getId());
1026: }
1027: editorArray = type.getDeletedEditors();
1028: for (int i = 0; i < editorArray.length; i++) {
1029: EditorDescriptor editor = (EditorDescriptor) editorArray[i];
1030: if (!editors.contains(editor)) {
1031: editors.add(editor);
1032: }
1033: IMemento idMemento = editorMemento
1034: .createChild(IWorkbenchConstants.TAG_DELETED_EDITOR);
1035: idMemento.putString(IWorkbenchConstants.TAG_ID,
1036: editorArray[i].getId());
1037: }
1038: editorArray = type.getDeclaredDefaultEditors();
1039: for (int i = 0; i < editorArray.length; i++) {
1040: EditorDescriptor editor = (EditorDescriptor) editorArray[i];
1041: if (!editors.contains(editor)) {
1042: editors.add(editor);
1043: }
1044: IMemento idMemento = editorMemento
1045: .createChild(IWorkbenchConstants.TAG_DEFAULT_EDITOR);
1046: idMemento.putString(IWorkbenchConstants.TAG_ID,
1047: editorArray[i].getId());
1048: }
1049: }
1050: Writer writer = null;
1051: try {
1052: writer = new StringWriter();
1053: memento.save(writer);
1054: writer.close();
1055: store.setValue(IPreferenceConstants.RESOURCES, writer
1056: .toString());
1057: } catch (IOException e) {
1058: try {
1059: if (writer != null) {
1060: writer.close();
1061: }
1062: } catch (IOException ex) {
1063: ex.printStackTrace();
1064: }
1065: MessageDialog.openError((Shell) null, "Saving Problems", //$NON-NLS-1$
1066: "Unable to save resource associations."); //$NON-NLS-1$
1067: return;
1068: }
1069:
1070: memento = XMLMemento
1071: .createWriteRoot(IWorkbenchConstants.TAG_EDITORS);
1072: Iterator itr = editors.iterator();
1073: while (itr.hasNext()) {
1074: EditorDescriptor editor = (EditorDescriptor) itr.next();
1075: IMemento editorMemento = memento
1076: .createChild(IWorkbenchConstants.TAG_DESCRIPTOR);
1077: editor.saveValues(editorMemento);
1078: }
1079: writer = null;
1080: try {
1081: writer = new StringWriter();
1082: memento.save(writer);
1083: writer.close();
1084: store.setValue(IPreferenceConstants.EDITORS, writer
1085: .toString());
1086: } catch (IOException e) {
1087: try {
1088: if (writer != null) {
1089: writer.close();
1090: }
1091: } catch (IOException ex) {
1092: ex.printStackTrace();
1093: }
1094: MessageDialog.openError((Shell) null,
1095: "Error", "Unable to save resource associations."); //$NON-NLS-1$ //$NON-NLS-2$
1096: return;
1097: }
1098: }
1099:
1100: /**
1101: * Set the collection of FileEditorMappings. The given collection is
1102: * converted into the internal hash table for faster lookup Each mapping
1103: * goes from an extension to the collection of editors that work on it. This
1104: * operation will rebuild the internal editor mappings.
1105: *
1106: * @param newResourceTypes
1107: * te new file editor mappings.
1108: */
1109: public void setFileEditorMappings(
1110: FileEditorMapping[] newResourceTypes) {
1111: typeEditorMappings = new EditorMap();
1112: for (int i = 0; i < newResourceTypes.length; i++) {
1113: FileEditorMapping mapping = newResourceTypes[i];
1114: typeEditorMappings.put(mappingKeyFor(mapping), mapping);
1115: }
1116: extensionImages = new HashMap();
1117: rebuildEditorMap();
1118: firePropertyChange(PROP_CONTENTS);
1119: }
1120:
1121: /*
1122: * (non-Javadoc) Method declared on IEditorRegistry.
1123: */
1124: public void setDefaultEditor(String fileName, String editorId) {
1125: EditorDescriptor desc = (EditorDescriptor) findEditor(editorId);
1126: FileEditorMapping[] mapping = getMappingForFilename(fileName);
1127: if (mapping[0] != null) {
1128: mapping[0].setDefaultEditor(desc);
1129: }
1130: if (mapping[1] != null) {
1131: mapping[1].setDefaultEditor(desc);
1132: }
1133: }
1134:
1135: /**
1136: * Alphabetically sort the internal editors.
1137: *
1138: * @see #comparer
1139: */
1140: private Object[] sortEditors(List unsortedList) {
1141: Object[] array = new Object[unsortedList.size()];
1142: unsortedList.toArray(array);
1143:
1144: Collections.sort(Arrays.asList(array), comparer);
1145: return array;
1146: }
1147:
1148: /**
1149: * Alphabetically sort the internal editors.
1150: *
1151: * @see #comparer
1152: */
1153: private void sortInternalEditors() {
1154: Object[] array = sortEditors(sortedEditorsFromPlugins);
1155: sortedEditorsFromPlugins = new ArrayList();
1156: for (int i = 0; i < array.length; i++) {
1157: sortedEditorsFromPlugins.add(array[i]);
1158: }
1159: }
1160:
1161: /**
1162: * Map of FileEditorMapping (extension to FileEditorMapping) Uses two
1163: * java.util.HashMap: one keeps the default which are set by the plugins and
1164: * the other keeps the changes made by the user through the preference page.
1165: */
1166: private static class EditorMap {
1167: HashMap defaultMap = new HashMap();
1168:
1169: HashMap map = new HashMap();
1170:
1171: /**
1172: * Put a default mapping into the editor map.
1173: *
1174: * @param key the key to set
1175: * @param value the value to associate
1176: */
1177: public void putDefault(String key, FileEditorMapping value) {
1178: defaultMap.put(key, value);
1179: }
1180:
1181: /**
1182: * Put a mapping into the user editor map.
1183: *
1184: * @param key the key to set
1185: * @param value the value to associate
1186: */
1187: public void put(String key, FileEditorMapping value) {
1188: Object result = defaultMap.get(key);
1189: if (value.equals(result)) {
1190: map.remove(key);
1191: } else {
1192: map.put(key, value);
1193: }
1194: }
1195:
1196: /**
1197: * Return the mapping associated to the key. First searches user
1198: * map, and then falls back to the default map if there is no match. May
1199: * return <code>null</code>
1200: *
1201: * @param key
1202: * the key to search for
1203: * @return the mapping associated to the key or <code>null</code>
1204: */
1205: public FileEditorMapping get(String key) {
1206: Object result = map.get(key);
1207: if (result == null) {
1208: result = defaultMap.get(key);
1209: }
1210: return (FileEditorMapping) result;
1211: }
1212:
1213: /**
1214: * Return all mappings. This will return default mappings overlayed with
1215: * user mappings.
1216: *
1217: * @return the mappings
1218: */
1219: public FileEditorMapping[] allMappings() {
1220: HashMap merge = (HashMap) defaultMap.clone();
1221: merge.putAll(map);
1222: Collection values = merge.values();
1223: FileEditorMapping result[] = new FileEditorMapping[values
1224: .size()];
1225: return (FileEditorMapping[]) values.toArray(result);
1226: }
1227:
1228: /**
1229: * Return all user mappings.
1230: *
1231: * @return the mappings
1232: */
1233: public FileEditorMapping[] userMappings() {
1234: Collection values = map.values();
1235: FileEditorMapping result[] = new FileEditorMapping[values
1236: .size()];
1237: return (FileEditorMapping[]) values.toArray(result);
1238: }
1239: }
1240:
1241: /*
1242: * (non-Javadoc)
1243: *
1244: * @see org.eclipse.ui.IEditorRegistry#isSystemInPlaceEditorAvailable(String)
1245: */
1246: public boolean isSystemInPlaceEditorAvailable(String filename) {
1247: return ComponentSupport.inPlaceEditorAvailable(filename);
1248: }
1249:
1250: /*
1251: * (non-Javadoc)
1252: *
1253: * @see org.eclipse.ui.IEditorRegistry#isSystemExternalEditorAvailable(String)
1254: */
1255: public boolean isSystemExternalEditorAvailable(String filename) {
1256: int nDot = filename.lastIndexOf('.');
1257: if (nDot >= 0) {
1258: String strName = filename.substring(nDot);
1259: return Program.findProgram(strName) != null;
1260: }
1261: return false;
1262: }
1263:
1264: /*
1265: * (non-Javadoc)
1266: *
1267: * @see org.eclipse.ui.IEditorRegistry#getSystemExternalEditorImageDescriptor(java.lang.String)
1268: */
1269: public ImageDescriptor getSystemExternalEditorImageDescriptor(
1270: String filename) {
1271: Program externalProgram = null;
1272: int extensionIndex = filename.lastIndexOf('.');
1273: if (extensionIndex >= 0) {
1274: externalProgram = Program.findProgram(filename
1275: .substring(extensionIndex));
1276: }
1277: if (externalProgram == null) {
1278: return null;
1279: }
1280:
1281: return new ExternalProgramImageDescriptor(externalProgram);
1282: }
1283:
1284: /**
1285: * Removes the entry with the value of the editor descriptor from the given
1286: * map. If the descriptor is the last descriptor in a given
1287: * FileEditorMapping then the mapping is removed from the map.
1288: *
1289: * @param map
1290: * the map to search
1291: * @param desc
1292: * the descriptor value to remove
1293: */
1294: private void removeEditorFromMapping(HashMap map,
1295: IEditorDescriptor desc) {
1296: Iterator iter = map.values().iterator();
1297: FileEditorMapping mapping;
1298: IEditorDescriptor[] editors;
1299: while (iter.hasNext()) {
1300: mapping = (FileEditorMapping) iter.next();
1301: editors = mapping.getEditors();
1302: for (int i = 0; i < editors.length; i++) {
1303: if (editors[i] == desc) {
1304: mapping.removeEditor((EditorDescriptor) editors[i]);
1305: break;
1306: }
1307: }
1308: if (editors.length <= 0) {
1309: map.remove(mapping);
1310: break;
1311: }
1312: }
1313: }
1314:
1315: /* (non-Javadoc)
1316: * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension, java.lang.Object[])
1317: */
1318: public void removeExtension(IExtension source, Object[] objects) {
1319: for (int i = 0; i < objects.length; i++) {
1320: if (objects[i] instanceof EditorDescriptor) {
1321: EditorDescriptor desc = (EditorDescriptor) objects[i];
1322:
1323: sortedEditorsFromPlugins.remove(desc);
1324: mapIDtoEditor.values().remove(desc);
1325: removeEditorFromMapping(typeEditorMappings.defaultMap,
1326: desc);
1327: removeEditorFromMapping(typeEditorMappings.map, desc);
1328: //TODO remove from content type mappings
1329: }
1330:
1331: }
1332: }
1333:
1334: /* (non-Javadoc)
1335: * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamicHelpers.IExtensionTracker, org.eclipse.core.runtime.IExtension)
1336: */
1337: public void addExtension(IExtensionTracker tracker,
1338: IExtension extension) {
1339: EditorRegistryReader eReader = new EditorRegistryReader();
1340: IConfigurationElement[] elements = extension
1341: .getConfigurationElements();
1342: for (int i = 0; i < elements.length; i++) {
1343: String id = elements[i]
1344: .getAttribute(IWorkbenchConstants.TAG_ID);
1345: if (id != null && findEditor(id) != null) {
1346: continue;
1347: }
1348: eReader.readElement(this , elements[i]);
1349: }
1350: }
1351:
1352: private IExtensionPoint getExtensionPointFilter() {
1353: return Platform.getExtensionRegistry().getExtensionPoint(
1354: PlatformUI.PLUGIN_ID,
1355: IWorkbenchRegistryConstants.PL_EDITOR);
1356: }
1357:
1358: /* (non-Javadoc)
1359: * @see org.eclipse.ui.IEditorRegistry#getDefaultEditor(java.lang.String, org.eclipse.core.runtime.content.IContentType)
1360: */
1361: public IEditorDescriptor getDefaultEditor(String fileName,
1362: IContentType contentType) {
1363: return getEditorForContentType(fileName, contentType);
1364: }
1365:
1366: /**
1367: * Return the editor for a file with a given content type.
1368: *
1369: * @param filename the file name
1370: * @param contentType the content type
1371: * @return the editor for a file with a given content type
1372: * @since 3.1
1373: */
1374: private IEditorDescriptor getEditorForContentType(String filename,
1375: IContentType contentType) {
1376: IEditorDescriptor desc = null;
1377: Object[] contentTypeResults = findRelatedObjects(contentType,
1378: filename, relatedRegistry);
1379: if (contentTypeResults != null && contentTypeResults.length > 0) {
1380: desc = (IEditorDescriptor) contentTypeResults[0];
1381: }
1382: return desc;
1383: }
1384:
1385: /* (non-Javadoc)
1386: * @see org.eclipse.ui.IEditorRegistry#getEditors(java.lang.String, org.eclipse.core.runtime.content.IContentType)
1387: */
1388: public IEditorDescriptor[] getEditors(String fileName,
1389: IContentType contentType) {
1390: return findRelatedObjects(contentType, fileName,
1391: relatedRegistry);
1392: }
1393:
1394: /* (non-Javadoc)
1395: * @see org.eclipse.ui.IEditorRegistry#getImageDescriptor(java.lang.String, org.eclipse.core.runtime.content.IContentType)
1396: */
1397: public ImageDescriptor getImageDescriptor(String filename,
1398: IContentType contentType) {
1399: if (filename == null) {
1400: return getDefaultImage();
1401: }
1402:
1403: if (contentType != null) {
1404: IEditorDescriptor desc = getEditorForContentType(filename,
1405: contentType);
1406: if (desc != null) {
1407: ImageDescriptor anImage = (ImageDescriptor) extensionImages
1408: .get(desc);
1409: if (anImage != null) {
1410: return anImage;
1411: }
1412: anImage = desc.getImageDescriptor();
1413: extensionImages.put(desc, anImage);
1414: return anImage;
1415: }
1416: }
1417: // Lookup in the cache first...
1418: String key = mappingKeyFor(filename);
1419: ImageDescriptor anImage = (ImageDescriptor) extensionImages
1420: .get(key);
1421: if (anImage != null) {
1422: return anImage;
1423: }
1424:
1425: // See if we have a mapping for the filename or extension
1426: FileEditorMapping[] mapping = getMappingForFilename(filename);
1427: for (int i = 0; i < 2; i++) {
1428: if (mapping[i] != null) {
1429: // Lookup in the cache first...
1430: String mappingKey = mappingKeyFor(mapping[i]);
1431: ImageDescriptor mappingImage = (ImageDescriptor) extensionImages
1432: .get(key);
1433: if (mappingImage != null) {
1434: return mappingImage;
1435: }
1436: // Create it and cache it
1437: IEditorDescriptor editor = mapping[i]
1438: .getDefaultEditor();
1439: if (editor != null) {
1440: mappingImage = editor.getImageDescriptor();
1441: extensionImages.put(mappingKey, mappingImage);
1442: return mappingImage;
1443: }
1444: }
1445: }
1446:
1447: // Nothing - time to look externally for the icon
1448: anImage = getSystemExternalEditorImageDescriptor(filename);
1449: if (anImage == null) {
1450: anImage = getDefaultImage();
1451: }
1452: // for dynamic UI - comment out the next line
1453: //extensionImages.put(key, anImage);
1454: return anImage;
1455:
1456: }
1457:
1458: /**
1459: * Find objects related to the content type.
1460: *
1461: * This method is temporary and exists only to back us off of the
1462: * soon-to-be-removed IContentTypeManager.IRelatedRegistry API.
1463: *
1464: * @param type
1465: * @param fileName
1466: * @param registry
1467: * @return the related objects
1468: */
1469: private IEditorDescriptor[] findRelatedObjects(IContentType type,
1470: String fileName, RelatedRegistry registry) {
1471: List allRelated = new ArrayList();
1472: List nonDefaultFileEditors = new ArrayList();
1473: IEditorDescriptor[] related;
1474:
1475: if (fileName != null) {
1476: FileEditorMapping mapping = getMappingFor(fileName);
1477: if (mapping != null) {
1478: // backwards compatibility - add editors flagged as "default"
1479: related = mapping.getDeclaredDefaultEditors();
1480: for (int i = 0; i < related.length; i++) {
1481: // we don't want to return duplicates
1482: if (!allRelated.contains(related[i])) {
1483: // if it's not filtered, add it to the list
1484: if (!WorkbenchActivityHelper
1485: .filterItem(related[i])) {
1486: allRelated.add(related[i]);
1487: }
1488: }
1489: }
1490:
1491: // add all filename editors to the nonDefaultList
1492: // we'll later try to add them all after content types are resolved
1493: // duplicates (ie: default editors) will be ignored
1494: nonDefaultFileEditors.addAll(Arrays.asList(mapping
1495: .getEditors()));
1496: }
1497:
1498: int index = fileName.lastIndexOf('.');
1499: if (index > -1) {
1500: String extension = "*" + fileName.substring(index); //$NON-NLS-1$
1501: mapping = getMappingFor(extension);
1502: if (mapping != null) {
1503: related = mapping.getDeclaredDefaultEditors();
1504: for (int i = 0; i < related.length; i++) {
1505: // we don't want to return duplicates
1506: if (!allRelated.contains(related[i])) {
1507: // if it's not filtered, add it to the list
1508: if (!WorkbenchActivityHelper
1509: .filterItem(related[i])) {
1510: allRelated.add(related[i]);
1511: }
1512: }
1513: }
1514: nonDefaultFileEditors.addAll(Arrays.asList(mapping
1515: .getEditors()));
1516: }
1517: }
1518: }
1519:
1520: if (type != null) {
1521: // now add any objects directly related to the content type
1522: related = registry.getRelatedObjects(type);
1523: for (int i = 0; i < related.length; i++) {
1524: // we don't want to return duplicates
1525: if (!allRelated.contains(related[i])) {
1526: // if it's not filtered, add it to the list
1527: if (!WorkbenchActivityHelper.filterItem(related[i])) {
1528: allRelated.add(related[i]);
1529: }
1530: }
1531: }
1532:
1533: }
1534:
1535: if (type != null) {
1536: // now add any indirectly related objects, walking up the content type hierarchy
1537: while ((type = type.getBaseType()) != null) {
1538: related = registry.getRelatedObjects(type);
1539: for (int i = 0; i < related.length; i++) {
1540: // we don't want to return duplicates
1541: if (!allRelated.contains(related[i])) {
1542: // if it's not filtered, add it to the list
1543: if (!WorkbenchActivityHelper
1544: .filterItem(related[i])) {
1545: allRelated.add(related[i]);
1546: }
1547: }
1548: }
1549: }
1550: }
1551:
1552: // add all non-default editors to the list
1553: for (Iterator i = nonDefaultFileEditors.iterator(); i.hasNext();) {
1554: IEditorDescriptor editor = (IEditorDescriptor) i.next();
1555: if (!allRelated.contains(editor)
1556: && !WorkbenchActivityHelper.filterItem(editor)) {
1557: allRelated.add(editor);
1558: }
1559: }
1560:
1561: return (IEditorDescriptor[]) allRelated
1562: .toArray(new IEditorDescriptor[allRelated.size()]);
1563: }
1564:
1565: /**
1566: * Return the editors bound to this content type, either directly or indirectly.
1567: *
1568: * @param type the content type to check
1569: * @return the editors
1570: * @since 3.1
1571: *
1572: * TODO: this should be rolled in with the above findRelatedObjects code
1573: */
1574: public IEditorDescriptor[] getEditorsForContentType(
1575: IContentType type) {
1576: ArrayList allRelated = new ArrayList();
1577: if (type == null) {
1578: return new IEditorDescriptor[0];
1579: }
1580:
1581: Object[] related = relatedRegistry.getRelatedObjects(type);
1582: for (int i = 0; i < related.length; i++) {
1583: // we don't want to return duplicates
1584: if (!allRelated.contains(related[i])) {
1585: // if it's not filtered, add it to the list
1586: if (!WorkbenchActivityHelper.filterItem(related[i])) {
1587: allRelated.add(related[i]);
1588: }
1589:
1590: }
1591: }
1592:
1593: // now add any indirectly related objects, walking up the content type hierarchy
1594: while ((type = type.getBaseType()) != null) {
1595: related = relatedRegistry.getRelatedObjects(type);
1596: for (int i = 0; i < related.length; i++) {
1597: // we don't want to return duplicates
1598: if (!allRelated.contains(related[i])) {
1599: // if it's not filtered, add it to the list
1600: if (!WorkbenchActivityHelper.filterItem(related[i])) {
1601: allRelated.add(related[i]);
1602: }
1603: }
1604: }
1605: }
1606:
1607: return (IEditorDescriptor[]) allRelated
1608: .toArray(new IEditorDescriptor[allRelated.size()]);
1609: }
1610:
1611: /**
1612: * Get filemappings for all defined filetypes, including those defined by content type.
1613: *
1614: * @return the filetypes
1615: * @since 3.1
1616: */
1617: public IFileEditorMapping[] getUnifiedMappings() {
1618: IFileEditorMapping[] standardMappings = PlatformUI
1619: .getWorkbench().getEditorRegistry()
1620: .getFileEditorMappings();
1621:
1622: List allMappings = new ArrayList(Arrays
1623: .asList(standardMappings));
1624: // mock-up content type extensions into IFileEditorMappings
1625: IContentType[] contentTypes = Platform.getContentTypeManager()
1626: .getAllContentTypes();
1627: for (int i = 0; i < contentTypes.length; i++) {
1628: IContentType type = contentTypes[i];
1629: String[] extensions = type
1630: .getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
1631: for (int j = 0; j < extensions.length; j++) {
1632: String extension = extensions[j];
1633: boolean found = false;
1634: for (Iterator k = allMappings.iterator(); k.hasNext();) {
1635: IFileEditorMapping mapping = (IFileEditorMapping) k
1636: .next();
1637: if ("*".equals(mapping.getName()) && extension.equals(mapping.getExtension())) { //$NON-NLS-1$
1638: found = true;
1639: break;
1640: }
1641: }
1642: if (!found) {
1643: MockMapping mockMapping = new MockMapping(type,
1644: "*", extension); //$NON-NLS-1$
1645: allMappings.add(mockMapping);
1646: }
1647: }
1648:
1649: String[] filenames = type
1650: .getFileSpecs(IContentType.FILE_NAME_SPEC);
1651: for (int j = 0; j < filenames.length; j++) {
1652: String wholename = filenames[j];
1653: int idx = wholename.indexOf('.');
1654: String name = idx == -1 ? wholename : wholename
1655: .substring(0, idx);
1656: String extension = idx == -1 ? "" : wholename.substring(idx + 1); //$NON-NLS-1$
1657:
1658: boolean found = false;
1659: for (Iterator k = allMappings.iterator(); k.hasNext();) {
1660: IFileEditorMapping mapping = (IFileEditorMapping) k
1661: .next();
1662: if (name.equals(mapping.getName())
1663: && extension.equals(mapping.getExtension())) {
1664: found = true;
1665: break;
1666: }
1667: }
1668: if (!found) {
1669: MockMapping mockMapping = new MockMapping(type,
1670: name, extension);
1671: allMappings.add(mockMapping);
1672: }
1673: }
1674: }
1675:
1676: return (IFileEditorMapping[]) allMappings
1677: .toArray(new IFileEditorMapping[allMappings.size()]);
1678: }
1679:
1680: }
1681:
1682: class MockMapping implements IFileEditorMapping {
1683:
1684: private IContentType contentType;
1685: private String extension;
1686: private String filename;
1687:
1688: MockMapping(IContentType type, String name, String ext) {
1689: this .contentType = type;
1690: this .filename = name;
1691: this .extension = ext;
1692: }
1693:
1694: public IEditorDescriptor getDefaultEditor() {
1695: IEditorDescriptor[] candidates = ((EditorRegistry) PlatformUI
1696: .getWorkbench().getEditorRegistry())
1697: .getEditorsForContentType(contentType);
1698: if (candidates.length == 0) {
1699: return null;
1700: }
1701: return candidates[0];
1702: }
1703:
1704: public IEditorDescriptor[] getEditors() {
1705: return ((EditorRegistry) PlatformUI.getWorkbench()
1706: .getEditorRegistry())
1707: .getEditorsForContentType(contentType);
1708: }
1709:
1710: public IEditorDescriptor[] getDeletedEditors() {
1711: return new IEditorDescriptor[0];
1712: }
1713:
1714: public String getExtension() {
1715: return extension;
1716: }
1717:
1718: public ImageDescriptor getImageDescriptor() {
1719: IEditorDescriptor editor = getDefaultEditor();
1720: if (editor == null) {
1721: return WorkbenchImages
1722: .getImageDescriptor(ISharedImages.IMG_OBJ_FILE);
1723: }
1724:
1725: return editor.getImageDescriptor();
1726: }
1727:
1728: public String getLabel() {
1729: return filename + '.' + extension;
1730: }
1731:
1732: public String getName() {
1733: return filename;
1734: }
1735:
1736: /* (non-Javadoc)
1737: * @see java.lang.Object#equals(java.lang.Object)
1738: */
1739: public boolean equals(Object obj) {
1740: if (this == obj) {
1741: return true;
1742: }
1743:
1744: if (!(obj instanceof MockMapping)) {
1745: return false;
1746: }
1747:
1748: MockMapping mapping = (MockMapping) obj;
1749: if (!this .filename.equals(mapping.filename)) {
1750: return false;
1751: }
1752:
1753: if (!this .extension.equals(mapping.extension)) {
1754: return false;
1755: }
1756:
1757: if (!Util.equals(this .getEditors(), mapping.getEditors())) {
1758: return false;
1759: }
1760: return Util.equals(this.getDeletedEditors(), mapping
1761: .getDeletedEditors());
1762: }
1763: }
|